我正在处理here中描述的问题。我有两个目标。
例如,在以下等式中
X = a + b
Y = a + b + c
Z = a + b + c + d
适当的输出应为c和d,其中X和Y确定c,Y和Z确定d。
我提供了两列名为 InputDataSet 的pandas DataFrame,其中两列是 Equation 和 Variable 。每行代表给定方程式中变量的隶属关系。例如,以上等式集将表示为
InputDataSet = pd.DataFrame([['X','a'],['X','b'],['Y','a'],['Y','b'],['Y','c'],
['Z','a'],['Z','b'],['Z','c'],['Z','d']],columns=['Equation','Variable'])
输出也将存储在名为 OutputDataSet 的2列DataFrame中,其中第一个包含具有唯一解的变量,第二个是最小等式集的逗号分隔字符串需要解决给定的变量。例如,正确的 OutputDataSet 看起来像
OutputDataSet = pd.DataFrame([['c','X,Y'],['d','Y,Z']],columns=['Variable','EquationList'])
我当前的解决方案采用InputDataSet并将其转换为NetworkX图。将图拆分为连接的子图后,它将图转换为二阶矩阵(因为图本质上是二分图)。进行此转换后,将计算SVD
,并根据nullspace
计算出pseudoinverse
和SVD
(要了解如何计算,请参见here和here:查看numpy.linalg.pinv的源代码和nullspace的cookbook函数。我融合了这两个函数,因为它们都使用SVD。)
计算完零空间和伪逆,并舍入到给定的公差之后,我在零空间中找到所有系数均为0的所有行,并将这些变量作为具有唯一解的变量返回,并将那些方程式与非伪逆中的变量的零系数。
代码如下:
import networkx as nx
import pandas as pd
import numpy as np
import numpy.core as cr
def svd_lite(a, tol=1e-2):
wrap = getattr(a, "__array_prepare__", a.__array_wrap__)
rcond = cr.asarray(tol)
a = a.conjugate()
u, s, vt = np.linalg.svd(a)
nnz = (s >= tol).sum()
ns = vt[nnz:].conj().T
shape = a.shape
if shape[0]>shape[1]:
u = u[:,:shape[1]]
elif shape[1]>shape[0]:
vt = vt[:shape[0]]
cutoff = rcond[..., cr.newaxis] * cr.amax(s, axis=-1, keepdims=True)
large = s > cutoff
s = cr.divide(1, s, where=large, out=s)
s[~large] = 0
res = cr.matmul(cr.swapaxes(vt, -1, -2), cr.multiply(s[..., cr.newaxis],
cr.swapaxes(u, -1, -2)))
return (wrap(res),ns)
cols = InputDataSet.columns
tolexp=2
graphs = nx.connected_component_subgraphs(nx.from_pandas_dataframe(InputDataSet,cols[0],
cols[1]))
OutputDataSet = []
Eqs = InputDataSet[cols[0]].unique()
Vars = InputDataSet[cols[1]].unique()
for i in graphs:
EqList = np.array([val for val in np.array(i.nodes) if val in Eqs])
VarList = [val for val in np.array(i.nodes) if val in Vars]
pinv,nulls = svd_lite(nx.bipartite.biadjacency_matrix(i,EqList,VarList,format='csc')
.astype(float).todense(),tol=10**-tolexp)
df2 = np.where(~np.round(nulls,tolexp).any(axis=1))[0]
df3 = np.round(np.array(pinv),tolexp)
OutputDataSet.extend([[VarList[i],",".join(EqList[np.nonzero(df3[i])])] for i in df2])
OutputDataSet = pd.DataFrame(OutputDataSet)
在我测试过该算法的数据上,它的执行时间相当不错。但是,主要问题是,它建议使用太多的方程式来确定给定变量。
通常,在具有10,000个方程式的数据集的情况下,该算法会声称在确定10,000个变量中需要10,000个方程式中的8,000个,这绝对不是这种情况。
我尝试将公差(我将伪逆中的系数四舍五入)提高到.1,但是即使如此,将近5000个方程具有非零系数。
我猜想伪逆可能在一组非最佳系数上崩溃,但是Moore-Penrose伪逆是唯一的,所以这是不可能的。
我在这里做错什么了吗?还是我要采取的方法不会给我我想要的东西?
谢谢您的时间!