46

假设我有一个二维稀疏数组。在我的真实用例中,行数和列数都大得多(比如 20000 和 50000),因此当使用密集表示时它无法放入内存:

>>> import numpy as np
>>> import scipy.sparse as ssp

>>> a = ssp.lil_matrix((5, 3))
>>> a[1, 2] = -1
>>> a[4, 1] = 2
>>> a.todense()
matrix([[ 0.,  0.,  0.],
        [ 0.,  0., -1.],
        [ 0.,  0.,  0.],
        [ 0.,  0.,  0.],
        [ 0.,  2.,  0.]])

现在假设我有一个密集的一维数组,其中包含大小为 3 的所有非零分量(或在我的现实生活中为 50000):

>>> d = np.ones(3) * 3
>>> d
array([ 3.,  3.,  3.])

我想使用 numpy 的通常广播语义来计算 a 和 d 的元素乘法。但是,scipy 中的稀疏矩阵属于 np.matrix:“*”运算符被重载以使其表现得像矩阵乘法而不是元素乘法:

>>> a * d
array([ 0., -3.,  0.,  0.,  6.])

一种解决方案是将“a”切换到“*”运算符的数组语义,这将给出预期的结果:

>>> a.toarray() * d
array([[ 0.,  0.,  0.],
       [ 0.,  0., -3.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  6.,  0.]])

但我不能这样做,因为对 toarray() 的调用会实现不适合内存的“a”的密集版本(结果也会很密集):

>>> ssp.issparse(a.toarray())
False

知道如何在只保留稀疏数据结构并且不必在“a”的列上执行低效的 python 循环的情况下构建它吗?

4

3 回答 3

49

我也在 scipy.org 上回复过,但我想我应该在这里添加一个答案,以防其他人在搜索时找到这个页面。

您可以将向量转换为稀疏对角矩阵,然后使用矩阵乘法(带 *)来做与广播相同的事情,但效率很高。

>>> d = ssp.lil_matrix((3,3))
>>> d.setdiag(np.ones(3)*3)
>>> a*d
<5x3 sparse matrix of type '<type 'numpy.float64'>'
 with 2 stored elements in Compressed Sparse Row format>
>>> (a*d).todense()
matrix([[ 0.,  0.,  0.],
        [ 0.,  0., -3.],
        [ 0.,  0.,  0.],
        [ 0.,  0.,  0.],
        [ 0.,  6.,  0.]])

希望有帮助!

于 2010-07-28T21:27:58.890 回答
27

我认为 A.multiply(B) 应该在 scipy sparse 中工作。方法 multiply 执行“逐点”乘法,而不是矩阵乘法。

高温高压

于 2010-12-21T20:01:07.003 回答
1

好吧,这是一个简单的代码,可以满足您的需求。我不知道它是否像您想要的那样高效,所以接受还是放弃:

import scipy.sparse as ssp
def pointmult(a,b):
    x = a.copy()
    for i in xrange(a.shape[0]):
        if x.data[i]:
            for j in xrange(len(x.data[i])):
                x.data[i] *= b[x.rows[i]]
    return x

它仅适用于 lil 矩阵,因此如果您希望它适用于其他格式,则必须进行一些更改。

于 2010-07-18T22:34:09.900 回答