大型Numpy Scipy CSR矩阵,行式操作

nad*_*dre 6 python numpy sum scipy

我想迭代CSR矩阵的行并将每个元素除以行的总和,类似于此处:

numpy逐行划分

我的问题是我正在处理一个大矩阵:(96582,350138)

当从链接的帖子应用操作时,它会膨胀我的记忆,因为返回的矩阵是密集的.

所以这是我的第一次尝试:

for row in counts:
    row = row / row.sum()
Run Code Online (Sandbox Code Playgroud)

不幸的是,这根本不会影响矩阵,所以我想出了第二个想法来创建一个新的csr矩阵并使用vstack连接行:

from scipy import sparse
import time

start_time = curr_time = time.time()
mtx = sparse.csr_matrix((0, counts.shape[1]))
for i, row in enumerate(counts):
   prob_row = row / row.sum()
   mtx = sparse.vstack([mtx, prob_row])
   if i % 1000 == 0:
      delta_time = time.time() - curr_time
      total_time = time.time() - start_time
      curr_time = time.time()
      print('step: %i, total time: %i, delta_time: %i' % (i, total_time, delta_time))
Run Code Online (Sandbox Code Playgroud)

这很好用,但经过一些迭代后,它变得越来越慢:

step: 0, total time: 0, delta_time: 0
step: 1000, total time: 1, delta_time: 1
step: 2000, total time: 5, delta_time: 4
step: 3000, total time: 12, delta_time: 6
step: 4000, total time: 23, delta_time: 11
step: 5000, total time: 38, delta_time: 14
step: 6000, total time: 55, delta_time: 17
step: 7000, total time: 88, delta_time: 32
step: 8000, total time: 136, delta_time: 47
step: 9000, total time: 190, delta_time: 53
step: 10000, total time: 250, delta_time: 59
step: 11000, total time: 315, delta_time: 65
step: 12000, total time: 386, delta_time: 70
step: 13000, total time: 462, delta_time: 76
step: 14000, total time: 543, delta_time: 81
step: 15000, total time: 630, delta_time: 86
step: 16000, total time: 722, delta_time: 92
step: 17000, total time: 820, delta_time: 97
Run Code Online (Sandbox Code Playgroud)

有什么建议?知道为什么vstack越来越慢?

MSe*_*ert 5

vstack是一个O(n)操作,因为它需要为结果分配内存,然后将作为参数传递的所有数组的内容复制到结果数组中.

你可以简单地用来multiply做手术:

>>> res = counts.multiply(1 / counts.sum(1))  # multiply with inverse
>>> res.todense()
matrix([[ 0.33333333,  0.        ,  0.66666667],
        [ 0.        ,  0.        ,  1.        ],
        [ 0.26666667,  0.33333333,  0.4       ]])
Run Code Online (Sandbox Code Playgroud)

但它也很容易用于np.lib.stride_tricks.as_strided你想要的操作(相对高性能).此as_strided函数还允许对数组执行更复杂的操作(如果您的情况没有方法或函数).

例如,使用scipy文档的示例csr :

>>> from scipy.sparse import csr_matrix
>>> import numpy as np
>>> row = np.array([0,0,1,2,2,2])
>>> col = np.array([0,2,2,0,1,2])
>>> data = np.array([1.,2,3,4,5,6])
>>> counts = csr_matrix( (data,(row,col)), shape=(3,3) )
>>> counts.todense()
matrix([[ 1.,  0.,  2.],
        [ 0.,  0.,  3.],
        [ 4.,  5.,  6.]])
Run Code Online (Sandbox Code Playgroud)

您可以将每行除以它的总和,如下所示:

>>> row_start_stop = np.lib.stride_tricks.as_strided(counts.indptr, 
                                                     shape=(counts.shape[0], 2),
                                                     strides=2*counts.indptr.strides)
>>> for start, stop in row_start_stop:   
...    row = counts.data[start:stop]
...    row /= row.sum()
>>> counts.todense()
matrix([[ 0.33333333,  0.        ,  0.66666667],
        [ 0.        ,  0.        ,  1.        ],
        [ 0.26666667,  0.33333333,  0.4       ]])
Run Code Online (Sandbox Code Playgroud)