Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Найти ближайшую точку в другом фрейме данных (С МНОГО ДАННЫХ)

Автор вопроса: Arnaud HОтветов: 1

Проблема проста, у меня два DataFrame:

  • один с 90 000 квартир и их широта / долгота

  • и один с 3000 аптек и их широта / долгота

И я хочу создать новую переменную для всех своих квартир: "расстояние до ближайшей аптеки".

Для этого я попробовал два метода, которые тратят много времени:

Первый метод: я создал матрицу с моими квартирами в ряду и моими аптеками в столбцах и расстоянием между ними на пересечении, после чего я просто беру минимальное значение матрицы, чтобы получить вектор-столбец 90 000 значение

Я просто использую двойной для с numpy:

m,n=len(result['latitude']),len(pharma['lat'])
M = np.ones((m,n))
for i in range(m):
     for j in range(n):
        if (result['Code departement'][i]==pharma['departement'][j]):
            M[i,j] =(pharma['lat'][j]-result['latitude'][i])**2+(pharma['lng'][j]-result['longitude'] [i])**2

ps: я знаю, что неправильная формула для широты / долготы, но апартаменты находятся в одном регионе, так что это хорошее приближение

Второй способ: я использую решение из этих тем (у кого такая же проблема, но с меньшим объемом данных) https://gis.stackexchange.com/questions/222315/geopandas-find-nearest-point-in-other-dataframe

Я использовал геопанды и ближайший метод:

from shapely.ops import nearest_points
pts3 = pharma.geometry.unary_union


def near(point, pts=pts3):
     nearest = pharma.geometry == nearest_points(point, pts)[1]
     return pharma[nearest].geometry.get_values()[0]

appart['Nearest'] = appart.apply(lambda row: near(row.geometry), axis=1)

И, как я уже сказал, оба метода тратят слишком много времени, после 1 часа работы мой компьютер / ноутбук вышел из строя и вышел из строя.

Мой последний вопрос: есть ли у вас оптимизированный способ ускорить работу? возможно ? Если он уже оптимизирован, я куплю другой компьютер, но по каким критериям, но по каким критериям искать, чтобы компьютер мог выполнять такие быстрые вычисления?

  • Я думаю, вам следует следовать второму ответу на вопрос, на который вы нас указываете, то есть тот, который использует пространственный индекс, чтобы избежать вычисления расстояний по принципу "все: все". High Performance Mark 16.11.2019
  • У тебя есть пример? Потому что у меня сложилось впечатление, что я уже использую пространственный индекс во втором решении с геопандами, и это ничего не изменило за потраченное время. Arnaud H 17.11.2019
  • Тогда я неправильно понял ваш код, и мой предыдущий комментарий был ошибочным. High Performance Mark 17.11.2019
  • Чтобы уточнить, второй вариант, основанный на shapely, не использует пространственный индекс. martinfleis 17.11.2019
  • Нет, конечно, я не понимаю, что такое пространственный индекс. У тебя есть один пример? одна ссылка? Arnaud H 17.11.2019
  • Вы можете начать здесь geoffboeing.com/2016/10/r-tree -spatial-index-python, но имейте в виду, что это для пересечения. Я реализовал аналогичные вещи здесь docs.momepy.org/en/ стабильный / _modules / momepy /. Надеюсь, это поможет. martinfleis 17.11.2019

pythonpandasoptimizationgeopandasnearest-neighbor

Ответы

Ответ 1 · рейтинг 10 · mgc

Думаю, Ball Tree является подходящей структурой для этой задачи.

Вы можете использовать реализацию scikit-learn, см. код ниже для примера, адаптированного к вашему случаю:

import numpy as np
import geopandas as gpd
from shapely.geometry import Point
from sklearn.neighbors import BallTree

## Create the two GeoDataFrame to replicate your dataset
appart = gpd.GeoDataFrame({
        'geometry': Point(a, b),
        'x': a,
        'y': b,
    } for a, b in zip(np.random.rand(100000), np.random.rand(100000))
])

pharma = gpd.GeoDataFrame([{
        'geometry': Point(a, b),
        'x': a,
        'y': b,
    } for a, b in zip(np.random.rand(3000), np.random.rand(3000))
])

# Create a BallTree
tree = BallTree(pharma[['x', 'y']].values, leaf_size=2)

# Query the BallTree on each feature from 'appart' to find the distance
# to the nearest 'pharma' and its id
appart['distance_nearest'], appart['id_nearest'] = tree.query(
    appart[['x', 'y']].values, # The input array for the query
    k=1, # The number of nearest neighbors
)

С помощью этого метода вы можете решить свою проблему довольно быстро (в приведенном выше примере на моем компьютере потребовалось менее секунды, чтобы найти индекс ближайшей точки из 3000 точек во входном наборе данных из 100000 точек).

По умолчанию query метод BallTree возвращает расстояние до ближайшего соседа и его идентификатор. Если вы хотите, вы можете отключить возврат расстояния до этого ближайшего соседа, установив для параметра return_distance значение False. Если вас действительно волнует только расстояние, вы можете сохранить только это значение:

appart['distance_nearest'], _ = tree.query(appart[['x', 'y']].values, k=1)

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы