Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 高效计算稀疏数组的列式和,其中每个非零元素为1_Python_Arrays_Numpy_Scipy_Sparse Matrix - Fatal编程技术网

Python 高效计算稀疏数组的列式和,其中每个非零元素为1

Python 高效计算稀疏数组的列式和,其中每个非零元素为1,python,arrays,numpy,scipy,sparse-matrix,Python,Arrays,Numpy,Scipy,Sparse Matrix,我有一大堆格式的数据。当然大多数元素都是零,我还知道所有非零元素的值都是1。我想计算矩阵中行的不同子集的和。目前,我正在做以下工作: 将numpy导入为np 将scipy作为sp导入 导入scipy.sparse #创建一些分布稀疏的数据 数据=np.随机选择((0,1),大小=(10002000),p=(0.95,0.05)) data=sp.sparse.csr_矩阵(数据,dtype='int8') #在行的随机子集上生成列式和 nrand=1000 对于范围内的k(nrand): ind

我有一大堆格式的数据。当然大多数元素都是零,我还知道所有非零元素的值都是1。我想计算矩阵中行的不同子集的和。目前,我正在做以下工作:

将numpy导入为np
将scipy作为sp导入
导入scipy.sparse
#创建一些分布稀疏的数据
数据=np.随机选择((0,1),大小=(10002000),p=(0.95,0.05))
data=sp.sparse.csr_矩阵(数据,dtype='int8')
#在行的随机子集上生成列式和
nrand=1000
对于范围内的k(nrand):
inds=np.random.choice(data.shape[0],size=100,replace=False)
#60%的时间都花在这里
提取的行=数据[IND]
#20%的时间都花在这里
行总和=提取的行总和(轴=0)
最后几行是更大的计算管道中的瓶颈。正如我在代码中所注释的,60%的时间用于从随机索引中分割数据,20%用于计算实际总和


在我看来,我应该能够利用我对数组中数据的了解(即稀疏矩阵中的任何非零值都是1;没有其他值存在)来更有效地计算这些和。不幸的是,我不知道怎么做。只处理
数据。索引
也许?我尝试过其他稀疏结构(例如CSC矩阵),以及首先转换为密集数组,但这些方法都比CSR矩阵方法慢。

众所周知,稀疏矩阵的索引速度相对较慢。通过直接访问数据属性来解决这个问题有很多问题

但首先是一些时间安排。使用
数据
ind
如您所示

In [23]: datad=data.A  # times at 3.76 ms per loop

In [24]: timeit row_sumd=datad[inds].sum(axis=0)
1000 loops, best of 3: 529 µs per loop

In [25]: timeit row_sum=data[inds].sum(axis=0)
1000 loops, best of 3: 890 µs per loop

In [26]: timeit d=datad[inds]
10000 loops, best of 3: 55.9 µs per loop

In [27]: timeit d=data[inds]
1000 loops, best of 3: 617 µs per loop
稀疏的版本比密集的版本慢,但不是很多。稀疏索引的速度要慢得多,但其总和要快一些

稀疏和是用矩阵乘积完成的

def sparse.spmatrix.sum
     ....
    return np.asmatrix(np.ones((1, m), dtype=res_dtype)) * self
这表明,更快的方法是将
inds
转换成一个适当的1数组并进行乘法

In [49]: %%timeit
   ....: b=np.zeros((1,data.shape[0]),'int8')
   ....: b[:,inds]=1
   ....: rowmul=b*data
   ....: 
1000 loops, best of 3: 587 µs per loop
这使得稀疏运算的速度与等效的密集运算的速度一样快。(但转换为“密集”要慢得多)

==================

上一次测试缺少稀疏
中存在的
np.asmatrix
。但时间是相似的,结果也是一样的

In [232]: timeit b=np.zeros((1,data.shape[0]),'int8'); b[:,inds]=1; x1=np.asmatrix(b)*data
1000 loops, best of 3: 661 µs per loop

