Вот мой первый геодатфрейм:
!pip install geopandas
import pandas as pd
import geopandas
city1 = [{'City':"Buenos Aires","Country":"Argentina","Latitude":-34.58,"Longitude":-58.66},
{'City':"Brasilia","Country":"Brazil","Latitude":-15.78 ,"Longitude":-70.66},
{'City':"Santiago","Country":"Chile ","Latitude":-33.45 ,"Longitude":-70.66 }]
city2 = [{'City':"Bogota","Country":"Colombia ","Latitude":4.60 ,"Longitude":-74.08},
{'City':"Caracas","Country":"Venezuela","Latitude":10.48 ,"Longitude":-66.86}]
city1df = pd.DataFrame(city1)
city2df = pd.DataFrame(city2)
gcity1df = geopandas.GeoDataFrame(
city1df, geometry=geopandas.points_from_xy(city1df.Longitude, city1df.Latitude))
gcity2df = geopandas.GeoDataFrame(
city2df, geometry=geopandas.points_from_xy(city2df.Longitude, city2df.Latitude))
City1
City Country Latitude Longitude geometry
0 Buenos Aires Argentina -34.58 -58.66 POINT (-58.66000 -34.58000)
1 Brasilia Brazil -15.78 -47.91 POINT (-47.91000 -15.78000)
2 Santiago Chile -33.45 -70.66 POINT (-70.66000 -33.45000)
и мой второй геодатафрейм: City2:
City Country Latitude Longitude geometry
1 Bogota Colombia 4.60 -74.08 POINT (-74.08000 4.60000)
2 Caracas Venezuela 10.48 -66.86 POINT (-66.86000 10.48000)
я хотел бы третий датафрейм с ближайшим городом от города1 до города2 с расстоянием, как:
City Country Latitude Longitude geometry Nearest Distance
0 Buenos Aires Argentina -34.58 -58.66 POINT (-58.66000 -34.58000) Bogota 111 Km
Вот мое реальное решение с использованием geodjango и dict (но это слишком долго):
from django.contrib.gis.geos import GEOSGeometry
result = []
dict_result = {}
for city01 in city1 :
dist = 99999999
pnt = GEOSGeometry('SRID=4326;POINT( '+str(city01["Latitude"])+' '+str(city01['Longitude'])+')')
for city02 in city2:
pnt2 = GEOSGeometry('SRID=4326;POINT('+str(city02['Latitude'])+' '+str(city02['Longitude'])+')')
distance_test = pnt.distance(pnt2) * 100
if distance_test < dist :
dist = distance_test
result.append(dist)
dict_result[city01['City']] = city02['City']
Вот мои попытки:
from shapely.ops import nearest_points
# unary union of the gpd2 geomtries
pts3 = gcity2df.geometry.unary_union
def Euclidean_Dist(df1, df2, cols=['x_coord','y_coord']):
return np.linalg.norm(df1[cols].values - df2[cols].values,
axis=1)
def near(point, pts=pts3):
# find the nearest point and return the corresponding Place value
nearest = gcity2df.geometry == nearest_points(point, pts)[1]
return gcity2df[nearest].City
gcity1df['Nearest'] = gcity1df.apply(lambda row: near(row.geometry), axis=1)
gcity1df
Вот :
City Country Latitude Longitude geometry Nearest
0 Buenos Aires Argentina -34.58 -58.66 POINT (-58.66000 -34.58000) Bogota
1 Brasilia Brazil -15.78 -70.66 POINT (-70.66000 -15.78000) Bogota
2 Santiago Chile -33.45 -70.66 POINT (-70.66000 -33.45000) Bogota
С уважением
Ответы:
Во-первых, я объединяю два фрейма данных путем перекрестного соединения. И тогда я нашел расстояние между двумя точками
map
в Python. Я используюmap
, потому что в большинстве случаев это намного быстрее, чемapply
,itertuples
иiterrows
т. Д. (Ссылка: https://stackoverflow.com/a/52674448/8205554 )Наконец, я группирую по фрейму данных и выбираю минимальные значения расстояния.
Вот библиотеки,
Здесь используются функции,
И данные,
Перекрестное соединение с
geopandas
фреймами данных,math
функции иgeopandas
,geopy
иgeopandas
,Если вы хотите использовать
pandas
вместоgeopandas
,С
math
функциями,С
geopy
,источник
geopy.distance.distance()
те же 3 расстояния (округленно)2285
,4629
и4227
км.geopy
, как веб-сайт, я доверяю больше edwilliams.org/gccalc.htm , с чем согласенgeopy
. Сайт NOAA, nhc.noaa.gov/gccalc.shtml , говорит, что он основан на первом, но затем дает другие результаты. Это вероятно основано на старой версии прежнего.Я думаю, что довольно сложно найти решение с временной сложностью лучше, чем O (m · n) , где m и n - размеры
city1
иcity2
. Благодаря простоте сравнения расстояний (единственная операция O (m · n)) и использованию векторизованных операций, предоставляемых numpy и pandas, скорость не должна быть проблемой для любого разумного размера ввода.Идея состоит в том, что для сравнения расстояний на сфере вы можете сравнить расстояния между точками в 3D. Самый близкий город - также самый близкий, проходящий через сферу. Кроме того, вы обычно берете квадратные корни для вычисления расстояний, но если вам нужно только сравнить их, вы можете избежать квадратных корней.
Обратите внимание, что любое решение, которое использует широту и долготу, как если бы они были декартовыми координатами, является неправильным, потому что, двигаясь к полюсам, меридианы (линии равной долготы) становятся ближе друг к другу.
источник
Возможно, это решение не самый быстрый способ решить вашу проблему, но я верю, что оно поможет.
Если вам нужно работать в метрах, а не в градусах, вы всегда можете перепроектировать свой слой (это также устранит ошибку, которую Уолтер имеет в виду). Вы можете сделать это,
gcity3df = gcity3df.to_crs({'init': 'epsg:XXXX'})
если XXXX - это код epsg для crs, который используется в вашем регионе мира.источник