Расстояние между координатами Python против R время расчета - PullRequest
0 голосов
/ 01 марта 2019

Я пытаюсь вычислить расстояние между одной точкой и многими другими на WGS84 эллипсоид - , а не на приближении haversine , как объяснено в других ответах.Я хотел бы сделать это на Python, но время вычисления очень велико по отношению к R. Мой скрипт на Python ниже занимает почти 23 секунды, в то время как эквивалентный скрипт на R занимает 0,13 секунды.Любое предложение для ускорения моего кода Python?

Python-скрипт:

import numpy as np
import pandas as pd
import xarray as xr
from geopy.distance import geodesic
from timeit import default_timer as timer
df = pd.DataFrame()
city_coord_orig = (4.351749, 50.845701) 
city_coord_orig_r = tuple(reversed(city_coord_orig))
N = 100000
np.random.normal()
df['or'] = [city_coord_orig_r] * N
df['new'] = df.apply(lambda x: (x['or'][0] + np.random.normal(), x['or'][1] + np.random.normal()), axis=1)
start = timer()
df['d2city2'] = df.apply(lambda x: geodesic(x['or'], x['new']).km, axis=1)
end = timer()
print(end - start)

R-скрипт

# clean up
rm(list = ls())
# read libraries
library(geosphere)

city.coord.orig <- c(4.351749, 50.845701)
N<-100000
many <- data.frame(x=rep(city.coord.orig[1], N) + rnorm(N), 
                   y=rep(city.coord.orig[2], N) + rnorm(N))
city.coord.orig <- c(4.351749, 50.845701)
start_time <- Sys.time()
many$d2city <- distGeo(city.coord.orig, many[,c("x","y")]) 
end_time <- Sys.time()
end_time - start_time

1 Ответ

0 голосов
/ 01 марта 2019

Вы используете .apply(), который использует простой цикл для запуска вашей функции для каждой строки.Расчет расстояния полностью выполняется в Python (geopy использует geographiclib, который, кажется, написан только на Python).Не векторизованные вычисления расстояний медленны, вам нужно векторизованное решение с использованием скомпилированного кода, как при вычислении расстояния Хаверсайна .

pyproj предлагает vertorised WSG84вычисления расстояний (методы pyproj.Geod класса принимают массивы numpy) и обертывают библиотеку PROJ4 , что означает, что эти вычисления выполняются в собственном машинном коде:

from pyproj import Geod

# split out coordinates into separate columns
df[['or_lat', 'or_lon']] = pd.DataFrame(df['or'].tolist(), index=df.index)
df[['new_lat', 'new_lon']] = pd.DataFrame(df['new'].tolist(), index=df.index)

wsg84 = Geod(ellps='WGS84')
# numpy matrix of the lon / lat columns, iterable in column order
or_and_new = df[['or_lon', 'or_lat', 'new_lon', 'new_lat']].to_numpy().T
df['d2city2'] = wsg84.inv(*or_and_new)[-1] / 1000  # as km

Это происходит в значительно лучшие времена:

>>> from timeit import Timer
>>> count, total = Timer(
...     "wsg84.inv(*df[['or_lon', 'or_lat', 'new_lon', 'new_lat']].to_numpy().T)[-1] / 1000",
...     'from __main__ import wsg84, df'
... ).autorange()
>>> total / count * 10 ** 3  # milliseconds
66.09873340003105

66 миллисекунд для расчета расстояний в 100 000, неплохо!

Чтобы сделать сравнение, вот ваши geopy / df.apply() версия на той же машине:

>>> count, total = Timer("df.apply(lambda x: geodesic(x['or'], x['new']).km, axis=1)", 'from __main__ import geodesic, df').autorange()
>>> total / count * 10 ** 3  # milliseconds
25844.119450000107

25,8 секунды, даже в том же парке.

...