Agrupamento de dados geoespaciais

Guilherme Ferreira

2024-12-18

Introdução

A representação espacial de dados, especialmente os geográficos, facilitam a percepção ou compreensão de determinados fenômenos, inclusive a busca pela solução de problemas reais.

Mapas interativos, ao permitirem que as informações sejam consumidas de forma mais adequada, ajudam na exploração de dados e estimulam a formação de padrões.

O dados do ITBI (Imposto sobre Transmissão de Bens Imóveis), disponibilizados pela Prefeitura Municipal de Juiz de Fora, podem ser visualizados sob a forma de mapas, após a obtenção das coordenadas geográficas, calculadas a partir das informações correspondentes ao endereço das matrículas transacionadas.

Objetivos

O objetivo do presente artigo não é simplesmente demonstrar as habilidades técnicas necessárias para a construção de mapas, através de pacotes como {leaflet}, mas também valorizar a utilidade do uso das ferramentas de análise geoespacial disponíveis, para a solução de problemas reais.

Ao final do artigo, aprenderemos a:

  1. Obter coordenadas geográficas através de endereços;
  2. Criar marcadores personalizados;
  3. Agrupar dados geoespaciais.

Disclaimer

Os dados são utilizados para fins educacionais; contudo, embora sejam abertos ao público, respeitamos os princípios de confidencialidade e privacidade, de modo que as matrículas foram omitidas ou anonimizadas, para evitar a identificação dos imóveis ou proprietários.

Bibliotecas

Carregamos as seguintes bibilotecas do R:

  • rvest - biblioteca para extração de dados web;
  • tidyverse - coleção de ferramentas para manipulação de dados;
  • lubridate - biblioteca para manipular dados no formato data/hora;
  • prettydoc - temas adicionais para documentos Rmarkdown;
  • reshape2 - ferramenta para transformação de dados;
  • scales - utilizada para personalizar legendas;
  • tidygeocoder - interface para tarefas de geocodificação;
  • readxl - pacote para manipulação de dados do Excel;
  • stringr - conjunto de funções para manipulação de strings.
  • leaflet - biblioteca javascript para desenvolvimento de mapas interativos;
  • leaflet.extras - fornece funcionalidades adicionais ao pacote leaflet;
  • leafgl - para agilizar a renderização de marcadores;
  • osmdata - permite o acesso aos dados do OpenStreetMap(OSM);
  • sf - ferramenta para codificação de dados vetoriais espaciais;
  • viridis - para implementar mapa de cores amigável.

Coleta de dados

A coleta de dados foi realizada de acordo com o procedimento definido no artigo publicado anteriormente, intitulado Indicadores imobiliários de Juiz de Fora: Análise de dados do ITBI, disponível aqui.

Ajuste final

Depois da fase de coleta e pré-processamento, efetuamos o ajuste final dos dados: filtramos somente os registros das operações de compra e venda, para os anos a partir de 2022, formatamos a variável CEP e criamos uma nova variável, denominada end, que é a junção das variáveis logradouro, endereço e número.

  df <- df %>%
  filter(operação == "COMPRA E VENDA",
         ano >= "2022") %>%
  select(-operação) %>%
  mutate(cep = str_replace(cep, "(\\d+)(\\d{3})$", "\\1-\\2"),
         end = paste(logradouro, endereço, número, sep = " ")) 

Geocodificação

Geocodificação é o processo de conversão de endereços em coordenadas geográficas. Para isso, utilizamos o pacote tidygeocoder, que dá acesso à API do projeto de código livre e gratuito Open Source Routing Machine(OSRM), para obtenção das coordenadas geográficos dos endereços contidos no data frame. Passamos diversos parâmetros para a função geocode(), com o intuito de aumentar a acurácia do resultado da busca.

search <- df %>% geocode(street = end,
                              city = cidade,
                              county = bairro,
                              state = uf,
                              method ='osm')

Gravamos as coordenadas geográficas em um arquivo csv:

write.csv(search, paste(getwd(), '/search.csv', sep = ''))

Lemos o arquivo csv

search <- read.csv('search.csv')

Após aplicarmos os filtros para validação dos dados e selecionarmos as variáveis desejadas, salvamos o resultado em um novo objeto:

geo <- search %>% 
    filter(operação == "COMPRA E VENDA" & cep != 'NA' & lat != 'NA' ) %>%
    select(inscrição, lat, long)

Rotina para filtrar coordenadas

Para filtrar somente as coordenadas que estão dentro do município de Juiz de Fora, caso haja falhas no processo de geocodificação, adotamos o seguinte procedimento, com uso do pacote osmdata:

# Consultar limites de Juiz de Fora
juiz_de_fora <- opq(bbox = c(-43.5, -22, -43, -21.5)) %>%
  add_osm_feature(key = 'name', value = 'Juiz de Fora') %>%
  osmdata_sf()

# Obter o polígono
juiz_de_fora_poly <- juiz_de_fora$osm_multipolygons

# Garantir o CRS correto
juiz_de_fora_poly <- st_transform(juiz_de_fora_poly, crs = 4326)

# Transformar os pontos em um objeto sf
geo_sf <- geo %>%
  st_as_sf(coords = c("long", "lat"), crs = 4326) %>%
  st_jitter(factor = 0.0001) # para separar pontos sobrepostos

# 3. Filtrar os pontos que estão dentro do polígono
geo_in <- geo_sf %>%
  filter(apply(st_within(., juiz_de_fora_poly, sparse = FALSE), 1, any))

Mapa inicial

