Análisis de Datos Geográficos y Geoespaciales con Pandas: ¡Dando Vida a tus Mapas! 🗺️
Descubre cómo Pandas, combinado con bibliotecas geoespaciales como Geopandas y Shapely, puede transformar la forma en que trabajas con datos basados en ubicación. Este tutorial te guiará a través de la carga, manipulación y visualización de información geográfica, abriendo un mundo de posibilidades para tus proyectos de ciencia de datos.
El análisis de datos geográficos, o geoespaciales, es una rama fascinante de la ciencia de datos que nos permite entender patrones, tendencias y relaciones en el mundo físico. Desde la distribución de tiendas hasta la planificación urbana o el seguimiento de fenómenos ambientales, la información geográfica es omnipresente y crucial. En este tutorial, exploraremos cómo la poderosa biblioteca Pandas, junto con sus extensiones geoespaciales, puede ser tu mejor aliada para desentrañar los secretos ocultos en tus datos basados en ubicación.
Aunque Pandas es excelente para datos tabulares, carece de capacidades nativas para tipos de datos geográficos como puntos, líneas o polígonos. Aquí es donde entran en juego librerías especializadas como Geopandas y Shapely, que extienden la funcionalidad de Pandas para manejar estos objetos geométricos de manera eficiente.
🚀 ¿Por qué es Importante el Análisis Geoespacial?
El análisis geoespacial nos permite responder preguntas como:
- ¿Dónde están concentrados mis clientes?
- ¿Cuál es la ruta más eficiente entre dos puntos?
- ¿Cómo se distribuyen los fenómenos naturales en una región?
- ¿Qué áreas están cubiertas por un servicio o infraestructura?
Entender la dimensión espacial de tus datos puede ofrecer insights que los análisis tabulares tradicionales simplemente no pueden revelar.
🛠️ Preparación del Entorno: Instalación de Librerías
Antes de empezar, necesitamos instalar las librerías esenciales. Geopandas tiene algunas dependencias, por lo que la forma más sencilla es usar conda o pip con los paquetes precompilados.
Instalación con Conda
conda install geopandas
Instalación con Pip
Si usas pip, puede que necesites instalar fiona, pyproj, rtree, shapely y gdal por separado, o usar una instalación que ya los incluya.
pip install geopandas
pip install matplotlib # Para visualización
Una vez instaladas, podemos importarlas:
import pandas as pd
import geopandas as gpd
from shapely.geometry import Point, LineString, Polygon
import matplotlib.pyplot as plt
🌎 Fundamentos de Datos Geoespaciales
Antes de sumergirnos en el código, es crucial entender algunos conceptos básicos:
- Geometría: Representa una característica geográfica. Los tipos comunes son
Point(un solo lugar),LineString(una secuencia de puntos conectados, como una carretera) yPolygon(un área cerrada, como un país o un lago). - Sistema de Coordenadas de Referencia (CRS - Coordinate Reference System): Define cómo se relacionan las coordenadas con ubicaciones reales en la Tierra. Es fundamental para asegurar que tus datos geográficos estén alineados correctamente. Los más comunes son
EPSG:4326(WGS 84, latitud/longitud) yEPSG:3857(Web Mercator, usado por muchos mapas web). - GeoDataFrame: Es la estructura de datos central de Geopandas. Es una extensión de
pandas.DataFrameque incluye una columna especial para objetos geométricos y un CRS.
📊 Creando tu Primer GeoDataFrame
Podemos crear un GeoDataFrame desde cero o cargarlo desde archivos geoespaciales. Primero, veamos cómo crear uno manualmente.
# Datos de ejemplo: Ciudades
data = {
'ciudad': ['Nueva York', 'Los Ángeles', 'Chicago', 'Houston', 'Phoenix'],
'pais': ['USA', 'USA', 'USA', 'USA', 'USA'],
'latitud': [40.7128, 34.0522, 41.8781, 29.7604, 33.4484],
'longitud': [-74.0060, -118.2437, -87.6298, -95.3698, -112.0740]
}
df = pd.DataFrame(data)
print("DataFrame original:")
print(df.head())
# Crear objetos de geometría (Puntos)
geometry = [Point(xy) for xy in zip(df['longitud'], df['latitud'])]
# Crear el GeoDataFrame
gdf = gpd.GeoDataFrame(df, geometry=geometry, crs="EPSG:4326")
print("\nGeoDataFrame creado:")
print(gdf.head())
print(gdf.crs)
En este ejemplo, tomamos las columnas latitud y longitud para crear objetos Point de Shapely. Luego, los asignamos a la columna geometry del GeoDataFrame y especificamos el CRS EPSG:4326 (WGS 84, el estándar para latitud/longitud).
📂 Cargando Datos Geoespaciales de Archivos
Geopandas puede leer una amplia variedad de formatos geoespaciales, como Shapefile (.shp), GeoJSON (.geojson), KML (.kml), y muchos más, gracias a su dependencia de fiona (que a su vez usa GDAL/OGR).
Para este ejemplo, usaremos un dataset de ejemplo de Geopandas que contiene los países del mundo. Si tuvieras un archivo local, el proceso sería similar.
# Cargar un archivo Shapefile (ejemplo con un dataset incorporado de geopandas)
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
print("\nGeoDataFrame de países:")
print(world.head())
print(world.crs)
print(world.geometry.head())
🗺️ Visualización Básica de Datos Geoespaciales
Una de las mayores ventajas de Geopandas es su capacidad para visualizar datos geoespaciales de manera sencilla, utilizando Matplotlib por debajo.
Visualizando Puntos
Continuando con nuestro GeoDataFrame de ciudades:
# Visualizar las ciudades
fig, ax = plt.subplots(1, 1, figsize=(10, 8))
gdf.plot(ax=ax, marker='o', color='red', markersize=50)
ax.set_title('Ciudades de EE. UU.')
ax.set_xlabel('Longitud')
ax.set_ylabel('Latitud')
plt.show()
Visualizando Polígonos (Países)
# Visualizar los países
fig, ax = plt.subplots(1, 1, figsize=(12, 8))
world.plot(ax=ax, color='lightgray', edgecolor='black')
ax.set_title('Mapa Mundial')
plt.show()
Visualización Avanzada: Temática y Combinada
Podemos usar columnas de datos para colorear los polígonos, creando mapas temáticos, o combinar diferentes GeoDataFrames.
# Visualizar países por población (usando una columna numérica para el color)
# Excluir Antártida para una mejor visualización
world_no_antarctica = world[(world['name'] != "Antarctica") & (world['pop_est'] > 0)]
fig, ax = plt.subplots(1, 1, figsize=(15, 10))
world_no_antarctica.plot(
column='pop_est',
cmap='viridis',
linewidth=0.8,
ax=ax,
edgecolor='0.8',
legend=True,
legend_kwds={'label': "Población Estimada", 'orientation': "horizontal"}
)
ax.set_title('Población Mundial por País')
ax.set_axis_off() # Eliminar ejes
plt.show()
# Combinar la visualización de países con las ciudades
fig, ax = plt.subplots(1, 1, figsize=(15, 10))
world.plot(ax=ax, color='lightgray', edgecolor='black')
gdf.plot(ax=ax, marker='o', color='red', markersize=50, label='Ciudades')
ax.set_title('Ciudades y Países del Mundo')
ax.set_xlabel('Longitud')
ax.set_ylabel('Latitud')
ax.legend()
plt.show()
🗺️ Proyecciones y Sistemas de Coordenadas (CRS)
La elección del CRS es fundamental. EPSG:4326 es ideal para almacenar datos de latitud/longitud, pero para realizar mediciones de distancia o área precisas, a menudo es mejor proyectar los datos a un CRS proyectado (que usa unidades lineales como metros).
Transformación de CRS
# Transformar el GeoDataFrame de ciudades a Web Mercator (EPSG:3857)
# que es útil para mapas web y cálculos de distancia en metros a escalas locales
cities_web_mercator = gdf.to_crs(epsg=3857)
print("\nCRS original de ciudades:", gdf.crs)
print("CRS de ciudades transformadas:", cities_web_mercator.crs)
print("Geometría de ciudades transformadas (primeras 2):")
print(cities_web_mercator.geometry.head(2))
# Comparar las coordenadas:
print("\nCoordenadas originales (lat/lon):")
print(gdf.geometry.iloc[0])
print("Coordenadas proyectadas (metros):")
print(cities_web_mercator.geometry.iloc[0])
Al transformar, las coordenadas cambian de latitud/longitud a valores X/Y en metros. Esto es crucial para operaciones espaciales.
📏 Operaciones Geoespaciales Básicas con Shapely y Geopandas
Una vez que tienes tus datos en un GeoDataFrame, puedes realizar un sinfín de operaciones espaciales. Shapely proporciona las herramientas para trabajar con geometrías individuales, y Geopandas las aplica a GeoDataFrames completos.
Calculando Áreas y Distancias
# Calcular el área de los países (en grados cuadrados si el CRS es 4326)
# Para áreas precisas, primero proyectar a un CRS adecuado (ej. EPSG:3035 para Europa, o un CRS local)
world_projected = world.to_crs(epsg=3395) # World Mercator para cálculo de área global
world_projected['area_sq_km'] = world_projected.geometry.area / 10**6 # Convertir a km²
print("\nÁrea de los primeros 5 países (km²):")
print(world_projected[['name', 'area_sq_km']].head())
# Calcular la distancia entre dos ciudades (en el CRS proyectado)
# Usaremos las ciudades ya proyectadas a Web Mercator
ny = cities_web_mercator[cities_web_mercator['ciudad'] == 'Nueva York'].geometry.iloc[0]
la = cities_web_mercator[cities_web_mercator['ciudad'] == 'Los Ángeles'].geometry.iloc[0]
distance_meters = ny.distance(la)
print(f"\nDistancia entre Nueva York y Los Ángeles: {distance_meters / 1000:.2f} km")
Buffers (Zonas de Influencia)
Un buffer crea un polígono alrededor de una geometría a una cierta distancia. Esto es útil para análisis de alcance o proximidad.
# Crear un buffer de 100 km alrededor de Nueva York
# Asegurémonos de que el CRS esté en metros para el buffer
ny_projected = gdf[gdf['ciudad'] == 'Nueva York'].to_crs(epsg=3857).geometry.iloc[0]
ny_buffer = ny_projected.buffer(100 * 1000) # 100 km en metros
# Visualizar el buffer
fig, ax = plt.subplots(1, 1, figsize=(10, 10))
cities_web_mercator.plot(ax=ax, color='blue', markersize=30, label='Ciudades')
gpd.GeoSeries([ny_buffer], crs=epsg=3857).plot(ax=ax, color='green', alpha=0.5, label='Buffer NY (100km)')
ax.set_title('Buffer de 100 km alrededor de Nueva York')
ax.set_xlabel('Coordenada X (metros)')
ax.set_ylabel('Coordenada Y (metros)')
ax.legend()
plt.show()
Uniones Espaciales (sjoin)
gpd.sjoin es el equivalente espacial de pd.merge. Permite unir dos GeoDataFrames basándose en su relación espacial (por ejemplo, qué puntos están dentro de qué polígonos).
Vamos a crear un GeoDataFrame de puntos aleatorios en EE. UU. y ver a qué país pertenecen.
# Generar puntos aleatorios para demostrar sjoin
import numpy as np
# Coordenadas aproximadas de EE. UU. (para generar puntos dentro)
min_lon, max_lon = -125, -65
min_lat, max_lat = 25, 50
num_points = 100
random_lons = np.random.uniform(min_lon, max_lon, num_points)
random_lats = np.random.uniform(min_lat, max_lat, num_points)
random_points_geom = [Point(xy) for xy in zip(random_lons, random_lats)]
random_points_gdf = gpd.GeoDataFrame(geometry=random_points_geom, crs="EPSG:4326")
# Seleccionar solo los polígonos de USA del GeoDataFrame 'world'
usa_polygon = world[world['name'] == 'United States of America']
# Realizar un sjoin: 'within' significa qué puntos están DENTRO de los polígonos de USA
points_in_usa = gpd.sjoin(random_points_gdf, usa_polygon, predicate='within', how='inner')
print("\nPuntos aleatorios dentro de USA (primeros 5):")
print(points_in_usa.head())
# Visualizar los puntos dentro de USA
fig, ax = plt.subplots(1, 1, figsize=(12, 10))
usa_polygon.plot(ax=ax, color='lightblue', edgecolor='blue', label='USA')
points_in_usa.plot(ax=ax, marker='o', color='red', markersize=20, label='Puntos en USA')
ax.set_title('Puntos Aleatorios Dentro de USA')
ax.set_xlabel('Longitud')
ax.set_ylabel('Latitud')
ax.legend()
plt.show()
Operaciones Topológicas Avanzadas
Shapely y Geopandas ofrecen una rica colección de operaciones topológicas para combinar o modificar geometrías:
.union(): Combina geometrías en una sola..intersection(): Devuelve la parte de las geometrías que se superponen..difference(): Devuelve la parte de una geometría que no se superpone con otra..symmetric_difference(): Devuelve las partes de las geometrías que no se superponen entre sí.
# Ejemplo de intersección de buffers (simplificado para ilustración)
# Crear dos puntos y sus buffers
point_a = Point(0, 0)
point_b = Point(1.5, 0)
buffer_a = point_a.buffer(1)
buffer_b = point_b.buffer(1)
# Calcular la intersección
intersection_buffer = buffer_a.intersection(buffer_b)
# Visualizar
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
gpd.GeoSeries([buffer_a], color='blue', alpha=0.5, ax=ax, label='Buffer A').plot()
gpd.GeoSeries([buffer_b], color='red', alpha=0.5, ax=ax, label='Buffer B').plot()
gpd.GeoSeries([intersection_buffer], color='purple', alpha=0.7, ax=ax, label='Intersección').plot()
ax.set_title('Intersección de Buffers')
ax.set_aspect('equal', adjustable='box') # Para que los círculos se vean como círculos
ax.legend()
plt.show()
📈 Casos de Uso Comunes
Las posibilidades con Geopandas son vastas. Aquí te dejamos algunos casos de uso comunes:
- Análisis de Proximidad: ¿Qué puntos de interés están a una distancia determinada de una ubicación? (Usando buffers y
sjoin). - Agregación de Datos por Región: Calcular el promedio de una variable (ej. ventas) para cada región geográfica (ej. estado, país). (Usando
sjoinygroupby). - Filtrado Geográfico: Seleccionar solo las entidades que caen dentro de un área específica. (Usando
cxpara indexado espacial, osjoin). - Enrutamiento y Logística: Aunque Geopandas no hace enrutamiento directamente, puede preparar los datos para librerías especializadas.
✅ Conclusión
Dominar el análisis de datos geográficos abre una nueva dimensión en tus proyectos de ciencia de datos. Pandas, en combinación con Geopandas y Shapely, proporciona un conjunto de herramientas extremadamente potente y flexible para manejar, analizar y visualizar información espacial. Desde la creación de mapas temáticos hasta el cálculo de distancias y la realización de uniones espaciales complejas, estas librerías te permiten dar vida a tus datos y extraer insights geográficos valiosos.
¡Experimenta con tus propios conjuntos de datos geográficos y descubre el poder de la ubicación! ¡El mundo es tu lienzo de datos!
Tutoriales relacionados
- Agregación Avanzada de Datos con Pandas: El Poder de `groupby()` y `agg()`intermediate18 min
- Manipulación Avanzada de Cadenas en Pandas: Potenciando tus Datos Textuales con `.str` 📝intermediate20 min
- Explorando y Manipulando Datos Jerárquicos con MultiIndex en Pandas 🌲intermediate15 min
- Análisis Exploratorio de Datos con Pandas: El Arte de Desvelar Secretos Ocultos en tus Datosintermediate20 min
- Ingeniería de Características en Datos Tabulares con Pandas y NumPy 🛠️intermediate15 min
Comentarios (0)
Aún no hay comentarios. ¡Sé el primero!