Cómo hacer enriquecimiento geográfico en ETL: paso a paso
Este tutorial muestra cómo hacer enriquecimiento geográfico en ETL para añadir latitud/longitud y municipio a registros de clientes. Enriquecer datos geográficos hace que los análisis y las visualizaciones sean más útiles (mapas, segmentación por región) y mejora los informes de negocio.
Requisitos previos
- Python 3.8+ instalado
- Bibliotecas: requests, pandas
- Fichero CSV con columna de dirección (address)
- Clave de API de un servicio de geocodificación (p. ej.: Nominatim o Google Geocoding)
Paso 1: Preparar los datos de entrada
Empieza por cargar el CSV y garantizar que la columna address está normalizada (trim, eliminar duplicados obvios). Esto evita llamadas innecesarias a la API y costes. También crearemos un identificador único para cada dirección.
import pandas as pd
data = pd.read_csv('clientes.csv')
# Normalizar espacios y eliminar filas sin dirección
data['address'] = data['address'].astype(str).str.strip()
data = data[data['address']!='']
# Crear clave para deduplicación
data['addr_key'] = data['address'].str.lower()
Paso 2: Deduplicación antes de la geocodificación
Hacer geocodificación es costoso; deduplicamos las direcciones para llamar a la API solo una vez por dirección distinta. Mantenemos un mapeo para reaplicarlo a los registros originales.
# Obtener direcciones únicas
unique_addrs = data[['addr_key','address']].drop_duplicates().reset_index(drop=True)
Paso 3: Implementar la llamada a la API de geocodificación con manejo de errores
Crearemos una función sencilla que llama a la API (ejemplo con Nominatim) y gestiona errores básicos y límites de tasa. En producción utiliza reintentos exponenciales y caché persistente.
import requests
import time
def geocode(address, email='seu_email@example.com'):
# Ejemplo con Nominatim (OpenStreetMap) — respeta políticas de uso
url = 'https://nominatim.openstreetmap.org/search'
params = {'q': address, 'format': 'json', 'limit': 1, 'addressdetails': 1, 'email': email}
try:
resp = requests.get(url, params=params, timeout=10)
if resp.status_code == 200:
j = resp.json()
if j:
lat = j[0].get('lat')
lon = j[0].get('lon')
city = j[0].get('address', {}).get('city') or j[0].get('address', {}).get('town') or j[0].get('address', {}).get('village')
return {'latitude': float(lat), 'longitude': float(lon), 'city': city}
return None
else:
return None
except requests.RequestException:
return None
# Prueba rápida (solo una dirección)
# print(geocode('Praça do Comércio, Lisbon'))
Paso 4: Ejecutar geocodificación en lote con caché en memoria
Recorremos las direcciones únicas, guardamos resultados en un diccionario (cache) y aplicamos un pequeño delay para evitar rate limits. En escenarios mayores, usa un caché persistente (Redis, fichero) y workers paralelos con throttling.
cache = {}
results = []
for idx, row in unique_addrs.iterrows():
key = row['addr_key']
addr = row['address']
if key in cache:
results.append({'addr_key': key, **cache[key]})
continue
res = geocode(addr)
if res:
cache[key] = res
results.append({'addr_key': key, **res})
else:
cache[key] = {'latitude': None, 'longitude': None, 'city': None}
results.append({'addr_key': key, 'latitude': None, 'longitude': None, 'city': None})
time.sleep(1) # Respetar límites del servicio
geo_df = pd.DataFrame(results)
Paso 5: Reunir los datos geocodificados con el dataset original
Hacemos un join entre los resultados de geocodificación y el dataset original por el campo addr_key. Así cada cliente recibe latitud, longitud y ciudad.
final = data.merge(geo_df, on='addr_key', how='left')
# Eliminar columnas temporales si es necesario
final = final.drop(columns=['addr_key'])
final.to_csv('clientes_enriquecidos.csv', index=False)
Verificar el resultado
Abre el fichero clientes_enriquecidos.csv y confirma que cada registro tiene latitud y longitud válidas o valores nulos controlados. Haz muestreos: verifica 10 direcciones con y sin coordenadas. Para validar geográficamente, cárgalo en una herramienta de visualización (p. ej.: Power BI o QGIS) y confirma que los puntos caen en los lugares esperados.
Conclusión
Has implementado un flujo de enriquecimiento geográfico sencillo en ETL: normalización, deduplicación, geocodificación con manejo básico de errores y unión de los resultados. Próximos pasos: añadir caché persistente, reintentos exponenciales, paralelismo controlado y validación de precisión (comprobaciones de distancia). Consejo: empieza probando con un subconjunto antes de procesar todo el dataset para evitar costes y bloqueos de la API.