@Evan和@Martinis Group处在正确的轨道上-
扩大Evan的答案,以下是一个函数,该函数使用广播快速计算n维加权欧式距离,而无需Python循环:
import numpy as npdef fast_wdist(A, B, W): """ Compute the weighted euclidean distance between two arrays of points: D{i,j} = sqrt( ((A{0,i}-B{0,j})/W{0,i})^2 + ... + ((A{k,i}-B{k,j})/W{k,i})^2 ) inputs: A is an (k, m) array of coordinates B is an (k, n) array of coordinates W is an (k, m) array of weights returns: D is an (m, n) array of weighted euclidean distances """ # compute the differences and apply the weights in one go using # broadcasting jujitsu. the result is (n, k, m) wdiff = (A[np.newaxis,...] - B[np.newaxis,...].T) / W[np.newaxis,...] # square and sum over the second axis, take the sqrt and transpose. the # result is an (m, n) array of weighted euclidean distances D = np.sqrt((wdiff*wdiff).sum(1)).T return D为了检查是否可以正常工作,我们将其与使用嵌套Python循环的较慢版本进行比较:
def slow_wdist(A, B, W): k,m = A.shape _,n = B.shape D = np.zeros((m, n)) for ii in xrange(m): for jj in xrange(n): wdiff = (A[:,ii] - B[:,jj]) / W[:,ii] D[ii,jj] = np.sqrt((wdiff**2).sum()) return D
首先,让我们确保两个函数给出相同的答案:
# make some random points and weightsdef setup(k=2, m=100, n=300): return np.random.randn(k,m), np.random.randn(k,n),np.random.randn(k,m)a, b, w = setup()d0 = slow_wdist(a, b, w)d1 = fast_wdist(a, b, w)print np.allclose(d0, d1)# True
不用说,使用广播而不是Python循环的版本要快几个数量级:
%%timeit a, b, w = setup()slow_wdist(a, b, w)# 1 loops, best of 3: 647 ms per loop%%timeit a, b, w = setup()fast_wdist(a, b, w)# 1000 loops, best of 3: 620 us per loop



