Aqui está meu primeiro 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))
Cidade1
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)
e meu 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)
eu gostaria do terceiro dataframe com a cidade mais próxima de city1 a city2 com a distância como:
City Country Latitude Longitude geometry Nearest Distance
0 Buenos Aires Argentina -34.58 -58.66 POINT (-58.66000 -34.58000) Bogota 111 Km
Aqui está minha solução atual usando geodjango e dict (mas é muito longo):
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']
Aqui estão minhas tentativas:
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
aqui :
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
Saudações
Respostas:
Em primeiro lugar, mesclo dois quadros de dados por junção cruzada. E então, eu encontrei a distância entre dois pontos usando
map
em python. Eu usomap
, porque na maioria das vezes é muito mais rápido do queapply
,itertuples
,iterrows
etc. (Referência: https://stackoverflow.com/a/52674448/8205554 )Por fim, agrupo por quadro de dados e busco valores mínimos de distância.
Aqui estão bibliotecas,
Aqui estão as funções usadas,
E dados,
Junção cruzada com
geopandas
quadros de dados,math
funções egeopandas
,geopy
egeopandas
,Se você deseja usar em
pandas
vez degeopandas
,Com
math
funções,Com
geopy
,fonte
geopy.distance.distance()
as mesmas distâncias são 3 (arredondada)2285
,4629
e4227
km.geopy
, como site confio em mais edwilliams.org/gccalc.htm , o que concordageopy
. O site da NOAA, nhc.noaa.gov/gccalc.shtml , diz que é baseado no primeiro, mas depois produz resultados diferentes. Provavelmente é baseado em uma versão antiga da primeira.Eu acho que é bastante difícil encontrar uma solução com uma complexidade de tempo melhor que O (m · n) , onde m e n são os tamanhos de
city1
ecity2
. Mantendo a comparação da distância (a única operação O (m · n)) simples e aproveitando as operações vetorizadas fornecidas por numpy e pandas, a velocidade não deve ser um problema para qualquer tamanho de entrada razoável.A ideia é que, para comparar distâncias em uma esfera, você possa comparar as distâncias entre os pontos em 3D. A cidade mais próxima também é a mais próxima passando pela esfera. Além disso, você normalmente usa raízes quadradas para calcular distâncias, mas se precisar compará-las apenas, pode evitar as raízes quadradas.
Observe que qualquer solução que use latitude e longitude como se fossem coordenadas cartesianas está errada, porque, movendo-se para os polos, os meridianos (linhas de igual longitude) se aproximam.
fonte
Essa solução provavelmente não é a maneira mais rápida de resolver seu problema, mas acredito que isso funcionará.
Se você precisar trabalhar em medidores e não em graus, sempre poderá reprojetar sua camada (isso também apagará o erro que Walter está dizendo). Você pode fazer isso
gcity3df = gcity3df.to_crs({'init': 'epsg:XXXX'})
onde XXXX é o código epsg para crs sendo usados em sua região mundial.fonte