我试图弄清楚如何加速以下Python代码。
基本上,代码构建矩阵visibleChildren
的外积的矩阵并将其存储为块对角稀疏矩阵。 br />我使用C
在块对角线中构建索引。
对代码进行分析后发现,对numpy.repeat()
的调用大约占执行时间的50%。
numpy.repeat()
最初,我正在构建稀疏矩阵,如下所示
import numpy as np
import scipy.sparse as spspar
L = 1000
K = 100
C = np.random.randn(L,K)
# From the matrix of outter products of C and store in block_diagonal
# sparse matrix
CCt = np.einsum('ij...,i...->ij...',C,C)
# create indices into the block diagonal sparse coo matrix
i = np.tile(np.tile(np.arange(K),K),L) + K*np.repeat(np.arange(L),K*K)
j = np.tile(np.repeat(np.arange(K),K),L) + K*np.repeat(np.arange(L),K*K)
# store as block diagonal sparse coo matrix
BlckCCt = spspar.coo_matrix((CCt.flatten(),(j,i)),shape=(K*K*L,K*K*L))
这太慢而且内存密集。
感谢您的任何意见。
编辑:我使用ipython timeit比较了@ hjpaul的建议。这是我能报告的内容
BlckCCt = spspar.block_diag(CCt,"coo")
所以看起来它们都需要大约相同的数量(我对ipython性能分析很新,所以也许我并没有以正确的方式比较它们。)
答案 0 :(得分:3)
仅供参考,您的
CCt = np.einsum('ij...,i...->ij...',C,C)
与
相同CCt1=C[:,None,:]*C[:,:,None]
生成(L,K,K)
数组。对于我较小的测试用例np.einsum
快2倍。
sparse.block_diag
将每个子矩阵转换为coo
,并将其传递给sparse.bmat
。 bmat
将所有子矩阵的rows
,cols
,data
收集到类似于j, i
的大数组中,并使用coo_matrix
调用ipython
那些。
对各个部分执行timeit
K*np.repeat(np.arange(L),K*K)
,我同意tile
是最慢的代码块。例如,比repeat
一块要慢得多。
由于您对i
和j
执行相同的kk= K*np.repeat(np.arange(L),K*K)
ii=np.tile(np.tile(np.arange(K),K),L) + kk
jj=np.tile(np.repeat(np.arange(K),K),L) + kk
,您只能执行一次,并使用该变量两次吗?
repeat
我会更多地看一下那件作品,但那是一个开始。
(np.zeros((K*K,),int)+np.arange(L)[:,None]).flatten()*K
:
np.tile(np.arange(L)*K,K*K).reshape(L,K*K).T.flatten()
甚至更好(> 2x)
*K
我已将arange(L)
移至较小的tile
,并使用更快的.T.flatten
。 (K*K,L)
负责更改订单。
根据评论,重塑应为K
。我正在测试那些并不重要的价值观。这些替代方案的相对速度因L
和i
的相对大小而异。
j
和kk
的第一部分的平铺是可选的,如果CCt
(第2部分)是形状(L,K,K)(如(0,4,0)
})。是否节省时间尚不清楚。跨度比完全平铺版本(4,)
v。i = (np.arange(K)[None,None,:] + kk.reshape(L,K,K)).flatten()
j = (np.arange(K)[None,:,None] + kk.reshape(L,K,K)).flatten()
更复杂。)
kk
我们可以对k1 = K*np.arange(L)[:,None,None]
np.arange(K)[None,None,:] + k1
i = np.tile( np.arange(K)[None,None,:] + k1, (1,K,1)).flatten()
j = np.tile( np.arange(K)[None,:,None] + k1, (1,1,K)).flatten()
是(L,1,K),所以我们需要将其平铺
np.ix_
生成这些数组的另一种方法是使用i = np.sum(np.ix_(K*np.arange(L), np.arange(K), np.zeros(K)))
j = np.sum(np.ix_(K*np.arange(L), np.zeros(K), np.arange(K)))
重新整形范围,然后只对值进行求和。
.flatten
(根据需要添加{{1}})。我已经在小尺寸上对它进行了测试,看起来是正确的。我不知道速度。