Konwertuj pandas DataFrame na GeoDataFrame

42

To wydaje się dość proste pytanie, ale nie mogę wymyślić, jak przekonwertować pandę DataFrame na GeoDataFrame dla połączenia przestrzennego.

Oto przykład tego, jak wyglądają moje dane przy użyciu df.head():

    Date/Time           Lat       Lon       ID
0   4/1/2014 0:11:00    40.7690   -73.9549  140
1   4/1/2014 0:17:00    40.7267   -74.0345  NaN

W rzeczywistości ta ramka danych została utworzona z pliku CSV, więc jeśli łatwiej jest odczytać plik CSV bezpośrednio jako GeoDataFrame, to też jest w porządku.

atkat12
źródło
1
użyj GeoPandas
gen

Odpowiedzi:

78

Konwersja zawartości w DataFrame (np Lati Lonkolumny) do odpowiednich zgrabna geometrii, a potem używać ich razem z oryginalnym DataFrame stworzyć GeoDataFrame.

from geopandas import GeoDataFrame
from shapely.geometry import Point

geometry = [Point(xy) for xy in zip(df.Lon, df.Lat)]
df = df.drop(['Lon', 'Lat'], axis=1)
crs = {'init': 'epsg:4326'}
gdf = GeoDataFrame(df, crs=crs, geometry=geometry)

Wynik:

    Date/Time           ID      geometry
0   4/1/2014 0:11:00    140     POINT (-73.95489999999999 40.769)
1   4/1/2014 0:17:00    NaN     POINT (-74.03449999999999 40.7267)

Ponieważ geometrie często występują w formacie WKT, pomyślałem, że dołączę również przykład dla tego przypadku:

import geopandas as gpd
import shapely.wkt

geometry = df['wktcolumn'].map(shapely.wkt.loads)
df = df.drop('wktcolumn', axis=1)
crs = {'init': 'epsg:4326'}
gdf = gpd.GeoDataFrame(df, crs=crs, geometry=geometry)
Martin Valgur
źródło
Dzięki jeszcze raz! To o wiele prostsze i działa bardzo szybko - znacznie lepiej niż iteracja przez każdy wiersz df przy moim n = 500 000 :)
atkat12
6
Boże, dzięki! Sprawdzam tę odpowiedź jak co 2 dni :)
Owen,
1
pomyślałbyś, że byłby to pierwszy wpis w dokumentacji!
Dominik
+1 za shapely.wkt. Zajęło mi to trochę czasu, aby to rozgryźć!
StefanK
14

Jednowarstwowe! Plus niektóre wskaźniki wydajności dla osób korzystających z dużych zbiorów danych.

Biorąc pod uwagę, pandas.DataFrameże ma x Longitude i y Latitude tak:

df.head()
x   y
0   229.617902  -73.133816
1   229.611157  -73.141299
2   229.609825  -73.142795
3   229.607159  -73.145782
4   229.605825  -73.147274

Przekształćmy pandas.DataFramew geopandas.GeoDataFramenastępujący sposób:

Import biblioteki i zgrabne przyspieszenia :

import geopandas as gpd
import shapely
shapely.speedups.enable() # enabled by default from version 1.6.0

Kod + czasy testu porównawczego w zestawie danych testowych, które mam:

#Martin's original version:
#%timeit 1.87 s ± 7.03 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
gdf = gpd.GeoDataFrame(df.drop(['x', 'y'], axis=1),
                                crs={'init': 'epsg:4326'},
                                geometry=[shapely.geometry.Point(xy) for xy in zip(df.x, df.y)])



#Pandas apply method
#%timeit 8.59 s ± 60.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
gdf = gpd.GeoDataFrame(df.drop(['x', 'y'], axis=1),
                       crs={'init': 'epsg:4326'},
                       geometry=df.apply(lambda row: shapely.geometry.Point((row.x, row.y)), axis=1))

Korzystanie pandas.applyjest zaskakująco wolniejsze, ale może lepiej pasować do niektórych innych przepływów pracy (np. W większych zestawach danych przy użyciu biblioteki dask):

Kredyty dla:

Niektóre odniesienia do pracy w toku (od 2017 r.) Do obsługi dużych daskzestawów danych:

weiji14
źródło
Dzięki za porównanie, rzeczywiście wersja zip jest znacznie szybsza
MCMZL