Como fazer enriquecimento geográfico em ETL: passo a passo
Este tutorial mostra como fazer enriquecimento geográfico em ETL para acrescentar latitude/longitude e município a registos de clientes. Enriquecer dados geográficos torna as análises e as visualizações mais úteis (mapas, segmentação por região) e melhora relatórios de negócio.
Pré-requisitos
- Python 3.8+ instalado
- Bibliotecas: requests, pandas
- Ficheiro CSV com coluna de morada (address)
- Chave de API de um serviço de geocodificação (ex.: Nominatim ou Google Geocoding)
Passo 1: Preparar os dados de entrada
Começa por carregar o CSV e garantir que a coluna address está normalizada (trim, remover duplicados óbvios). Isto evita chamadas desnecessárias à API e custos. Vamos também criar um identificador único para cada morada.
import pandas as pd
data = pd.read_csv('clientes.csv')
# Normalizar espaços e remover linhas sem morada
data['address'] = data['address'].astype(str).str.strip()
data = data[data['address']!='']
# Criar chave para deduplicação
data['addr_key'] = data['address'].str.lower()
Passo 2: Deduplicação antes do geocodificação
Fazer geocodificação é custoso; deduplicamos as moradas para chamar a API apenas uma vez por morada distinta. Mantemos um mapeamento para reaplicar aos registos originais.
# Obter moradas únicas
unique_addrs = data[['addr_key','address']].drop_duplicates().reset_index(drop=True)
Passo 3: Implementar a chamada à API de geocodificação com tratamento de erros
Criamos uma função simples que chama a API (exemplo com Nominatim) e trata erros básicos e limites de taxa. Em produção usa retries exponenciais e cache persistente.
import requests
import time
def geocode(address, email='seu_email@example.com'):
# Exemplo com Nominatim (OpenStreetMap) — respeita 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
# Teste rápido (apenas uma morada)
# print(geocode('Praça do Comércio, Lisbon'))
Passo 4: Executar geocodificação em lote com cache em memória
Percorremos as moradas únicas, guardamos resultados num dicionário (cache) e aplicamos um pequeno delay para evitar rate limits. Em cenários maiores, usa um cache persistente (Redis, ficheiro) e workers paralelos com 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) # Respeitar limites do serviço
geo_df = pd.DataFrame(results)
Passo 5: Reunir os dados geocodificados com o dataset original
Fazemos um join entre os resultados de geocodificação e o dataset original pelo campo addr_key. Assim cada cliente recebe latitude, longitude e cidade.
final = data.merge(geo_df, on='addr_key', how='left')
# Remover colunas temporárias se necessário
final = final.drop(columns=['addr_key'])
final.to_csv('clientes_enriquecidos.csv', index=False)
Verificar o resultado
Abre o ficheiro clientes_enriquecidos.csv e confirma que cada registo tem latitude e longitude válidas ou valores nulos controlados. Faz amostras: verifica 10 moradas com e sem coordenadas. Para validar geograficamente, carrega numa ferramenta de visualização (ex.: Power BI ou QGIS) e confirma que os pontos caem nos locais esperados.
Conclusão
Acabaste de implementar um fluxo de enriquecimento geográfico simples em ETL: normalização, deduplicação, geocodificação com tratamento básico de erros e junção dos resultados. Próximos passos: adicionar cache persistente, retries exponenciais, paralelismo controlado e validação de precisão (verificações de distância). Dica: começa por testar com um subconjunto antes de processar todo o dataset para evitar custos e bloqueios da API.