scipy 为什么从密集阵列转换为稀疏阵列后运行速度更快?

yx2lnoni  于 2022-11-10  发布在  其他
关注(0)|答案(1)|浏览(134)

为了简化,我有下面的测试代码:

from scipy.sparse import csr_matrix, dok_array, issparse
import numpy as np
from tqdm import tqdm

X = np.load('dense.npy')

# convert it to csr sparse matrix

# X = csr_matrix(X)

print(repr(X))

n = X.shape[0]
with tqdm(total=n*(n-1)//2) as pbar:
    cooccur = dok_array((n, n), dtype='float32')
    for i in range(n):
        for j in range(i+1, n):
            u, v = X[i], X[j]
            if issparse(u):
                u = u.toarray()[0]
                v = v.toarray()[0]
                #import pdb; pdb.set_trace()
            m = u - v
            min_uv = u - np.maximum(m, 0)
            val = np.sum(min_uv - np.abs(m) * min_uv)
            pbar.update()

案例1:按原样运行-时间使用情况如下(2分54秒):

案例2:取消注解X=csr_matrix(X)行(只是为了比较),运行时间为1分56秒:

这很奇怪,我不明白为什么在密集阵列上操作会更慢。对于原始阵列,稀疏阵列和密集阵列之间的运行时间差异很大(由于大量的迭代)。
我将代码放入一个函数中,并使用line_profiler查看时间使用情况。1.对于稀疏矩阵,切片确实慢得多; 2.最后一行之上的3行在情况2中快得多; 3.对于情况2,总的运行时间更小,即使它花费额外的时间用于切片和转换成密集矢量。
我很困惑为什么这3行代码在案例1和案例2中花费了不同的运行时间--它们在这两个案例中是完全相同的numpy向量。有什么解释吗?
dense.npy文件上传到here,以重现观察结果。

63lcw9qa

63lcw9qa1#

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

n = 1_000
sparsity = 0.98

A = np.random.rand(n, n)
A[A < sparsity] = 0
As = csr_matrix(A)

def _test(X):
    n = X.shape[0]
    for i in range(n):
        for j in range(i+1, n):
            u, v = X[i], X[j]
            if issparse(u):
                u = u.toarray()[0]
                v = v.toarray()[0]
            m = u - v
            min_uv = u - np.maximum(m, 0)
            val = np.sum(min_uv - np.abs(m) * min_uv)

在高密度上运行此程序:

%timeit _test(A)
5.3 s ± 21.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

在稀疏数据库上运行此程序:

%timeit _test(As)
1min 10s ± 1.06 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

这是有意义的,因为您实际上并没有将稀疏数据结构用于任何事情-您只是在每次内部循环迭代时将其昂贵且低效地转换回密集数据结构。
我不知道你是如何得到运行时的,因为密集和稀疏之间的数量级差异是我对你提供的代码的期望。

相关问题