我有一个对列表(比如' A ')和两个数组,&#39 ;的乙'和' C ' (每个数组有三列)。阵列' B'和' C'是坐标/向量的集合(3维)。 ' A'是一对指数列表;每对中的第一个条目表示B 中行的索引,每对中的第二个条目指向C 中行的索引。举个例子:
A = [(0, 0), (0, 1), (0, 3), (1, 2), (2, 2)]
B = [[ 0.1 0.4 0.5]
[ 0.7 0.0 0.4]
[ 0.8 0.4 0.7]
[ 0.9 0.3 0.8]]
C = [[ 0.9 0.8 0.9]
[ 0.3 0.9 0.5]
[ 0.3 0.4 0.8]
[ 0.5 0.4 0.3]]
对于列表A中的每一对,我希望找到B和C中向量的欧几里德范数。也就是说,对于对(i,j),我希望找到Norm(B [i,:] - C [j,:])。我希望以最快的方式为所有对做这件事。
目前,我是按照以下方式进行的:
import numpy as np
map( lambda x: np.sqrt( (B[x[0]] - C[x[1]]).dot(B[x[0]] - C[x[1]]) ), A)
我发现上述技术比以下技术更快:
map( lambda x: np.linalg.norm((B[x[0]] - C[x[1]])), A)
我正在处理数组B和C ,其中数百万行。谁能告诉我如何在 python 中以最快的方式获得上述功能?
答案 0 :(得分:4)
尝试(时间测量样式可能仅适用于python> = 3.3):
import numpy as np
import time
A = np.array([[0, 0], [0, 1], [0, 3], [1, 2], [2, 2]])
B = np.array([[ 0.1, 0.4, 0.5],
[ 0.7, 0.0, 0.4],
[ 0.8, 0.4, 0.7],
[ 0.9, 0.3, 0.8]])
C = np.array([[ 0.9, 0.8, 0.9],
[ 0.3, 0.9, 0.5],
[ 0.3, 0.4, 0.8],
[ 0.5, 0.4, 0.3]])
# your approach A
start = time.perf_counter()
print(list(map( lambda x: np.sqrt( (B[x[0]] - C[x[1]]).dot(B[x[0]] - C[x[1]]) ), A))) # outer list because of py3
print('used: ', time.perf_counter() - start)
# your approach B
start = time.perf_counter()
print(list(map( lambda x: np.linalg.norm((B[x[0]] - C[x[1]])), A))) # outer list because of py3
print('used: ', time.perf_counter() - start)
# new approach
start = time.perf_counter()
print(np.linalg.norm(B[A[:,0]] - C[A[:,1]], axis=1))
print('used: ', time.perf_counter() - start)
输出:
[0.97979589711327131, 0.53851648071345037, 0.44721359549995798,
0.69282032302755092, 0.50990195135927852]
used: 0.0014244442358304925
[0.97979589711327131, 0.53851648071345037, 0.44721359549995798,
0.69282032302755092, 0.50990195135927852]
used: 0.0004404035049961194
[ 0.9797959 0.53851648 0.4472136 0.69282032 0.50990195] # probably hidden print-magic which cuts off some digits during print
used: 0.0010253945897682102
这些时间显然与输入有关,而且它是一个非常糟糕的基准,所以请自行测量数据!
对于numpy风格,新方法可以说是最干净的,但根据您的数据,它不需要是最快的。总的来说,我希望它是使用大多数BLAS和矢量化处理的方法。
对于较大的向量,请确保您有一个快速的多线程BLAS分发链接到numpy。
答案 1 :(得分:2)
检查出来:
import numpy as np
A = np.random.randint(1000, size=(10000,2))
B = np.random.randn(1000,3)
C = np.random.randn(1000,3)
def f():
return np.linalg.norm(B[A[:,0]] - C[A[:,1]], axis=1)
%timeit f() # >>> 100000 loops, best of 3: 448 µs ms per loop
def g():
return map( lambda x: np.sqrt( (B[x[0]] - C[x[1]]).dot(B[x[0]] - C[x[1]]) ), A)
%timeit g() # >>> 10 loops, best of 3: 31.8 ms per loop
assert np.abs(f()-g()).max() < 1e-10