矩阵乘法:保持scipy.sparse.dok_matrix格式

Matrix multiplication: maintain scipy.sparse.dok_matrix format

我正在尝试使用 scipy 以 dok(键字典)格式执行稀疏线性代数计算。 当我将两个矩阵相乘时,格式从 dok 类型变为 csr 格式,这是数据和后续操作的低效格式。

如何保留dok格式?

我看过文档:

但是看不到任何信息自动类型转换或者是否以及如何避免它。

看这个例子:

from scipy.sparse import dok_matrix

my_mat = dok_matrix([[1,2], [3,4]])

print(type(my_mat.dot(my_mat)))
print(type(my_mat @ my_mat))

显示格式已更改:

<class 'scipy.sparse.csr.csr_matrix'>
<class 'scipy.sparse.csr.csr_matrix'>

只需转换回来:

result = result.todok()

CSR 可能是后续操作的低效格式(或者可能不是,我们无法判断),但它非常适合矩阵乘法。尝试使矩阵乘法代码对 DOK 结果进行原生操作会比仅转换结果慢。

正如@user2357112 所指出的,csr 适合线性代数。然而,转换的成本是巨大的。由于 dok 不是唯一支持可接受时间编辑的格式,因此值得检查另一个选项 lil。根据您的用例,您可能会节省很多时间:

from scipy import sparse
from timeit import timeit

a = random(100,100,0.1,format='lil')
b = random(100,100,0.1,format='dok')
a
# <100x100 sparse matrix of type '<class 'numpy.float64'>'
#         with 1000 stored elements in LInked List format>
b
# <100x100 sparse matrix of type '<class 'numpy.float64'>'
#         with 1000 stored elements in Dictionary Of Keys format>
timeit(lambda:(a@a).tolil(),number=100)*10
# 1.491789099527523
timeit(lambda:(b@b).todok(),number=100)*10
# 4.220661079743877

请注意,在此示例中 a@a/b@b 相当密集,如果我们选择较稀疏的情况,差异就​​不那么明显了:

a = random(100,100,0.01,format='lil')
b = random(100,100,0.01,format='dok')

timeit(lambda:(a@a).tolil(),number=100)*10
# 0.6880075298249722
timeit(lambda:(b@b).todok(),number=100)*10
# 0.7450748200062662