У меня есть датафрейм с кортежами широты и долготы, как показано ниже (образец фактических координат):

    id    latlon             
67  79    (39.1791764701497, -96.5772313693982)
68  17    (39.1765194942359, -96.5677757455844)
69  76    (39.1751440428827, -96.5772939901891)
70  58    (39.175359525189, -96.5691986655256)
71  50    (39.1770962912298, -96.5668107589661)

Я хочу найти id и расстояние до ближайшего latlon в одном и том же кадре данных (для иллюстрации я просто составляю числа ниже в столбцах nearest_id и nearest_dist ) :

    id    latlon                                  nearest_id  nearest_dist
67  79    (39.1791764701497, -96.5772313693982)   17          37          
68  17    (39.1765194942359, -96.5677757455844)   58          150           
69  76    (39.1751440428827, -96.5772939901891)   50          900          
70  58    (39.175359525189, -96.5691986655256)    17          12          
71  50    (39.1770962912298, -96.5668107589661)   79          4      

У меня есть большое количество (45K +) координат, по которым я хочу выполнить эту операцию.

Вот мое попытанное решение ниже, используя great_circle из geopy.distances:

def great_circle_dist(latlon1, latlon2):
    """Uses geopy to calculate distance between coordinates"""
    return great_circle(latlon1, latlon2).meters

def find_nearest(x):
        """Finds nearest neighbor """
        df['distances'] = df.latlon.apply(great_circle_dist, args=(x,))
        df_sort = df.sort_values(by='distances')
        return (df_sort.values[1][0], df_sort.values[1][2])

df['nearest'] = df['latlon'].apply(find_nearest)
df['nearest_id'] = df.nearest.apply(lambda x: x[0])
df['nearest_dist'] = df.nearest.apply(lambda x: x[1])
del df['nearest']
del df['distances']

Что можно сделать, чтобы этот расчет был эффективным?

0
quantif 29 Авг 2017 в 02:34

3 ответа

Лучший ответ

Пространственная индексация должна помочь.

Вы можете добиться пространственной индексации, используя базу данных (например, Postgres с расширением PostGIS), но у вас также может быть решение в памяти.

Ознакомьтесь с библиотекой Rtree. Вам нужно будет создать индекс, добавить все свои точки в индекс, а затем запросить индекс, используя метод nearest.

1
daphshez 29 Авг 2017 в 15:00

Вы можете сделать это с PostGIS / PostgreSQL эффективно, но тогда вам придется поместить ваши данные в таблицу sql, что может быть сложно. Вы можете выполнять команды postgresql из python, но вам все равно нужно настроить бэкэнд. Надеюсь, кто-то сможет дать вам советы о том, как использовать это только с помощью Python.

1
Bootstrap 28 Авг 2017 в 23:50

В scipy.spatial есть много полезных (и чрезвычайно быстрых) алгоритмов для пространственного поиска. Тот, который кажется правильным инструментом для вашей проблемы, это «cKDTree».

tree = cKDTree(data)

Данные должны представлять собой массив n * 2 (он может вычислять расстояние в n-мерном пространстве, но в этом случае у нас есть два измерения)

Затем вы можете запросить дерево для k ближайших соседей:

dist, idx = tree.query(x, k=1)

Используя индекс, это должно быть тривиально, чтобы получить идентификатор. Я ответил на аналогичный вопрос здесь. Также проверьте комментарии для информации о проекции.

2
Alz 30 Авг 2017 в 00:15