【问题标题】:creating a scipy.lil_matrix using a python generator efficiently使用 python 生成器有效地创建 scipy.lil_matrix
【发布时间】:2016-11-01 09:25:33
【问题描述】:

我有一个生成器可以生成相同长度的单一维度numpy.arrays。我想要一个包含该数据的稀疏矩阵。行的生成顺序与我希望将它们放在最终矩阵中的顺序相同。 csr 矩阵优于 lil 矩阵,但我认为后者在我所描述的场景中更容易构建。

假设 row_gen 是生成 numpy.array 行的生成器,则以下代码按预期工作。

def row_gen():
    yield numpy.array([1, 2, 3])
    yield numpy.array([1, 0, 1])
    yield numpy.array([1, 0, 0])

matrix = scipy.sparse.lil_matrix(list(row_gen()))

因为该列表基本上会破坏生成器的所有优势,所以我希望以下内容具有相同的最终结果。更具体地说,我无法在内存中保存整个密集矩阵(或所有矩阵行的列表):

def row_gen():
    yield numpy.array([1, 2, 3])
    yield numpy.array([1, 0, 1])
    yield numpy.array([1, 0, 0])

matrix = scipy.sparse.lil_matrix(row_gen())

但是它在运行时会引发以下异常:

TypeError: no supported conversion for types: (dtype('O'),)

我还注意到跟踪包括以下内容:

File "/usr/local/lib/python2.7/site-packages/scipy/sparse/lil.py", line 122, in __init__
  A = csr_matrix(A, dtype=dtype).tolil()

这让我觉得使用scipy.sparse.lil_matrix 最终会创建一个csr 矩阵,然后才将其转换为lil 矩阵。在这种情况下,我宁愿先创建csr 矩阵。

回顾一下,我的问题是:从 python 生成器或 numpy 一维数组创建scipy.sparse 矩阵的最有效方法是什么?

【问题讨论】:

    标签: python numpy scipy generator sparse-matrix


    【解决方案1】:

    让我们看看sparse.lil_matrix 的代码。它检查第一个参数:

    if isspmatrix(arg1):    # is is already a sparse matrix
         ...
    elif isinstance(arg1,tuple):    # is it the shape tuple
        if isshape(arg1):
            if shape is not None:
                raise ValueError('invalid use of shape parameter')
            M, N = arg1
            self.shape = (M,N)
            self.rows = np.empty((M,), dtype=object)
            self.data = np.empty((M,), dtype=object)
            for i in range(M):
                self.rows[i] = []
                self.data[i] = []
        else:
            raise TypeError('unrecognized lil_matrix constructor usage')
    else:
        # assume A is dense
        try:
            A = np.asmatrix(arg1)
        except TypeError:
            raise TypeError('unsupported matrix type')
        else:
            from .csr import csr_matrix
            A = csr_matrix(A, dtype=dtype).tolil()
    
            self.shape = A.shape
            self.dtype = A.dtype
            self.rows = A.rows
            self.data = A.data
    

    根据文档 - 您可以从另一个稀疏矩阵、形状和密集数组构造它。密集数组构造函数首先制作一个csr矩阵,然后将其转换为lil

    形状版本构造一个空的lil,其数据如下:

    In [161]: M=sparse.lil_matrix((3,5),dtype=int)
    In [163]: M.data
    Out[163]: array([[], [], []], dtype=object)
    In [164]: M.rows
    Out[164]: array([[], [], []], dtype=object)
    

    很明显,传递一个生成器是行不通的——它不是一个密集的数组。

    但是在创建了lil 矩阵后,您可以使用常规数组赋值来填充元素:

    In [167]: M[0,:]=[1,0,2,0,0]
    In [168]: M[1,:]=[0,0,2,0,0]
    In [169]: M[2,3:]=[1,1]
    In [170]: M.data
    Out[170]: array([[1, 2], [2], [1, 1]], dtype=object)
    In [171]: M.rows
    Out[171]: array([[0, 2], [2], [3, 4]], dtype=object)
    In [172]: M.A
    Out[172]: 
    array([[1, 0, 2, 0, 0],
           [0, 0, 2, 0, 0],
           [0, 0, 0, 1, 1]])
    

    你可以直接给子列表赋值(我觉得这样更快,但也有点危险):

    In [173]: M.data[1]=[1,2,3]
    In [174]: M.rows[1]=[0,2,4]
    In [176]: M.A
    Out[176]: 
    array([[1, 0, 2, 0, 0],
           [1, 0, 2, 0, 3],
           [0, 0, 0, 1, 1]])
    

    另一种增量方法是构造coo 格式的3 个数组或列表,然后从中生成coocsr

    sparse.bmat 是另一种选择,它的代码是构建coo 输入的一个很好的例子。我让你自己看看。

    【讨论】:

    • 谢谢,但您建议的两种方法都假设我手头有矩阵的形状。事实并非如此,因为 lil 是专门为添加行而构建的,所以我正在寻找一种在构建过程中有效增加其大小的方法。
    • 未知数 - 行数还是列数?或两者?收集coo 三重数组不需要知道最终大小,但sparse 矩阵不是为增量增长而设计的(稀疏数组也不是)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-18
    • 2011-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-20
    • 2010-12-21
    相关资源
    最近更新 更多