Python 访问矩阵并将值放入矩阵的最快方式

Python 访问矩阵并将值放入矩阵的最快方式,python,numpy,scipy,sparse-matrix,Python,Numpy,Scipy,Sparse Matrix,我写了一个程序,并一直在分析它。瓶颈如下(如果我使用稀疏矩阵): 如果我使用密集矩阵,那么这些操作很慢(必须将矩阵初始化为零) 稀疏矩阵版本速度更快(193秒对178秒)。但对我来说,检索和放置行显然是一个瓶颈。我尝试使用take函数,其中我使用range()创建一个包含行索引的数组。然而,这比我目前所做的要糟糕得多(10000倍),对于矩阵X,X[idx,:]用于放置,而X.getrow(idx).todense()用于获取 是否有更好的方法访问和替换这些行?我的矩阵相当大(约100000行2

我写了一个程序,并一直在分析它。瓶颈如下(如果我使用稀疏矩阵):

如果我使用密集矩阵,那么这些操作很慢(必须将矩阵初始化为零)

稀疏矩阵版本速度更快(193秒对178秒)。但对我来说,检索和放置行显然是一个瓶颈。我尝试使用
take
函数,其中我使用
range()
创建一个包含行索引的数组。然而,这比我目前所做的要糟糕得多(10000倍),对于矩阵X,
X[idx,:]
用于放置,而
X.getrow(idx).todense()
用于获取

是否有更好的方法访问和替换这些行?我的矩阵相当大(约100000行20-500列)

编辑: 我正在使用csr_矩阵(但对任何类型的稀疏矩阵都是开放的——这一种似乎适合抓取行)。下面是一系列测试,仅给出MWE。速度约为3E-4s、7E-3s、1s。这让我感到惊讶,我想知道是否有比top方法更快的方法。如果我删除todense()调用,稀疏时间将减少一半,但这似乎仍然相当缓慢

import numpy as np
from time import time
from scipy.sparse import csr_matrix

def testFancy(mat,idxs):
    for i in idxs:
        x = mat[i,:]

def testTake(mat,idxs):
    for i in idxs:
        x = mat.take(range(i*50,i*50+50))

def testSparse(mat,idxs):
    for i in idxs:
        x = mat.getrow(i).todense()

mat = np.random.rand(50000,50)
idxs = np.random.randint(50000-1, size=1000)

#fancy
t0 = time()
testFancy(mat,idxs)
t1 = time()
print str(t1-t0)

#take
t0 = time()
testTake(mat,idxs)
t1 = time()
print str(t1-t0)

#sparse
mat = csr_matrix((50000,50))
t0 = time()
testSparse(mat,idxs)
t1 = time()
print str(t1-t0)

只需使用奇特的索引,用于获取和设置数组中的行

import numpy as np
from scipy.sparse import csr_matrix

mat_ds = np.random.rand(50000,50)
mat_csr = csr_matrix((50000,50))
mat_lil = mat_csr.tolil()

idxs = np.random.randint(50000-1, size=1000)

print(mat_sp[idxs, :].todense())
print(mat_csr[idxs, :])

mat_sp[idxs, :] = 2.0 # or any other expression that makes sens here
mat_csr[idxs, :] = 2.0 
数组是否稀疏并不重要。这将比任何带有循环的定制解决方案都要快(在我的例子中,比
testSparse
快约250倍)

当然,对稀疏数组的赋值应该以保持稀疏性的方式进行,否则它将被重新分配,这对于
csr\u矩阵来说是非常昂贵的。例如,上面的示例会产生警告

编辑:回应评论。让我们考虑只查询一行,

In [1]: %timeit -n 1 mat_csr[0, :].todense()
1 loops, best of 3: 101 µs per loop

In [2]: %timeit -n 1 mat_lil[0, :].todense()
1 loops, best of 3: 157 µs per loop

In [3]: %timeit -n 1 mat_ds[0, :]
The slowest run took 8.25 times longer than the fastest. This could mean that an intermediate result is being cached 
1 loops, best of 3: 954 ns per loop

是的,查询密集数组的速度比结果转换为密集的稀疏数组快10到100倍(无论您使用csr还是lil数组),因为开销更小。对此无能为力,您只需选择是否需要稀疏数组

我试着使用一个dok_mat:rix。我的测试结果为0.03s,总体应用为66s,包括:

3034124   11.833    0.000   20.293    0.000 defmatrix.py:312(__getitem__)

这似乎是一个很好的折衷方案,但我确实想知道它是否能更好。

An会有所帮助。您能提供一个我们可以复制粘贴的最小工作示例吗?除此之外,很难说什么。还要注意的是,稀疏矩阵有不同的实现。仅从术语
sparse matrix
我们只能猜测底层数据结构。
sparse.csr_矩阵
有一个定义良好的数据结构-压缩的稀疏行。
csr_矩阵((50000,50))
有0个非零元素。将它和密集的形状数组进行比较是并没有意义的。您需要提供有关“检索并放入行”位的更多详细信息。同时阅读各种稀疏格式的优缺点(例如,比较csr和lil等)。循环只是为了规范计算时间。访问将一次完成一行。@user671931我更新了答案以考虑您的评论。
In [1]: %timeit -n 1 mat_csr[0, :].todense()
1 loops, best of 3: 101 µs per loop

In [2]: %timeit -n 1 mat_lil[0, :].todense()
1 loops, best of 3: 157 µs per loop

In [3]: %timeit -n 1 mat_ds[0, :]
The slowest run took 8.25 times longer than the fastest. This could mean that an intermediate result is being cached 
1 loops, best of 3: 954 ns per loop
3034124   11.833    0.000   20.293    0.000 defmatrix.py:312(__getitem__)