scipy csr_matrix 来自几个表示为集合列表的向量

Posted

技术标签:

【中文标题】scipy csr_matrix 来自几个表示为集合列表的向量【英文标题】:scipy csr_matrix from several vectors represented as list of sets 【发布时间】:2015-10-25 18:44:36 【问题描述】:

我有几个稀疏向量表示为元组列表,例如。

[[(22357, 0.6265631775164965),
  (31265, 0.3900572375543419),
  (44744, 0.4075397480094991),
  (47751, 0.5377595092643747)],
 [(22354, 0.6265631775164965),
  (31261, 0.3900572375543419),
  (42344, 0.4075397480094991),
  (47751, 0.5377595092643747)],
...
]

我的目标是从数百万个这样的向量中组合scipy.sparse.csr_matrix

我想问一下,对于这种转换,是否存在一些简单优雅的解决方案,而无需尝试将所有内容都存储在内存中。

编辑: 澄清一下:我的目标是构建二维矩阵,其中我的每个稀疏向量代表矩阵中的一行。

【问题讨论】:

那么目标是创建一个长向量还是一个二维矩阵?向量的长度是否一致? 目标是创建二维矩阵,其中我的每个稀疏向量将代表一条线。 【参考方案1】:

考虑以下几点:

import numpy as np
from scipy.sparse import csr_matrix

vectors = [[(22357, 0.6265631775164965),
            (31265, 0.3900572375543419),
            (44744, 0.4075397480094991),
            (47751, 0.5377595092643747)],
           [(22354, 0.6265631775164965),
            (31261, 0.3900572375543419),
            (42344, 0.4075397480094991),
            (47751, 0.5377595092643747)]]

indptr = np.cumsum([0] + map(len, vectors))
indices, data = np.vstack(vectors).T
A = csr_matrix((data, indices.astype(int), indptr))

不幸的是,通过这种方式,列索引从整数转换为双精度数并返回。 This works correctly 最多适用于非常大的矩阵,但并不理想。

【讨论】:

coo 样式输入会更直观吗? @hpaulj,通常我会说是,但在这种情况下,输入几乎已经是 csr 格式,这是请求的格式。【参考方案2】:

indices,data 收集到结构化数组中可避免整数-双精度转换问题。它也比vstack 方法快一点(在有限的测试中)(像这样的列表数据np.arraynp.vstack 快​​。)

indptr = np.cumsum([0]+[len(i) for i in vectors])
aa = np.array(vectors,dtype='i,f').flatten()
A = sparse.csr_matrix((aa['f1'], aa['f0'], indptr))

因为我使用的是 Python3,所以我用列表推导替换了 map

coo 格式的指标(data, (i,j)) 可能更直观

ii = [[i]*len(v) for i,v in enumerate(vectors)])
ii = np.array(ii).flatten()
aa = np.array(vectors,dtype='i,f').flatten()
A2 = sparse.coo_matrix((aa['f1'],(np.array(ii), aa['f0'])))
# A2.tocsr()

这里,第一步的ii 是每个子列表的行号。

[[0, 0, 0, 0],
 [1, 1, 1, 1],
 [2, 2, 2, 2],
 [3, 3, 3, 3],
 ...]]

这种构造方法比csr直接indptr慢。


对于每行有不同数量的条目的情况,这种方法有效(使用intertools.chain 来展平列表):

一个示例列表(暂时没有空行):

In [779]: vectors=[[(1, .12),(3, .234),(6,1.23)],
                   [(2,.222)],
                   [(2,.23),(1,.34)]]

行索引:

In [780]: ii=[[i]*len(v) for i,v in enumerate(vectors)]
In [781]: ii=list(chain(*ii))

从元组中提取并展平的列和数据值

In [782]: jj=[j for j,_ in chain(*vectors)]    
In [783]: data=[d for _,d in chain(*vectors)]

In [784]: ii
Out[784]: [0, 0, 0, 1, 2, 2]

In [785]: jj
Out[785]: [1, 3, 6, 2, 2, 1]

In [786]: data
Out[786]: [0.12, 0.234, 1.23, 0.222, 0.23, 0.34]

In [787]: A=sparse.csr_matrix((data,(ii,jj)))  # coo style input

In [788]: A.A
Out[788]: 
array([[ 0.   ,  0.12 ,  0.   ,  0.234,  0.   ,  0.   ,  1.23 ],
       [ 0.   ,  0.   ,  0.222,  0.   ,  0.   ,  0.   ,  0.   ],
       [ 0.   ,  0.34 ,  0.23 ,  0.   ,  0.   ,  0.   ,  0.   ]])

【讨论】:

实际上,当向量长度不相等时,这两种方法都会失败。在这种情况下,总是需要某种 Python 循环,并且对于什么是最有效的方法,所有的赌注都被取消了(我通过使用 map 在我的回答中隐藏了这个事实)。 在这种情况下,itertools.chain 是扁平化列表列表的有用工具。 第二个带链的解决方案正是我想要的。我刚刚修复(用*ll 替换错字为*vectors)谢谢

以上是关于scipy csr_matrix 来自几个表示为集合列表的向量的主要内容,如果未能解决你的问题,请参考以下文章

(Python Scipy)如何展平一个 csr_matrix 并将其附加到另一个 csr_matrix?

对 scipy.sparse.csr_matrix 中的行求和

scipy csr_matrix和csc_matrix函数详解

为啥 scipy 的稀疏 csr_matrix 的向量点积比 numpy 的密集数组慢?

scipy csr_matrix:了解 indptr

scipy.sparse.csr.csr_matrix 未显示在变量资源管理器中