Oto moja pierwsza geobramka:
!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))
Miasto 1
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)
i moja druga 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)
chciałbym trzecią ramkę danych z najbliższym miastem od miasta1 do miasta2 o odległości:
City Country Latitude Longitude geometry Nearest Distance
0 Buenos Aires Argentina -34.58 -58.66 POINT (-58.66000 -34.58000) Bogota 111 Km
Oto moje rzeczywiste rozwiązanie wykorzystujące geodjango i dict (ale jest o wiele za długie):
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']
Oto moje próby:
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
tutaj:
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
pozdrowienia
Odpowiedzi:
Po pierwsze, scalam dwie ramki danych poprzez łączenie krzyżowe. A potem znalazłem odległość między dwoma punktami, używając
map
w pythonie. Używammap
, ponieważ przez większość czasu jest o wiele szybciej niżapply
,itertuples
,iterrows
itd. (Reference: https://stackoverflow.com/a/52674448/8205554 )Na koniec grupuję według ramki danych i pobieram minimalne wartości odległości.
Oto biblioteki,
Oto używane funkcje,
I dane,
Połącz krzyżowo z
geopandas
ramkami danych,math
Funkcje igeopandas
,geopy
ageopandas
,Jeśli chcesz użyć
pandas
zamiastgeopandas
,Z
math
funkcjamiz
geopy
,źródło
geopy.distance.distance()
te same 3 Odległości są (w zaokrągleniu)2285
,4629
a4227
km.geopy
, jako strona ufam więcej edwilliams.org/gccalc.htm , co zgadza się z tymgeopy
. Strona internetowa NOAA, nhc.noaa.gov/gccalc.shtml , mówi, że jest oparta na tym pierwszym, ale daje różne wyniki. Prawdopodobnie jest oparty na starej wersji tego pierwszego.Myślę, że dość trudno jest znaleźć rozwiązanie o złożoności czasowej lepszej niż O (m · n) , gdzie m i n są wielkościami
city1
icity2
. Utrzymanie prostego porównania odległości (jedynej operacji O (m · n)) i wykorzystanie wektoryzowanych operacji zapewnianych przez numpy i pandy, prędkość nie powinna stanowić problemu dla żadnego rozsądnego rozmiaru wejściowego.Chodzi o to, że aby porównać odległości na kuli, możesz porównać odległości między punktami w 3D. Najbliższe miasto to także najbliższe miasto przechodzące przez kulę. Ponadto, zwykle obliczasz pierwiastki kwadratowe, aby obliczyć odległości, ale jeśli musisz je tylko porównać, możesz uniknąć pierwiastków kwadratowych.
Zauważ, że każde rozwiązanie wykorzystujące szerokość i długość geograficzną, jakby były współrzędnymi kartezjańskimi, jest błędne, ponieważ zbliżając się do biegunów południki (linie o równej długości geograficznej) zbliżają się do siebie.
źródło
To rozwiązanie prawdopodobnie nie jest najszybszym sposobem rozwiązania problemu, ale wierzę, że to wystarczy.
Jeśli musisz pracować na metrach, a nie stopniach, zawsze możesz ponownie przerzucić warstwę (spowoduje to również usunięcie błędu, który ma na myśli Walter). Możesz to zrobić, gdy
gcity3df = gcity3df.to_crs({'init': 'epsg:XXXX'})
XXXX to kod epsg dla crs używanego w twoim regionie świata.źródło