快速构建一个非常大的稀疏矩阵

时间:2016-07-19 13:29:50

标签: python-2.7 for-loop scipy sparse-matrix

如何加速构建一个非常大的稀疏矩阵,其中每一行只有一个非零元素对应一列,每列有一个相等数量(平均)的非零元素?

我有一个大小N1的巨大(稀疏)矩阵 - 按 - N2,例如大小为1e8 - 由 - 5e4,其中每行包含只有一个非零元素是随机选择的,不会被numpy.random.choice(numpy.arange(N2),size=N2,replace=False)替换。

据我所知,构建矩阵的唯一方法是在numpy.random.choice()循环for次运行N1。由于N1非常大,为了加快速度,我使用scipy.weave

import numpy as np
from scipy import weave
from scipy.weave import converters
import scipy.sparse as sparse # Cython import

def weave_sparse(N1,N2,w):
    conn_matrix = sparse.dok_matrix((N1,N2))
    fac = lambda N : np.random.choice(np.arange(N), size=N, replace=False)[0]
    code = """
           int i;
           py::tuple arg(1);
           arg[0] = N2;
           for(i=0;i<N1;i++) conn_matrix[i,(int) fac.call(arg)] = w;
           """
    weave.inline(code,['conn_matrix','N1','N2', 'w', 'fac'],
                 compiler='gcc',extra_compile_args=['-std=c++11 -Ofast'],force=0)
    return conn_matrix

仍然,N1接近1e6并超出代码,需要很长时间才能完成。我怀疑可能有一种更有效的方法来构建稀疏矩阵。还有其他任何策略可以在人类可读的时间内加速和构建矩阵吗?

2 个答案:

答案 0 :(得分:4)

您不应该weave来提高效率。这是一个适合你的例子。我使用N1N2的小值来轻松检查结果。我也使用了csr_matrix,但任何scipy稀疏矩阵类型都应该在很少或没有变化的情况下工作。

In [50]: from scipy.sparse import csr_matrix

N1N2和数组w基本上是输入; w是一个长度为N1的数组。它包含将放在每一行中的值。在这里,我将w填入1。

In [51]: N1 = 15

In [52]: N2 = 12

In [53]: w = np.empty(N1, dtype=int)

In [54]: w[:] = 1

现在创建csr_matrix

In [55]: rows = np.arange(N1)

In [56]: cols = np.random.randint(0, N2, size=N1)

In [57]: conn_matrix = csr_matrix((w, (rows, cols)), shape=(N1, N2), dtype=int)

.A属性只是.toarray()方法的快捷方式;它返回一个常规的numpy数组:

In [58]: conn_matrix.A
Out[58]: 
array([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
       [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]], dtype=int64)

答案 1 :(得分:1)

因此,这里的速度问题可以重新构建为构建非常大的稀疏矩阵的有效问题。正如@Warren所指出的np.random.choice(np.arange(N2),size=N2,replace=False)元素N1仍然是一个随机排列问题。因此,经过一些思考后,上述内容的简明实现最终可能如下:

N1 = 10000000 #1e8
N2 = 5000
rows = np.arange(N1)
cols = (np.floor(np.random.permutation(N1)/float(N1)*N2)).astype(int) # Randomly pick N1 objects and assign to N2 categories in almost equal proportion
w = np.ones(N1)
conn_matrix = sparse.csr_matrix((w, (rows, cols)), shape=(N1, N2), dtype=int)