Para a construção do mapa preliminar, utilizamos como entrada o objeto da classe sf, antes da aplicação do filtro. Além disso, recorremos à função addGlPoints do pacote leafgl, que utiliza a biblioteca gráfica WebGL, que é muito mais rápida para renderizar grandes volumes de pontos; do contrário, se usássemos o marcador padrão, provocaríamos lentidão no carregamento da página.

Ao visualizarmos o mapa básico, fica evidente a poluição visual, devido ao grande número de pontos de dados. Podemos observar, também, que houve falhas no processo de geocodificação, pois algumas coordenadas estão localizadas em regiões diferentes do polígono pesquisado.

h <- leaflet(width = "100%") %>% 
  addTiles() %>% 
  addPolygons(data = juiz_de_fora_poly, color = "blue", fillOpacity = 0.2) %>%
  setView(-43.365703, -21.762661, zoom = 12) %>% 
  addGlPoints(
    data = geo_sf,       # Data frame com as coordenadas
    radius = 5,          # Tamanho do ponto
    fillOpacity = 0.7,   # Opacidade do preenchimento
    fillColor = "red",  # Cor dos pontos
) %>%
  addFullscreenControl(position = "bottomright")
h

Ícone personalizado

O pacote leaflet possui um plugin que permite a criação de ícones personalizados.

icons <- awesomeIcons(
  icon = 'home',
  iconColor = 'black',
  markerColor = 'white',
  library = 'glyphicon'
)

Agrupamento de dados

Clustering

Para melhorar a visualização dos dados no mapa interativo, utilizamos o método de clustering oferecido nativamente pelo pacote leaflet.

Agrupamentos automáticos são exibidos como círculos coloridos no mapa, segundo um vetor de cores, formado pelo verde, amarelo e vermelho, que determina o volume de itens do cluster. O nível de agrupamento é inversamente proporcional ao tamanho do zoom. Quanto maior o zoom menor o cluster, até chegar à unidade de análise individual. Ao passar o mouse sobre o círculo, será exibida a entensão da área delimitada pelos marcadores.

h2 <- leaflet(geo_in, width = "100%") %>%
  addTiles() %>%
  addPolygons(data = juiz_de_fora_poly, color = "blue", fillOpacity = 0.2) %>%
  setView(-43.365703, -21.762661, zoom = 12) %>%
  addAwesomeMarkers(icon = icons, clusterOptions = markerClusterOptions()) %>%
  addFullscreenControl(position = "bottomright")
h2

Heatmap

Mapas de calor são alternativas à técnica de agrupamento para visualização de pontos de dados densamente povoados. Nesse caso, ao invés dos círculos, adota-se a técnica de transição de cores para exibir a concentração relativa de pontos de dados no mapa.

Utilizamos o mapa de cores amigável viridis.

# Gerar o gradiente de cores usando a paleta viridis
viridis_gradient <- colorRampPalette(viridis(256))(256)

# Criar uma lista nomeada para o gradiente de cores
viridis_gradient_list <- setNames(viridis_gradient, seq(0, 1, length.out = length(viridis_gradient)))

h3 <-   leaflet(geo_in, width = "100%") %>%
  addTiles() %>%
  addPolygons(data = juiz_de_fora_poly, color = "blue", fillOpacity = 0.2) %>%
    addHeatmap(
    blur = 20, # Define o grau de "desfoque" das áreas
    max = 0.05, # Densidade máxima do heatmap (ajustar conforme os dados)
    radius = 15, # Raio de influência de cada ponto
    gradient = viridis_gradient_list # Gradiente personalizado

  ) %>%
  addFullscreenControl(position = "bottomright")
  
  h3

Considerações finais

Mapas interativos são úteis para representar a distribuição espacial dos dados. Sugerimos algumas alternativas, dentre muitas disponíveis.

Recordamos os objetivos inicialmente propostos: assegurar o domínio das ferramentas para a obtenção das coordenadas geográficas através de endereços textuais, o desenvolvimento de marcadores personalizados e o aprendizado das técnicas para agrupamento de dados geoespaciais.

A análise de dados geospaciais pode auxiliar o planejamento e tomada de decisão de construtoras, imobiliárias, corretores de imóveis, bancos e ser útil para formulação de políticas públicas.

Referências:

Bauer, P.C., Landesvatter, C., Behrenshttps, L. (2023). APIs for social scientists: A collaborative review. Acessado em 24/04/2024: https://bookdown.org/paul/apis_for_social_scientists/

Johnson, H. (2018). Interactive maps in R (with leaflet). Acessado em 24/04/2024: https://hansenjohnson.org/post/interactive-maps-in-r/

Kashnitsky, I. (2023). Geocode address text strings using tidygeocoder. Publicado em 01/11/2023. Acessado em 04/12/2024: https://ikashnitsky.phd/2023/geocoding/

Lovelace, R., Nowosad, J., Muenchow, J. (2021). Geocomputation with R. Acessado em 24/04/2024: https://bookdown.org/robinlovelace/geocompr/

Oldham, P. (2018). Exploring Geocoding Scientific Literature with R. Acessado em 24/04/2024: https://www.pauloldham.net/geocoding-scientific-literature-with-r/

Paniagua, C. A. T. (2022). Geocoding and visualizing address information with R. Publicado em 21/12/2022. Acessado em 04/12/2024: https://www.carlos-toruno.com/blog/geocoding/

Walker, K. (2024). Circle cluster and heatmaps for dense point data in R. Publicado em 07/10/2024. Acessado em 04/12/2024: https://walker-data.com/posts/mapgl-dots/