从元组列表列表构造稀疏矩阵

nea*_*mcb 11 python constructor scipy sparse-matrix

我有一个稀疏矩阵的行信息的Python列表.每行表示为(列,值)元组的列表.叫它alist:

alist = [[(1,10), (3,-3)],
         [(2,12)]]
Run Code Online (Sandbox Code Playgroud)

如何从列表列表中有效地构造一个scipy稀疏矩阵,得到如下矩阵:

0  10   0  -3
0   0  12   0
Run Code Online (Sandbox Code Playgroud)

显而易见的方法是制作一个scipy.sparse.lil_matrix内部具有此"列表列表"结构的内容.但是从scipy.sparse.lil_matrix - SciPy v0.19.0参考指南中我只看到了构建它们的三种方法:

  • 从密集阵列开始
  • 从另一个稀疏数组开始
  • 只是构建一个空数组

因此,获取新数据的唯一方法是使用其他稀疏矩阵表示来解决此问题,或者从密集数组开始,这两者都没有解决初始问题,并且这两者似乎都是效率低于表示的lil_matrix本身就是这个数据.

我想我可以制作一个空的,并使用循环来添加值,但我肯定错过了一些东西.

在稀疏矩阵方面,scipy文档非常令人沮丧.

hpa*_*ulj 8

您的数据布局是不寻常的.这是我第一次尝试使用它.

In [565]: M = sparse.lil_matrix((2,4), dtype=int)
In [566]: M
Out[566]: 
<2x4 sparse matrix of type '<class 'numpy.int32'>'
    with 0 stored elements in LInked List format>
In [567]: for i,row in enumerate(alist):
     ...:     for col in row:
     ...:         M[i, col[0]] = col[1]
     ...:         
In [568]: M
Out[568]: 
<2x4 sparse matrix of type '<class 'numpy.int32'>'
    with 3 stored elements in LInked List format>
In [569]: M.A
Out[569]: 
array([[ 0, 10,  0, -3],
       [ 0,  0, 12,  0]])
Run Code Online (Sandbox Code Playgroud)

是的,它是迭代的; 并且lil是用于此目的的最佳格式.

或者使用常见coo的输入方式:

In [580]: data,col,row = [],[],[]
In [581]: for i, rr in enumerate(alist):
     ...:     for cc in rr:
     ...:         row.append(i)
     ...:         col.append(cc[0])
     ...:         data.append(cc[1])
     ...:         
In [582]: data,col,row
Out[582]: ([10, -3, 12], [1, 3, 2], [0, 0, 1])
In [583]: M1=sparse.coo_matrix((data,(row,col)),shape=(2,4))
In [584]: M1
Out[584]: 
<2x4 sparse matrix of type '<class 'numpy.int32'>'
    with 3 stored elements in COOrdinate format>
In [585]: M1.A
Out[585]: 
array([[ 0, 10,  0, -3],
       [ 0,  0, 12,  0]])
Run Code Online (Sandbox Code Playgroud)

另一种选择是创建空白lil矩阵,并直接填写其属性:

换句话说,从:

In [591]: m.data
Out[591]: array([[], []], dtype=object)
In [592]: m.rows
Out[592]: array([[], []], dtype=object)
Run Code Online (Sandbox Code Playgroud)

并将其更改为:

In [587]: M.data
Out[587]: array([[10, -3], [12]], dtype=object)
In [588]: M.rows
Out[588]: array([[1, 3], [2]], dtype=object)
Run Code Online (Sandbox Code Playgroud)

它仍然需要对您的alist结构进行2级迭代.

In [593]: for i, rr in enumerate(alist):
     ...:     for cc in rr:
     ...:         m.rows[i].append(cc[0])
     ...:         m.data[i].append(cc[1])       
In [594]: m
Out[594]: 
<2x4 sparse matrix of type '<class 'numpy.int32'>'
    with 3 stored elements in LInked List format>
In [595]: m.A
Out[595]: 
array([[ 0, 10,  0, -3],
       [ 0,  0, 12,  0]])
Run Code Online (Sandbox Code Playgroud)

在另一个评论中你提到了理解这个问题的难度csr indptr.最简单的方法是转换这些格式:

In [597]: Mr=M.tocsr()
In [598]: Mr.indptr
Out[598]: array([0, 2, 3], dtype=int32)
In [599]: Mr.data
Out[599]: array([10, -3, 12])
In [600]: Mr.indices
Out[600]: array([1, 3, 2], dtype=int32)
Run Code Online (Sandbox Code Playgroud)

  • 这样一个清晰,有帮助,详细的答案 - 谢谢!基于COO格式的构造函数似乎最自然,我可以想出一些生成器来生成它并实现内存和时间效率的输入管道.我希望scipy人们以人们会找到它们的方式添加这样的例子.这是我的数据格式,并且考虑到支持所有这些不同稀疏格式的系统数量,如[稀疏数组 - 维基百科](https://en.wikipedia.org/wiki/Sparse_array)所述,我d认为更多人会使用它们交换数据. (3认同)

kup*_*n87 6

如果alist在创建稀疏矩阵之前有整体,则无需使用lil_matrix,因为它已经过优化,可以逐步更新稀疏矩阵.

如果你想用矩阵后跟词进行任何算术运算,csr_matrix可能是你最好的选择.您可以csr_matrix使用(data, (row, column))格式直接构造,如下所示:

In [40]: alist = [[(1,10), (3,-3)],
    ...:          [(2,12)]]

In [41]: i, j, data = zip(*((i, t[0], t[1]) for i, row in enumerate(alist) for t in row))

In [42]: (i, j, data)
Out[42]: ((0, 0, 1), (1, 3, 2), (10, -3, 12))

In [43]: csr_matrix((data, (i, j)), shape=(2, 4)).todense()
Out[43]: 
matrix([[ 0, 10,  0, -3],
        [ 0,  0, 12,  0]], dtype=int64)
Run Code Online (Sandbox Code Playgroud)

如果效率是一个真正的问题,您可以直接创建csr_matrix内部格式(使用indptr):

In [57]: indptr = np.cumsum([0] + [len(row) for row in alist])

In [58]: j, data = zip(*(t for row in alist for t in row))

In [59]: csr_matrix((data, j, indptr), shape=(2, 4)).todense()
Out[59]: 
matrix([[ 0, 10,  0, -3],
        [ 0,  0, 12,  0]])
Run Code Online (Sandbox Code Playgroud)

如果你要转换为pandas afterwords,那coo_matrix就是要走的路,因为pandas会转换为coo_matrix:

In [41]: i, j, data = zip(*((i, t[0], t[1]) for i, row in enumerate(alist) for t in row))

In [43]: coo_matrix((data, (i, j)), shape=(2, 4))
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,coo_matrix是要走的路,因为pandas无论如何转换为那种格式 (2认同)
  • 如果你不提供形状,coo_matrix将从shape =(max(i),max(j))推导出它.如果例如最后一列或最后一行全部为零,则会导致问题,因为您将从矩阵中丢失该行/列. (2认同)