Вы используете .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 секунды, даже в том же парке.