scipy 由元组列表的列表构造稀疏矩阵

uqzxnwby  于 2023-06-06  发布在  其他
关注(0)|答案(5)|浏览(201)

我有一个稀疏矩阵的行信息的Python列表。每一行都表示为(列,值)元组的列表。将其命名为alist

alist = [[(1,10), (3,-3)],
         [(2,12)]]

我如何从这个列表中有效地构造一个scipy稀疏矩阵,得到一个像这样的矩阵:

0  10   0  -3
0   0  12   0

最明显的方法是创建一个scipy.sparse.lil_matrix,它在内部具有这种“列表的列表”结构。但是从scipy.sparse.lil_matrix - SciPy v0.19.0参考指南中,我只看到了三种构建它们的方法:

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

因此,获取新数据的唯一方法是使用其他稀疏矩阵表示来解决这个问题,或者从密集数组开始,这两种方法都不能解决最初的问题,而且对于这个数据,这两种方法似乎都比lil_matrix本身效率更低。
我想我可以做一个空的,并使用一个循环来添加值,但肯定我错过了一些东西。
当涉及到稀疏矩阵时,scipy文档真的很令人沮丧。

xv8emn3q

xv8emn3q1#

如果在创建稀疏矩阵之前已经有了整个alist,那么就不需要使用lil_matrix,因为它已经针对增量更新稀疏矩阵进行了优化。
如果你想用矩阵做任何算术运算,csr_matrix可能是你最好的选择。您可以使用(data, (row, column))直接构造csr_matrix,如下所示:

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)

如果效率是一个真实的的问题,您可以直接创建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]])

如果你要转换到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))
ru9i0ody

ru9i0ody2#

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

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]])

是的,它是迭代的; 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]])

另一种选择是创建空白的lil矩阵,并直接填写其属性:
换句话说,开始:

In [591]: m.data
Out[591]: array([[], []], dtype=object)
In [592]: m.rows
Out[592]: array([[], []], dtype=object)

并将其更改为:

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

它仍然需要在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]])

在另一条评论中,您提到了理解csrindptr的困难。最简单的方法是转换这些格式之一:

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)
ncecgwcz

ncecgwcz3#

您可以从(列,值)元组alist的列表中创建位置和值的dict,然后使用dok_matrix构造稀疏矩阵

>>> d = {(i,j):v for i,l in enumerate(alist) for j,v in l}
>>> d
{(0, 1): 10, (0, 3): -3, (1, 2): 12}
>>> 
>>> from operator import itemgetter
>>> m = max(d.keys(), key=itemgetter(0))[0] + 1
>>> n = max(d.keys(), key=itemgetter(1))[1] + 1
>>> m,n
(2, 4)
>>>
>>> from scipy.sparse import dok_matrix
>>> S = dok_matrix((m,n), dtype=int)
>>> for pos,v in d.items():
...     S[pos] = v
... 
>>> S.todense()
matrix([[ 0, 10,  0, -3],
        [ 0,  0, 12,  0]])
>>>
cgvd09ve

cgvd09ve4#

只是想发布另一个使用coo_matrix的答案,这是一种快速构造稀疏矩阵的格式。

>>> alist = [[(1, 10), (3, -3)], [(2, 12)]]
>>> row, col, data = zip(*((i,j,v) for i,l in enumerate(alist) for j,v in l))
>>>
>>> from scipy.sparse import coo_matrix
>>> S = coo_matrix((data, (row, col)), (max(row)+1,max(col)+1), dtype=np.int8)
>>> S.todense()
matrix([[ 0, 10,  0, -3],
        [ 0,  0, 12,  0]], dtype=int8)
>>>
rslzwgfq

rslzwgfq5#

发布的解决方案可以总结为三个步骤:添加行号、分解行数据、提取坐标和数据。下面是一个更详细的迭代器实现:

alist = [[(1,10), (3,-3)],[(2,12)]]

import itertools
from scipy import sparse

# add row ids

it = enumerate(alist)
# explode row data by id
it = map(lambda t: itertools.product([t[0]],*t[1:]), it)
it = itertools.chain(*it)
# flatten tupples
it = map(lambda t: (t[0],*t[1]), it)
# extract coordinates and data 
i,j,data=zip(*it)
# use coo format
sparse.coo_matrix((data,(i,j)))

相关问题