Convierta un DataFrame de pandas en un GeoDataFrame

42

Esta parece una pregunta bastante simple, pero no puedo entender cómo convertir un DataFrame de pandas en un GeoDataFrame para una unión espacial.

Aquí hay un ejemplo de cómo se ven mis datos usando 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

De hecho, este marco de datos se creó a partir de un CSV, por lo que si es más fácil leer el CSV directamente como un GeoDataFrame, también está bien.

atkat12
fuente
1
use GeoPandas
gen

Respuestas:

78

Convierta el contenido del DataFrame (p. Ej. LatY Loncolumnas) primero en geometrías Shapely apropiadas y luego úselas junto con el DataFrame original para crear un 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)

Resultado:

    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)

Como las geometrías a menudo vienen en formato WKT, pensé que también incluiría un ejemplo para ese caso:

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
fuente
¡Gracias de nuevo! Eso es mucho más simple y funciona muy rápido, mucho mejor que iterar en cada fila del df en mi n = 500,000 :)
atkat12
66
Gosh, gracias! Compruebo esta respuesta como cada 2 días :)
Owen
1
¡pensaría que esta sería la primera entrada en la documentación!
Dominik
+1 para el shapely.wkt. ¡Me tomó un tiempo resolver esto!
StefanK
14

One-liners! Además de algunos indicadores de rendimiento para personas de big data.

Dado un pandas.DataFrameque tiene x Longitud e Latitud y así:

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

Convirtamos el pandas.DataFramea de la geopandas.GeoDataFramesiguiente manera:

Importaciones de biblioteca y aceleraciones bien proporcionadas :

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

Código + tiempos de referencia en un conjunto de datos de prueba que tengo por ahí:

#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))

El uso pandas.applyes sorprendentemente más lento, pero puede ser mejor para algunos otros flujos de trabajo (por ejemplo, en conjuntos de datos más grandes que usan la biblioteca dask):

Créditos para:

Algunas referencias de Work-In-Progress (a partir de 2017) para manejar grandes daskconjuntos de datos:

weiji14
fuente
Gracias por la comparación, de hecho, la versión zip es mucho más rápida
MCMZL