Вы используете .apply()
, который использует простой цикл для запуска вашей функции для каждой строки. Расчет расстояния полностью выполняется в Python (geopy
использует geographiclib
, который, кажется, написан только на Python). Не векторизованные вычисления расстояний медленны, вам нужно векторизованное решение с использованием скомпилированного кода, как при вычислении расстояния Хаверсайна .
pyproj
предлагает вычисленные по вертикали расчеты расстояний WSG84 (методы класса pyproj.Geod
принимают массивы) и упаковывает библиотеку 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 секунды, даже не в том же поле.
Потому что, глядя на При помощи кода через Reflector Cast не пытается учесть какие-либо неявные операторы приведения (код LINQ Cast сильно оптимизирован для особых случаев всех видов, но ничего в этом направлении) во внимание (как это делают многие языки .NET).
Не вдаваясь в размышления и другие вещи, дженерики не предлагают никакого готового способа принять во внимание такие дополнительные вещи в любом случае.
РЕДАКТИРОВАТЬ: В общем, более сложные средства, такие как неявные / явные, операторы равенства и т. Д. Не являются обычно обрабатываются общими средствами, такими как LINQ.
Спасибо за то, что я собирался использовать именно этот случай где-нибудь. Вы сэкономили мне кучу времени. В качестве возможного решения вашей проблемы вы могли бы вместо этого использовать ConvertAll <>, например так:
foreach (Class1 item in items.ConvertAll<Class1>((i) => (Class1)i))
{
Console.WriteLine(item.Test1);
}
РЕДАКТИРОВАТЬ: или если вы хотите быть более явным, чтобы приведение было неявным, то это тоже работает:
foreach (Class1 item in items.ConvertAll<Class1>(i => i))
{
Console.WriteLine(item.Test1);
}
Решением может быть использование здесь немного linq'инга, если вам действительно нужно такое преобразование:
List items = new List{new Class2{Test2 = 9}}; foreach (Class1 item in (from x in items select (Class1)x)) { Console.WriteLine(item.Test1); }