Эффективный поиск ближайшей пары координат из набора в Python

Проблема

представьте, что я стою в аэропорту. Учитывая географическую координатную пару, как можно эффективно определить, в каком аэропорту я стоял?

входы

  • координатная пара (x,y) представление местоположения, в котором я стоял.
  • набор пар координат [(a1,b1), (a2,b2)...] где каждая координатная пара представляет один аэропорт.

нужные Вывод

координатная пара (a,b) из множества пар координат аэропорта, представляющих ближайший аэропорт к точке (x,y).

Неэффективное Решение

вот моя неэффективная попытка решить эту проблему. Она четко линейна по длине набора аэропортов.

shortest_distance = None
shortest_distance_coordinates = None

point = (50.776435, -0.146834)

for airport in airports:
    distance = compute_distance(point, airport)
    if distance < shortest_distance or shortest_distance is None:
        shortest_distance = distance
        shortest_distance_coordinates = airport

Вопрос

как можно улучшить это решение? Это может включать в себя некоторый способ предварительной фильтрации список аэропортов, основанный на координатах местоположения, в котором мы сейчас находимся, или сортировка их в определенном порядке заранее.

3 ответов


Если ваши координаты несортированы, ваш поиск может быть улучшен только немного, предполагая, что это (latitude,longitude) фильтруя по широте сначала как для Земли

1 градус широты на сфере составляет 111,2 км или 69 км

но это не даст огромное ускорение.

Если вы сначала сортируете аэропорты по широте, вы можете использовать двоичный поиск для поиска первого аэропорта, который мог бы матч (airport_lat >= point_lat-tolerance), а затем только сравнить до последнего, что мог бы матч (airport_lat <= point_lat+tolerance) - но позаботьтесь о 0 градусах, равных 360. Хотя вы не можете использовать эту библиотеку напрямую, источники bisect являются хорошим началом для реализации двоичного поиска.

хотя технически таким образом поиск по-прежнему O(n), у вас гораздо меньше фактических вычислений расстояния (в зависимости от допуска) и несколько сравнений широты. Таким образом, у вас будет огромное ускорение.


>>> from scipy import spatial
>>> airports = [(10,10),(20,20),(30,30),(40,40)]
>>> tree = spatial.KDTree(airports)
>>> tree.query([(21,21)])
(array([ 1.41421356]), array([1]))

где 1.41421356-расстояние между запрашиваемой точкой и ближайшим соседом, а 1-индекс соседа.

см.: http://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.KDTree.query.html#scipy.spatial.KDTree.query


отсюда и:

import numpy as np
def closest_node(node, nodes):
    nodes = np.asarray(nodes)
    deltas = nodes - node
    dist_2 = np.einsum('ij,ij->i', deltas, deltas)
    return np.argmin(dist_2)

здесь node - кортеж с двумя значениями (x, y) и nodes представляет собой массив кортежей с двумя значениями ([(x_1, y_1), (x_2, y_2),])