2015-12-06 4 views
1

A - точка, а P - список точек. Я хочу, чтобы выяснить, какие точки Р [я] является наиболее близким к А, то есть я хочу найти P[i_0] с:Найти ближайшего соседа по более pythonic пути

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 

Он работает, но как это сделать короче/более путинским?

В целом в Python (и даже без использования Numpy) как найти k_0 такие, что D[k_0] = min D[k]? т.е. k_0 = argmin_k D[k]

+0

У вас есть SciPy? [Структура данных, специально разработанная для поиска ближайшего соседа, вероятно, будет работать лучше, чем любое решение на основе массивов.] (Http://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.spatial. cKDTree.html) – user2357112

+0

@ user2357112 Я знаю, что многие модули реализуют поиск ближайших соседей, но для этого примера я хотел бы сам его закодировать (без оптимизации производительности, но только с более коротким кодом). Мой вопрос заключается в том, как правильно реализовать «argmin» в Python. – Basj

+0

Подробнее Pythonic! = Более короткий код. – user2357112

ответ

2

Более Pythonic способ реализации того же алгоритма, который вы используете, чтобы заменить петлю с вызовом min с key функции:

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

Следует заметить, что я использую для ** exponentiation (^ - это оператор binary-xor в Python).

+0

Отлично! Я не знал этот шаблон min/key! – Basj

+0

вы можете увидеть свой код в действии здесь: [Простой (рабочий) рукописный распознавание цифр] (http://stackoverflow.com/questions/34116526/simple-working-handwritten-digit-recognition-how-to-improve-it) ! – Basj

0

Использование встроенного 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] 

Обратите внимание, что я использовал только простые списки питона.

+1

Квадратный корень не нужен, так как точка с наименьшим расстоянием также будет точкой с наименьшим квадратом расстояния. – Blckknght

1

версия NumPy в однострочнике:

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

Вы вычисляете немного другое значение (наименьшая сумма, квадрат, а не сумма * квадратов). Биты numpy, вероятно, полезны. – Blckknght

+0

@Blckknght Ups, отсутствует пара скобок. Исправлена. Спасибо за подсказку. –

+0

Я сравнил ваше решение и решение [@ imaluengo] (http://stackoverflow.com/a/34122191/1422096) с P, содержащим 5000 векторов размера 10. Когда вы выполняете 1000 различных поисков ближайшего соседа, я беру ~ 60 секунд с этот метод и ~ 0,6 сек с помощью метода @ imaluengo. Было бы интересно узнать, почему «np.apply_along_axis» имеет такой эффект. – Basj

1

Полностью Векторизованный подход в NumPy. Как и у @ MikeMüller, но используя numpy's broadcasting, чтобы избежать лямбда-функций.

С примерных данными:

>>> 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 2D-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 - A, с P.shape = (N, 4) и A.shape = (4,) будет загружать субстрат во все строки P (Pi = Pi - A).

Для небольших N (количество строк в P), питонический подход, вероятно, быстрее. При больших значениях N это должно быть значительно быстрее.

+0

Очень быстрый способ! См. Комментарий к [этот ответ] (http://stackoverflow.com/a/34116234/1422096). – Basj

 Смежные вопросы

  • Нет связанных вопросов^_^