Python中的伪逆计算

时间:2018-07-02 15:55:33

标签: pandas numpy dataframe scipy linear-algebra

问题

我正在处理here中描述的问题。我有两个目标。

  1. 对于任何给定的线性方程组,请找出哪些变量具有唯一解。
  2. 对于具有唯一解的那些变量,请返回方程的最小列表,以便了解这些方程即可确定该变量的值。

例如,在以下等式中

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计算出pseudoinverseSVD(要了解如何计算,请参见herehere:查看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伪逆是唯一的,所以这是不可能的。

我在这里做错什么了吗?还是我要采取的方法不会给我我想要的东西?

其他注意事项

  1. 所有变量的所有系数均为1
  2. 当前算法产生的结果是可靠的...当我将方程总数的任何矢量乘以算法生成的伪逆时,我得到的值基本上等于声称具有唯一解的值,这是有希望的。 / li>
  3. 在这里我想知道的是我在从伪逆推算信息时是否做错了什么,或者我的方法是否完全错误。
  4. 我很抱歉没有发布任何实际结果,但是它们不仅很大,而且由于重新格式化为XML格式可能有点不直观,反正可能还会需要另一个问题来解释。

谢谢您的时间!

0 个答案:

没有答案