Manipulações básicas em dados de geolocalização utilizando Python
Ao longo da minha carreira na área de dados eu posso afirmar que tenho menos “horas de vôo” em Python do que em R, no entanto, buscando equilibrar estas habilidades, há algum tempo venho me forçando realizar em Python atividades que tenho maior fluência executando em R.
Neste ano iniciei uma pesquisa que envolve dados de geolocalização e aprendi alguns macetes que podem ser úteis para quem não tem muita experiência, sendo assim, o objetivo deste post é demonstrar algumas manipulações básicas em dados de geolocalização, utilizando Python.
Mãos à obra
Para ajudar com os exemplos optei por utilizar os dados de geolocalização disponibilizados pelo Olist através da plataforma Kaggle. Através do endereço https://www.kaggle.com/olistbr/brazilian-ecommerce?select=olist_geolocation_dataset.csv, faça o download do arquivo olist_geolocation_dataset.csv. Caso deseje acompanhar utilizando o notebook que originou este post, deixei disponível no GitHub: https://github.com/juniorssz/exemplos-python-geo
Nesta primeira etapa utilizaremos o pandas, portanto, efetue a instalação caso ainda não tenha feito:
pip install pandas
Para carregar o dataset:
import pandas as pddf = pd.read_csv('olist_geolocation_dataset.csv')
Visualizando as primeiras observações:
df.head()

Visualizando a estrutura do dataset:
df.info()

Como estão distribuídos os registros com relação aos estados?
df.geolocation_state.value_counts()

Vamos agregar os registros por coordenada:
df_agg = df.groupby(['geolocation_lat', 'geolocation_lng']).agg(
uf=('geolocation_state', 'min'),
n_pontos=('geolocation_lat', 'count')
).reset_index()df_agg.head()

df_agg.shape

Observe que o número de registros reduziu de 1.000.163 para 718.463, isto significa que haviam pontos repetidos no dataset.
Garantindo somente dados do estado de Alagoas
Imagine que o objetivo aqui seja trabalhar somente com dados de AL. A opção mais óbvia seria filtrar os registros com uf == "AL"
, mas quem garante que esta informação está correta no conjunto de dados? Uma forma de garantir a integridade da informação é verificando se a coordenada realmente está localizada em AL. Para isto vamos precisar do pacote shapely.
Caso ainda não tenha instalado:
pip install shapely
Agora precisamos das coordenadas que formam o polígono do estado de Alagoas. Vamos aproveitar o ótimo trabalho realizado pelo Eduardo Veras e fazer o download do arquivo AL.json: https://github.com/eduardo-veras/kml-brasil/tree/master/lib/2010/estados/json.
Feito o download, precisamos ler o arquivo:
import json
from shapely.geometry import Point, Polygonwith open('AL.json') as json_file:
data_geo = json.load(json_file)
Agora devemos converter as coordenadas para o formato DataFrame:
df_borders = pd.DataFrame(data_geo['borders'][0])df_borders.head()

O próximo passo é criar o polígono do estado de Alagoas:
poligono = Polygon(zip(list(df_borders.lng), list(df_borders.lat)))poligono

Para facilitar a nossa vida, vamos criar uma função que recebe as coordenadas e o objeto Polygon, e retorna verdadeiro quando as coordenadas estão dentro do polígono.
def within_polygon(lng, lat, polygon):
point = Point(float(lng), float(lat))
return point.within(polygon)
Agora aplicamos a função em todo o dataset e o resultado atribuímos a uma nova coluna:
df_agg['localizado_no_poligono'] = df_agg.apply(lambda x: within_polygon(
x.geolocation_lng, x.geolocation_lat, poligono), axis=1)df_agg.head()

df_agg.localizado_no_poligono.value_counts()

Perceba que foram classificados 3.172 pontos dentro do estado de Alagoas. Vamos cruzar esta informação com a coluna uf:
pd.crosstab(df_agg.uf, df_agg.localizado_no_poligono).reset_index()

Aqui notamos que há 155 pontos identificados como AL, mas que na verdade não estão localizado no estado. Também observamos que há alguns pontos identificados como RJ, SE e SP, mas que deveriam estar atribuídos ao estado de Alagoas.
Agora vamos filtrar somente os pontos localizados em AL:
df_al = df_agg[df_agg.localizado_no_poligono]df_al.shape

