Aquí está mi primer geodatframe:
!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))
Ciudad1
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)
y mi segundo geodataframe: 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)
Me gustaría un tercer marco de datos con la ciudad más cercana de city1 a city2 con una distancia como:
City Country Latitude Longitude geometry Nearest Distance
0 Buenos Aires Argentina -34.58 -58.66 POINT (-58.66000 -34.58000) Bogota 111 Km
Aquí está mi solución real usando geodjango y dict (pero es demasiado largo):
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']
Aquí están mis intentos:
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
aquí :
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
Saludos
Respuestas:
En primer lugar, fusiono dos marcos de datos por combinación cruzada. Y luego, encontré la distancia entre dos puntos usando
map
Python. Yo usomap
, porque la mayoría de las veces es mucho más rápido queapply
,itertuples
,iterrows
etc. (Referencia: https://stackoverflow.com/a/52674448/8205554 )Por último, agrupo por marco de datos y obtengo valores mínimos de distancia.
Aquí hay bibliotecas,
Aquí están las funciones utilizadas,
Y datos,
Unión cruzada con
geopandas
marcos de datos,math
funciones ygeopandas
,geopy
ygeopandas
,Si quieres usar en
pandas
lugar degeopandas
,Con
math
funciones,con
geopy
,fuente
geopy.distance.distance()
las mismas 3 distancias son (redondeadas)2285
,4629
y4227
km.geopy
, como sitio web confío más en edwilliams.org/gccalc.htm , lo cual concuerdageopy
. El sitio web de la NOAA, nhc.noaa.gov/gccalc.shtml , dice que se basa en el primero, pero luego arroja resultados diferentes. Probablemente se basa en una versión anterior de la anterior.Creo que es bastante difícil encontrar una solución con una complejidad temporal mejor que O (m · n) , donde myn son los tamaños de
city1
ycity2
. Manteniendo la comparación de distancia (la única operación O (m · n)) simple, y aprovechando las operaciones vectorizadas proporcionadas por numpy y pandas, la velocidad no debería ser un problema para ningún tamaño de entrada razonable.La idea es que, para comparar distancias en una esfera, puede comparar las distancias entre los puntos en 3D. La ciudad más cercana es también la más cercana que pasa por la esfera. Además, normalmente toma raíces cuadradas para calcular distancias, pero si solo necesita compararlas, puede evitar las raíces cuadradas.
Tenga en cuenta que cualquier solución que use la latitud y la longitud como si fueran coordenadas cartesianas es incorrecta, porque al moverse hacia los polos los meridianos (líneas de igual longitud) se acercan entre sí.
fuente
Esta solución probablemente no sea la forma más rápida de resolver su problema, pero creo que funcionará.
Si necesita trabajar en metros y no en grados, siempre puede volver a proyectar su capa (también borrará el error que Walter quiere decir). Puede hacerlo
gcity3df = gcity3df.to_crs({'init': 'epsg:XXXX'})
donde XXXX es el código epsg para los crs que se utilizan en su región mundial.fuente