默认使用csr格式的稀疏矩阵
1、如果要统计稀疏矩阵全部元素的和,不要用sum(a),用np.sum(a)或则a.sum()就好。对于shape=10000*10000的矩阵而言,全部求和采用np.sum比sum高效得多:
number = np.sum(sum(xtest_mask),axis=1)[0,0] 2.2秒
number = np.sum(xtest_mask) 0.004秒
更应该直接用xtest_mask.sum() 速度也超快
2、逐元素操作效率
注意:
xtrain 和xtrain_mask
<10000x10000 sparse matrix of type '<class 'numpy.int64'>'
with 6897746 stored elements in Compressed Sparse Row format>
xtest 和xtest_mask
<10000x10000 sparse matrix of type '<class 'numpy.int64'>'
with 1719466 stored elements in Compressed Sparse Row format>
两者是四倍关系,。
xtrain_mask[xtrain_mask > 0] = 1 0.73秒
xtest_mask[xtest_mask > 0] = 1 0.17秒
时间上也是接近四倍关系。符合预期。
3、转换为np.array的效率
q=xtrain.toarray() 1.5秒
q=xtest.toarray() 0.37秒
4、求范数
norm_train = linalg.norm(xtrain,axis=1) 0.17秒
norm_train = np.linalg.norm(q,axis=1) 1.479秒
注意,求出范数后维度是(10000,),需要用reshape转换为(10000,1),此步几乎不耗时间。
norm_train = norm_train.reshape(np.shape(norm_train)[0],1)
5、矩阵乘法(尺寸改为5000*5000)
sim = (xtrain * xtrain.T) 12.45秒 (这个默认执行的是矩阵乘法而不是按位乘法))
先将xtrain转换为np.array():q,然后再计算:
sim2=np.dot(q,q.T) 矩阵乘法。这个计算的结果耗时很长很长。 183秒
sim22=np.dot(q,q) 矩阵乘法。这个计算的结果耗时很长很长。 很长时间都没有算出来。
为什么呢?因为矩阵是整型。转换成浮点型就会快很多倍!
q1=q.astype(float)
sim2=np.dot(q1,q1.T) 4.80秒
sim2=np.dot(q1,q1) 8.11秒
但这个对于稀疏矩阵的矩阵乘法而言则没有明显增益。
x1=xtrain.astype(float)
simf=x1*x1.T 12.19秒
sim3=q*q.T 默认执行的是按位乘法而不是矩阵乘法。 0.5秒 (如果后者不转置只需要0.18秒)
sim4=np.multiply(q,q.T) 执行的是按位乘法。时间结果同上。
sim5=np.multiply(xtrain ,xtrain.T) 12.64秒 同sim
如果直接用sparse内置的算法呢?
sim = xtrain.dot(xtrain.T) 12.42秒(同*号)
再做一点测试(norm_all是一个5000*5000的稠密的array)
test1=xtrain*norm_all 14.23秒 array 矩阵乘法
test11=xtrain.toarray()*norm_all 0.34秒 array 按位乘
test2=xtrain.dot(norm_all) 14.11秒 array 矩阵乘法,同test1
test13=np.dot(xtrain.toarray(),norm_all) 9.53秒 array 矩阵乘法
test14=np.dot(norm_all,norm_all) 7.84秒
test15=np.dot(norm_all,norm_all.T) 4.5秒
test3=xtrain.multiply(norm_all) 0.15 coo稀疏矩阵
q*norm_all=0.18
test3=xtrain.multiply(norm_all[0]) 0.09秒 coo稀疏矩阵
test3=xtrain.multiply(norm_all[0,0]) 0.016秒 csr稀疏矩阵
6、矩阵除以一个常数
sim/2 24.36秒 (100002)
sim/2 2.45秒 (50002)
sim.multiply(0.5) 0.24秒 (50002)
sim2/2 0.15mioa (50002)
7、矩阵按位除以矩阵
sim/sim 3.9秒 (50002)matrix
sim.toarray()/sim.toarray() 0.65秒 array
sim/sim.toarray() 0.68秒
sim.toarray()/sim 不支持
xtrain/xtrain 0.55秒 matrix
q/q 0.13 秒
norm_all = (norm_train * norm_train.T) 0.12 array
norm_all_re = np.power(norm_all,-1) 1.36 得到按位倒数矩阵(方便做等价按位除法)
sim_norm = sim/norm_all 0.48 float的matrix
sim_norm = sim.toarray()/norm_all 0.45 float的array
norm_all_re = np.power(norm_all,-1) 1.36
sim_norm2 = (sim.multiply(norm_all_re)) 1.56 得到coo稀疏阵再通过tocsr转换要0.38秒
注:sim_re=sim.power(-1) 会报错,稀疏矩阵的Power函数不支持负数,所以就不能通过sim.multiply(sim_re)的方式实现按位除了。
总结:
- 对稀疏矩阵求范数、求解Ax=b、求逆、矩阵分解等操作可以直接用稀疏矩阵自带的算法进行求解,会高效很多;。
- 涉及到矩阵乘法还是转换成array更快!一定要转换!
- 矩阵乘法,如果是浮点型array,是最快的。若是整型array,则会超级超级慢!注意!浮点型和整型对稀疏矩阵的矩阵乘法没有太大的影响。
- 对于array而言,*默认为按位乘法。对于稀疏矩阵sparse而言,*默认为矩阵乘法。
- 按位乘法,如果是两者都是矩阵,则array远快于稀疏矩阵。如果其中一个为标量,则稀疏矩阵更快。
- 按位除法,如果是两者都是矩阵,则array远快于稀疏矩阵。如果其中一个为标量,则可以转换为按位乘法,稀疏矩阵更快。
总之,稀疏矩阵是不适合用于矩阵与矩阵之间的运算的。不论是按位运算还是矩阵运算。
参考资料
https://blog.csdn.net/mantoureganmian/article/details/80612137
scipy.sparse稀疏矩阵内积点乘--效率优化!