Pronto, daqui para frente trabalharemos somente com os 3.172 pontos localizados em AL.
Plotando os pontos no mapa de Alagoas
O objetivo agora é visualizarmos a dispersão destes pontos no mapa de Alagoas. Para isto vamos precisar dos pacotes seaborn e geopandas.
Instale-los caso ainda não tenha feito:
pip install seabornpip install geopandas
Vamos precisar do shape file do estado de Alagoas, disponível no site do IBGE: https://www.ibge.gov.br/geociencias/organizacao-do-territorio/15774-malhas.html?=&t=downloads.
Faça o download do arquivo al_municipios.zip:

Em seguida descompacte na raiz dos seu projeto e mantenha todos os arquivos presentes na pasta al_municipios:

Agora vamos carregar o shape file de Alagoas:
import geopandas as gpd
import os
import seaborn as sns
import matplotlib.pyplot as pltshape_path = os.path.join('al_municipios', 'AL_Municipios_2019.shp')
shape_al = gpd.read_file(shape_path)
Para plotar somente o mapa de Alagoas, execute:
fig, ax = plt.subplots(figsize=(15,8))
shape_al.plot(ax=ax, color='lightgray')

Agora plotando os pontos sobre o mapa:
fig, ax = plt.subplots(figsize=(15,8))
shape_al.plot(ax=ax, color='lightgray')
sns.scatterplot(data=df_al,
x='geolocation_lng',
y='geolocation_lat',
size='n_pontos',
sizes=(50, 500),
alpha=0.3)

Calculando distâncias
Existem diversas fórmulas para cálculo de distâncias e inúmeras maneiras de se fazer em Python. Neste post optei por demonstrar como realizar através da fórmula de haversine.

Não vou entrar nos detalhes matemáticos da fórmula para não sair do foco do assunto, mas em resumo para quem não conhece, esta equação é utilizada para estabelecer a distância entre dois pontos em uma esfera. Portanto, é uma maneira de se obter a distância aproximada entre duas localidades do globo terrestre (que não é uma esfera perfeita).
Caso ainda não tenha feito, instale o pacote haversine:
pip install haversine
Para entender como funciona o pacote, vamos pegar como exemplo as coordenadas das cidades de Maceió e Itamaracá:
from haversine import haversine, Unit, haversine_vectormaceio = (-9.647449, -35.709190)
itamaraca = (-9.345859, -35.865804)
Observe que as coordenadas foram atribuidas a uma tupla, sendo o primeiro elemento a latitude e o segundo, a longitude.
Para calcular a distância em quilômetros, execute:
haversine(maceio, itamaraca)

Vamos dar uma olhada no Google Maps para ver se está fazendo sentido:

Parece coerente. É possível calcular a distância em outras unidades, como em metros:
haversine(maceio, itamaraca, unit=Unit.METERS)
Em milhas:
haversine(maceio, itamaraca, unit=Unit.MILES)
Ou em milhas náuticas:
haversine(maceio, itamaraca, Unit.NAUTICAL_MILES)
Também é possível calcular uma matriz de distâncias. Para o exemplo, vamos selecionar somente 10 pontos:
df_al_10 = df_al.head(10).reset_index(drop=True)df_al_10

Agora vamos construir a matriz:
dij = df_al_10[['geolocation_lat', 'geolocation_lng']]
dij = [tuple(x) for x in dij.to_numpy()]
dij = haversine_vector(dij, dij, Unit.KILOMETERS, comb=True)pd.DataFrame(dij).head(10)

Simples, não? Para mais detalhes, acesse a documentação: https://pypi.org/project/haversine/.
Conclusão
Com a intenção de facilitar a vida dos colegas com necessidades semelhantes às minhas, o objetivo deste post é centralizar alguns macetes para manipulação de dados de geolocalização com Python, que descobri pesquisando em fontes dispersas. Tentei simplificar ao máximo para que até os menos experientes sejam capazes de acompanhar, no entanto, se houverem dúvidas, é só entrar em contato comigo: https://acsjunior.com.