In [233]: timeit b=np.zeros((1,data.shape[0]),'int8'); b[:,inds]=1; x2=b*data
1000 loops, best of 3: 605 µs per loop
一个生成矩阵,另一个生成数组。但两者都在做矩阵积,第二个维度是
B
,而第一个维度是
数据。尽管
b
是一个数组,但任务实际上是委托给
数据及其矩阵乘积的——以一种不那么透明的方式

In [234]: x1
Out[234]: matrix([[9, 9, 5, ..., 9, 5, 3]], dtype=int8)

In [235]: x2
Out[235]: array([[9, 9, 5, ..., 9, 5, 3]], dtype=int8)
b*data.A
是元素乘法并引发错误
np.dot(b,data.A)
可以工作,但速度较慢

较新的
numpython/python
有一个
matmul
操作符。我看到了同样的时间模式:

In [280]: timeit b@dataA           # dense product
100 loops, best of 3: 2.64 ms per loop

In [281]: timeit b@data.A           # slower due to `.A` conversion
100 loops, best of 3: 6.44 ms per loop

In [282]: timeit b@data             # sparse product
1000 loops, best of 3: 571 µs per loop

np.dot
也可以将操作委托给
sparse
,不过您必须小心。我刚刚用
np.dot(csr\u矩阵(b),data.A)
数据
转换为密集数组,并使用-

运行时测试-

1) 函数定义:

def org_app(nrand,n):
    out = np.zeros((nrand,data.shape[1]),dtype=int)
    for k in range(nrand):
        inds = np.random.choice(data.shape[0], size=n, replace=False)        
        extracted_rows = data[inds]    
        out[k] = extracted_rows.sum(axis=0)    
    return out


def vectorized_app(nrand,n):
    inds2D = np.random.rand(nrand,data.shape[0]).argpartition(n)[:,:n]
    return np.array(data.todense())[inds2D.ravel()].reshape(nrand,n,-1).sum(1)
时间:

In [205]: # create some data with sparsely distributed ones
     ...: data = np.random.choice((0, 1), size=(1000, 2000), p=(0.95, 0.05))
     ...: data = sp.sparse.csr_matrix(data, dtype='int8')
     ...: 
     ...: # generate column-wise sums over random subsets of rows
     ...: nrand = 1000
     ...: n = 100
     ...: 

In [206]: %timeit org_app(nrand,n)
1 loops, best of 3: 1.38 s per loop

In [207]: %timeit vectorized_app(nrand,n)
1 loops, best of 3: 826 ms per loop

这里可能对您有用的两个函数是
rows,cols=extracted\u rows.nonzero()
,它为您提供非零组件的索引,也可能是
np.count\u nonzero()
,它在一个麻木的数组中统计非零项,但不幸的是,这种方法在实际应用程序中消耗了太多内存。这很好,这是一个巨大的速度提升!但是,请注意,您的代码(最终代码段)本身并没有正确运行:
b
必须是一个Numpy
matrix
,因此:
b=np.asmatrix(…)
,就像原始的
sparse.spmatrix.sum
实现一样。否则,Numpy将尝试计算elementwise乘积,这将不起作用。(还要注意,
np.dot
对稀疏矩阵不起作用,
csr\u矩阵.dot
在这里不适用,因为这里的csr矩阵在等式的右侧。)非常感谢!
asmatrix
没有多大区别。查看我的编辑。
In [205]: # create some data with sparsely distributed ones
     ...: data = np.random.choice((0, 1), size=(1000, 2000), p=(0.95, 0.05))
     ...: data = sp.sparse.csr_matrix(data, dtype='int8')
     ...: 
     ...: # generate column-wise sums over random subsets of rows
     ...: nrand = 1000
     ...: n = 100
     ...: 

In [206]: %timeit org_app(nrand,n)
1 loops, best of 3: 1.38 s per loop

In [207]: %timeit vectorized_app(nrand,n)
1 loops, best of 3: 826 ms per loop