如何最好地对SciPy稀疏矩阵进行行缩放?

时间:2013-01-17 23:33:55

标签: python scipy sparse-matrix

我有一个SciPy稀疏矩阵A,比如CSR格式,以及匹配长度的矢量v

使用A进行行缩放v的最佳方式是什么,即执行 diag(v) * A

2 个答案:

答案 0 :(得分:3)

简单的方法是让scipy处理血腥细节,并简单地执行:

scipy.sparse.spdiags(v, 0, len(v), len(v)) * A

编辑如果(且仅当)您的矩阵以CSC格式存储,您可以按如下方式进行操作:

A_csc.data = A_csc.data * v[A_csc.indices]

我已经完成了一些时间,因为它非常依赖于矩阵的稀疏性及其大小,可以随意使用以下代码:

from __future__ import division
import numpy as np
import scipy.sparse as sps
import timeit

A_csr = None
A_csc = None
v = None

def time_row_scaling(n, dens) :
    global A_csr, A_csc, v
    v = np.random.rand(n)
    A_csr = sps.rand(n, n, density=dens, format='csr')
    A_csc = A_csr.tocsc()
    def row_scale(A_csc, v) :
        A_csc.data = A_csc.data * v[A_csc.indices]
    row_scaled_1 = sps.spdiags(v, 0, n , n) * A_csr
    row_scaled_2 = sps.spdiags(v, 0, n , n) * A_csc
    row_scale(A_csc, v)
    if n < 1000 :
        np.testing.assert_almost_equal(row_scaled_1.toarray(),
                                       row_scaled_2.toarray())
        np.testing.assert_almost_equal(row_scaled_1.toarray(),
                                       A_csc.toarray())
    A_csc = A_csr.tocsc()
    t1 = timeit.timeit('sps.spdiags(v, 0, len(v) , len(v)) * A_csr',
                       'from __main__ import sps, v, A_csr',
                       number=1)
    t2 = timeit.timeit('sps.spdiags(v, 0, len(v), len(v)) * A_csc',
                       'from __main__ import sps, v, A_csc',
                       number=1)
    t3 = timeit.timeit('A_csc.data = A_csc.data * v[A_csc.indices]',
                       'from __main__ import A_csc, v',
                       number=1)
    print t1, t2, t3

>>> time_row_scaling(1000, 0.01)
0.00100659830939 0.00102425072673 0.000231944553347
>>> time_row_scaling(1000, 0.1)
0.0017328105481 0.00311339379218 0.00239826562947
>>> time_row_scaling(10000, 0.01)
0.0162369397769 0.0359325217874 0.0216837368279
>>> time_row_scaling(10000, 0.1)
0.167978350747 0.492032396702 0.209231639536

总结似乎是,如果是CSR,或者真的很大,请使用简单的第一种方法。如果它是一个很小的,非常稀疏的矩阵,那么就地方法会更快,尽管所有时间都很小。

答案 1 :(得分:2)

sklearn提供实用程序在sklearn.utils.sparsefuncs.inplace_csr_row_scale中执行此操作。在我的实验中,这略微优于Jaime建议的方法和csr_matrix.multiply方法。请注意我的实验在非常大的矩阵上 - 形状大约为10 ^ 7 x 10 ^ 4。对于这样大小的矩阵,sklearn大约需要2秒钟;其他方法的范围为2.5-5秒。

但是,我发现到目前为止最有效的方法是使用提供的mkl_?csrmultcsr方法和对角矩阵挂钩到MKL。

没有提供这样做的代码,因为我的包装器太多了,但是对于与上面使用的相同大小的矩阵,这会在大约0.3s内执行重新缩放。

也许有一天numpy / scipy会像稀疏数学一样挂钩MKL ......