为什么在选择行时CSR格式胜过CSC格式?

时间:2019-04-28 11:59:41

标签: python scipy sparse-matrix

我正在基于scipy.sparse对CSR和CSC格式进行这个小实验。如documentation所述,在处理列操作时,CSC格式比CSR格式更有效。所以我做了一个小实验:

from scipy.sparse import diags
d = diags([-1, 1, 1], [-1, 0, -1], shape= (100, 100))
%timeit d.tocsc()[:, 1]
%timeit d.tocsr()[:, 1]

然后我想我以错误的方式得到了行和列。所以我尝试了另一种方法:

%timeit d.tocsc()[1]
%timeit d.tocsr()[1]

但是在某些情况下,企业社会责任在时机上要优于企业社会责任。我想知道这种结果是否有任何结构性原因,还是我的测试有偏见?

1 个答案:

答案 0 :(得分:1)

稀疏矩阵的索引很复杂,其中包含许多可能影响时间的变量。您的测试用例是对称的,因此csrcsc格式几乎相同。如果形状为矩形或布局不同,情况可能会有所不同。

标量,切片和列表的索引编制也可能不同。

请记住,不管格式如何,稀疏索引比numpy.ndarray慢得多。如果需要迭代,请尽量不要使用稀疏。 (而且,如果必须迭代,请考虑直接使用“原始”稀疏属性。)

In [64]: d = sparse.diags([-1, 1, 1], [-1, 0, 1], shape= (100, 100))                 
In [65]: d                                                                           
Out[65]: 
<100x100 sparse matrix of type '<class 'numpy.float64'>'
    with 298 stored elements (3 diagonals) in DIAgonal format>

In [66]: %timeit d.tocsr()[:,1]                                                      
422 µs ± 13.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [67]: %timeit d.tocsc()[:,1]                                                      
506 µs ± 5.89 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [68]: %timeit d.tocsc()[1,:]                                                      
506 µs ± 1.15 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

将转化与索引分开:

In [69]: %%timeit x=d.tocsr() 
    ...: x[:,1]                                                                              
121 µs ± 2.05 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [70]: %%timeit x=d.tocsr() 
    ...: x[1,:]                                                                           
118 µs ± 2.95 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [71]: %%timeit x=d.tocsc() 
    ...: x[:,1]                                                                            
290 µs ± 5.89 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [72]: %%timeit x=d.tocsc() 
    ...: x[1,:]                                                                            
297 µs ± 14.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

csr的速度始终更快,令我有些惊讶。但是一点点。 csccsr使用通用的compressed基类(sparse.compressed._cs_matrix),但是编码细节似乎更适合csr

===

只是为了好玩,索引lil格式

In [73]: %%timeit x=d.tolil() 
    ...: x[1,:]                                                                            
76.4 µs ± 231 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [74]: %%timeit x=d.tolil() 
    ...: x[:,1]                                                                       
118 µs ± 647 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

正如lil存储所期望的那样,尽管列索引时间还不错,但行索引的速度更快。

lil有一个getrow,它是sparse中最接近numpy视图的东西:

In [75]: %%timeit x=d.tolil() 
    ...: x.getrow(1)                                                                          
36.7 µs ± 233 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

===

密集数组索引,即使转换时间更快:

In [83]: %%timeit x=d.A 
    ...: x[:,1]                                                                          
277 ns ± 9.97 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [84]: timeit d.A[:,1]                                                             
197 µs ± 587 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)