我试图找到一个有效的代码而不是下面的代码(这只是我的代码的一部分),以提高速度:
for pr in some_list:
Tp = T[partition[pr]].sum(0)
Tpx = np.dot(Tp, xhat)
hp = h[partition[[pr]].sum(0)
up = (uk[partition[pr][:]].sum(0))/len(partition[pr])
hpu = hpu + np.dot(hp.T, up)
Tpu = Tpu + np.dot(Tp.T, up)
我至少有两个相似的代码块。正如你所看到的,我使用了三次花式索引(真的找不到另一种方式)。在我的算法中,我需要很快完成这部分,但现在还没有发生。我真的很感激任何建议。
谢谢大家。
最佳,
答案 0 :(得分:3)
如果你的分区很少并且每个分区都有很多元素,你应该考虑交换对象的索引。沿着第二个维度对形状(30,1000)
的数组进行求和应该比沿着第一个维度对形状(1000,30)
的数组求和更快,因为在前一种情况下,您总是将相邻的内存块求和(即{{每个剩余索引的每个arr[k,:]
)1}}。因此,如果你将求和指数放在最后(并且在你使用时除去一些尾随的单一维度),你可能会加速。
作为hpaulj noted in a comment,不清楚你的循环是如何被矢量化的。但是,由于它的性能至关重要,您仍然可以尝试对某些工作进行矢量化。
我建议您为每个分区存储k
,hp
和up
(预分配后),然后在单个矢量化步骤中执行标量/矩阵产品。另请注意,Tp
在您的示例中未使用,因此我在此省略了它(无论您使用它做什么,您都可以像其他示例一样):
Tpx
显然,关键球员是numpy.einsum
。当然,如果part_len = len(some_list) # number of partitions, N
Tpshape = (part_len,) + T.shape[1:] # (N,30,100) if T was (1000,30,100)
hpshape = (part_len,) + h.shape[1:] # (N,30,1) if h was (1000,30,1)
upshape = (part_len,) + uk.shape[1:] # (N,30,1) if uk was (1000,30,1)
Tp = np.zeros(Tpshape)
hp = np.zeros(hpshape)
up = np.zeros(upshape)
for ipr,pr in enumerate(some_list):
Tp[ipr,:,:] = T[partition[pr]].sum(0)
hp[ipr,:,:] = h[partition[[pr]].sum(0)
up[ipr,:,:] = uk[partition[pr]].sum(0)/len(partition[pr])
# compute vectorized dot products:
#Tpx unclear in original, omitted
# sum over second index (dot), sum over first index (sum in loop)
hpu = np.einsum('abc,abd->cd',hp,up) # shape (1,1)
Tpu = np.einsum('abc,abd->cd',Tp,up) # shape (100,1)
和hpu
在循环之前有一些先前值,则必须使用上面Tpu
的结果递增这些值。
对于einsum
,它执行任意维数组的求和和收缩。上面的模式,einsum
,当应用于3d数组'abc,abd->cd'
和A
时,将返回一个二维数组B
,具有以下定义(数学伪代码):
C
对于给定的修正C(c,d) = sum_a sum_b A(a,b,c)*B(a,b,d)
求和指数,其内部是
a
如果保留sum_b A(a,b,c)*B(a,b,d)
和c
索引,则与d
相同。由于我们也将这些矩阵与np.dot(A(a,:,:).T,B(a,:,:))
进行求和,我们应该完全按照你的循环版本执行,总计每个a
贡献总和。