【问题标题】:Vectorise Python code向量化 Python 代码
【发布时间】:2016-10-10 10:35:21
【问题描述】:

我编写了克里金算法,但我发现它很慢。特别是,你知道我如何在下面的 cons 函数中对这段代码进行矢量化:

import time
import numpy as np

B = np.zeros((200, 6))
P = np.zeros((len(B), len(B)))

def cons():
  time1=time.time()
  for i in range(len(B)):
    for j in range(len(B)):
      P[i,j] = corr(B[i], B[j])
  time2=time.time()
  return time2-time1

def corr(x,x_i):
  return np.exp(-np.sum(np.abs(np.array(x) - np.array(x_i))))    

time_av = 0.
for i in range(30):
  time_av+=cons()
print "Average=", time_av/100.

编辑:奖励问题

  1. 如果我希望 corr(B[i], C[j]) 的 C 与 B 具有相同的维度,广播解决​​方案会发生什么
  2. 如果我的 p-norm 订单是一个数组,scipy 解决方案会发生什么:

    p=np.array([1.,2.,1.,2.,1.,2.])
    def corr(x, x_i):
      return np.exp(-np.sum(np.abs(np.array(x) - np.array(x_i))**p))  
    

    对于 2.,我尝试了 P = np.exp(-cdist(B, C,'minkowski', p)),但 scipy 期待一个标量。

【问题讨论】:

  • @TobySpeight 虽然 CR only 接受工作代码,但我不认为所有性能改进问题都是题外话。 This here says so too.
  • 不要添加需要对发布的解决方案进行重大修改的细节。相反,发布一个包含这些新细节的新问题以及是否需要。链接到这个问题。

标签: python numpy vectorization


【解决方案1】:

您的问题似乎很容易矢量化。对于您要计算的每对 B

P[i,j] = np.exp(-np.sum(np.abs(B[i,:] - B[j,:])))

您可以利用数组广播并引入第三个维度,沿最后一个求和:

P2 = np.exp(-np.sum(np.abs(B[:,None,:] - B),axis=-1))

这个想法是将B 的第一次出现重塑为(N,1,M),而第二个B 则保留为(N,M)。使用数组广播,后者相当于(1,N,M),所以

B[:,None,:] - B

形状为(N,N,M)。沿最后一个索引求和将产生您正在寻找的(N,N)-shape 相关数组。


请注意,如果您使用scipy,则可以使用scipy.spatial.distance.cdist(或等效地,scipy.spatial.distance.pdistscipy.spatial.distance.squareform 的组合)来执行此操作,而无需计算下三角半部分对称矩阵。以这种方式在 cmets 中使用@Divakar 的建议以获得最简单的解决方案:

from scipy.spatial.distance import cdist
P3 = 1/np.exp(cdist(B, B, 'minkowski',1))

cdist 将计算 1 范数的 Minkowski 距离,这正是坐标差绝对值的总和。

【讨论】:

  • 因此,我猜1/np.exp(pdist(B, 'minkowski',1))1/np.exp(cdist(B, B, 'minkowski',1)) 可以添加到那里。
  • @Divakar 是的,我不想太明确,因为 OP 似乎不使用 scipy,所以额外的导入可能是矫枉过正。但无论如何我都会添加它:)另外,感谢cdist,我不知道它的存在。
  • 非常完整的答案,谢谢。@AndrasDeak 事实上,我想避免使用 scipy 但 cdist 函数看起来很有趣。您指出下三角矩阵的计算是无用的,在我的代码中,我实际上有从 i+1 开始的第二个 for 循环:for j in range(i+1, len(B)),有没有机会通过您的第一个解决方案实现这一目标?
  • @Jean 不支持数组广播,我不这么认为。如果依赖 scipy 不是问题,我建议您同时计算冗余 numpy 版本和 scipy 版本;您可能会发现即使导入一次 scipy 的开销也是最快的。
  • 所以对于我得到的时间,平均超过 100 次尝试:我的解决方案:0.339s,数组广播:0.00393s 和 scipy(没有导入时间):0.00333s。
猜你喜欢
  • 1970-01-01
  • 2015-07-29
  • 2019-04-25
  • 1970-01-01
  • 1970-01-01
  • 2017-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多