高效地使用python生成器创建scipy.lil_matrix

问题描述:

我有一个生成器,生成长度相同的单维numpy.array。我想有一个包含这些数据的稀疏矩阵。行按照我希望在最终矩阵中具有的顺序生成。 csr matrix优于lil矩阵,但我认为后者在我描述的场景中更容易构建。高效地使用python生成器创建scipy.lil_matrix

假设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矩阵的最有效方法?

让我们来看看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]]) 

另一个增量方法是构建3个数组或列表coo格式的,然后使从这些一个或coocsr

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

+0

谢谢,但是你提出的两种方法都假设我已经掌握了矩阵的形状。事实并非如此,由于lil是专门为增加行数而构建的,因此我正在寻找一种在构建时有效增加其大小的方法。 – NirIzr

+0

什么是未知数 - 行数或列数?或两者?收集数组的'coo'三重奏不需要知道最终的大小,但是'稀疏'矩阵不是为增量增长而设计的(也不是稀疏数组)。 – hpaulj