KDTree для долготы/широты

Существуют ли какие-либо пакеты в Python, которые позволяют выполнять kdtree-подобные операции для долготы/широты на поверхности сферы? (при этом необходимо правильно учитывать сферические расстояния, а также зацикливание по долготе).


person astrofrog    schedule 11.05.2012    source источник


Ответы (2)


Двоичное дерево поиска не может справиться с зацикливанием полярного представления по своей конструкции. Возможно, вам потребуется преобразовать координаты в трехмерное декартово пространство, а затем применить ваш любимый алгоритм поиска, например, kD-Tree, Octree и т. д.

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

person moooeeeep    schedule 15.04.2013
comment
Под обертыванием вы имеете в виду продольно? Если да, можете ли вы объяснить, почему двоичное дерево не может справиться с этим, а трехмерное пространство может? - person pstatix; 26.11.2019
comment
@pstatix ​​Я имел в виду упорядоченные двоичные деревья, такие как kd-tree, которые разбивают набор данных в гиперплоскостях на подпространства. Когда координаты зацикливаются, например, как углы в полярных координатах, это не работает, поскольку соответствующие точки могут быть на обоих концах. По-видимому, существуют бинарные деревья, которые подразделяются на основе вычислений расстояния, а не расщепляются на гиперплоскости, например, по-видимому, шаровое дерево. Так что на самом деле это может быть вариант, о котором я не знал в то время. - person moooeeeep; 27.11.2019

Я считаю, что BallTree от scikit-learn с метрикой Haversine должен помочь вам.

В качестве примера:

from sklearn.neighbors import BallTree
import numpy as np
import pandas as pd

cities = pd.DataFrame(data={
    'name': [...],
    'lat': [...],
    'lon': [...]
})

query_lats = [...]
query_lons = [...]

bt = BallTree(np.deg2rad(cities[['lat', 'lon']].values), metric='haversine')
distances, indices = bt.query(np.deg2rad(np.c_[query_lats, query_lons]))

nearest_cities = cities['name'].iloc[indices]

Обратите внимание, что это возвращает расстояния, предполагающие сферу радиусом 1, чтобы получить расстояния на Земле, умноженные на радиус = 6371 км.

видеть:

person backbord    schedule 16.06.2019
comment
Работает отлично, за исключением одной вещи: обратите внимание, что расстояния, рассчитанные с помощью метрики гаверсинуса, предполагают сферу радиусом 1, поэтому вам нужно умножить на радиус = 6371 км, чтобы получить реальные расстояния. scikit-learn. org/stable/modules/generated/ Я думаю, что общие расчеты/сэкономленное время могут не сильно отличаться между этим и преобразованием в 3D-картезиан в ответе moooeeep, но это должно сэкономить место, поскольку не нужно хранить 3D координаты - person Spcogg the second; 18.06.2019