Эффективный поиск ближайшей пары координат из набора в 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-индекс соседа.
отсюда и:
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),]
)