在Python中找到矢量差异规范的最快方法

时间:2017-03-15 23:39:34

标签: python arrays list vector

我有一个对列表(比如' 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 中以最快的方式获得上述功能?

2 个答案:

答案 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