为何Scipy稀疏矩阵计算Gram矩阵(X.T@X)比Numpy密集运算慢?
问题:Scipy稀疏矩阵计算Gram矩阵反而比Numpy密集矩阵慢?
我需要计算Gram矩阵(即矩阵转置与自身的乘积,表达式为X.T @ X)。实际测试发现,将Scipy稀疏矩阵转换为Numpy密集数组后再计算该乘积,比直接用Scipy稀疏矩阵运算快得多。这一反直觉结果令我困惑,因为原本认为Scipy会利用数据的稀疏特性来提升运算速度。以下是复现代码及结果,显示Scipy运算速度约为Numpy的1/10:
import time from scipy import sparse # generate random sparse matrix n_samples, n_features = 10000, 200 density = 0.5 X = sparse.random(n_samples, n_features, density, format='csc') # time scipy operation start = time.time() X.T @ X duration_scipy = time.time() - start print("scipy: ", duration_scipy) # time numpy operations start = time.time() X_dense = X.toarray() X_dense.T @ X_dense duration_numpy = time.time() - start print("numpy: ", duration_numpy) print( "============\n" f"ratio np/sp: {duration_numpy / duration_scipy}" ) # Output: # scipy: 0.09316086769104004 # numpy: 0.009956836700439453 # ============ # ratio sp/np: 9.356472391169005
原因分析
这种现象核心是你的矩阵根本不算“稀疏”,再加上两种矩阵运算的底层逻辑差异:
密度阈值不达标:你设置的
density=0.5意味着50%的元素都是非零值,这远超稀疏矩阵的优势适用范围——一般只有非零占比低于10%(甚至1%以下)时,稀疏矩阵的存储和运算优势才会体现。当密度达到50%时,稀疏矩阵需要额外存储行/列索引等结构,反而会带来额外开销,而密集矩阵的连续内存布局更适合CPU高效处理。运算效率的底层差异:
- Scipy稀疏矩阵计算
X.T @ X时,需要遍历零散的非零元素,做大量索引查找和碎片化的乘加操作,很难利用CPU的缓存、多线程和SIMD向量指令,数据访问效率极低。 - Numpy密集矩阵的转置乘运算,会调用OpenBLAS、MKL这类高度优化的线性代数库,这些库会自动利用多线程并行、缓存预取、向量运算等技术把计算效率拉满——尤其是你的结果是200x200的小矩阵,中间的大矩阵乘积累计过程能被极致优化。
- Scipy稀疏矩阵计算
结果矩阵的稀疏性缺失:
X.T @ X的结果是200x200的矩阵,当X的密度为50%时,这个结果矩阵几乎是全密集的(任意两列的点积大概率非零)。Scipy仍会按稀疏结构去构建结果,额外承担了稀疏矩阵的构建开销,而Numpy直接用密集矩阵计算,完全没有这部分负担。
简单说,你的场景里稀疏矩阵的“稀疏特性”完全没发挥作用,反而被自身结构拖了后腿,而密集矩阵的硬件优化优势则完全体现了出来。
内容的提问来源于stack exchange,提问作者Badr MOUFAD
相关产品推荐
相关产品推荐

