以更pythonic的方式找到最近的邻居

Find nearest neighbour in a more pythonic way

A是一个点,P是点的列表。 我想找到哪个点 P[i] 最接近 A,即我想找到 P[i_0] 与:

i_0 = argmin_i || A - P[i]||^2

我是这样做的:

import numpy as np

# P is a list of 4 points
P = [np.array([-1, 0, 7, 3]), np.array([5, -2, 8, 1]), np.array([0, 2, -3, 4]), np.array([-9, 11, 3, 4])]
A = np.array([1, 2, 3, 4])
distance = 1000000000     # better would be : +infinity
closest = None

for p in P:
  delta = sum((p - A)**2)
  if delta < distance:
    distance = delta
    closest = p

print closest    # the closest point to A among all the points in P

它可以工作,但是如何以 shorter/more Pythonic 方式做到这一点?

在 Python 中更普遍(甚至不使用 Numpy),如何找到 k_0 使得 D[k_0] = min D[k]?k_0 = argmin_k D[k]

实现您正在使用的相同算法的更 Pythonic 方法是用 key 函数调用 min 来替换循环:

closest = min(P, key=lambda p: sum((p - A)**2))

请注意,我使用 ** 求幂(^ 是 Python 中的二元异或运算符)。

使用内置 min 是这样的:

import math
p1 = [1,2]
plst = [[1,3], [10,10], [5,5]]
res = min(plst, key=lambda x: math.sqrt(pow(p1[0]-x[0], 2) + pow(p1[1]-x[1], 2)))
print res
[1, 3]

请注意,我只是使用普通 python 列表。

单行的 NumPy 版本:

clostest = P[np.argmin(np.apply_along_axis(lambda p: np.sum((p - A) **2), 1, P))]

numpy 中的完全矢量化方法。类似于@MikeMüller 之一,但使用 numpy's broadcasting 来避免 lambda 函数。

使用示例数据:

>>> P = [np.array([-1, 0, 7, 3]), np.array([5, -2, 8, 1]), np.array([0, 2, -3, 4]), np.array([-9, 11, 3, 4])]
>>> A = np.array([1, 2, 3, 4])

并制作 P 二维 numpy 数组:

>>> P = np.asarray(P)
>>> P
array([[-1,  0,  7,  3],
       [ 5, -2,  8,  1],
       [ 0,  2, -3,  4],
       [-9, 11,  3,  4]])

可以用numpy一行计算:

>>> P[np.argmin(np.sum((P - A)**2, axis=1))]

请注意 P - AP.shape = (N, 4)A.shape = (4,) 会将减法广播到 P 的所有行(Pi = Pi - A)。

对于小 NP 中的行数),pythonic 方法可能更快。对于 N 的大值,这应该明显更快。