1 Introdução

Este projeto é inspirado na live intitulada “Geomarketing na prática” feita por Daniel Andrade no dia 25/01/2023.

Os dados fictícios foram fornecidos durante a live. É um estudo que busca identificar onde estão localizados os potenciais clientes de uma pizzaria no município do Rio de Janeiro.

Alguns desafios são apresentados durante o desenvolvimento do estudo, como trabalhar com diferentes formatos de arquivos. Aqui utilizei as extensões .csv, .gpkg, .shp e .kml.

Além disso, esse projeto é uma maneira de me desafiar. Enquanto o Daniel desenvolveu a análise utilizando o QGIS, eu busquei adaptar a mesma lógica dele, mas utilizando o R. Também procurei otimizar algumas etapas, principalmente no tratamento das planilhas.

Você pode optar por exibir ou ocultar todos os códigos utilizados através do menu superior Code.

2 Pacotes necessários para a análise

2.1 Pacotes para ETL-Dataviz

pacman::p_load(
  # ETL (extract, transform, load)
  janitor, readr, readxl, lubridate,
  dplyr, 
  tidyverse, 
  glue,
  skimr,
  # Visualização
  ggplot2,
  rmarkdown, 
  knitr,
  kableExtra,
  ggthemes,
  ggtext
)

2.2 Pacotes Geoespaciais

pacman::p_load(
  sf, raster, 
  leaflet, leaflet.extras,
  rgdal, rgeos,
  maps,
  mapview,
  ggmap
)

3 Extract, Transform, Load (ETL)

3.1 Arquivos

No code chunk abaixo estou realizando a seguinte sequência de passos (pipeline):

  1. Importo o arquivo .csv.

  2. Coloco o nome das colunas em letras minúsculas e sem espaço/caracteres especiais para facilitar a manipulação.

  3. Gero duas novas colunas:

    1. A coluna endereco_completo será usada para a geocodificação.

    2. A coluna Name será usada para unificar os dados (inner_join()) já geocodificados com as demais informações de endereço.

  4. Reordeno as colunas, para facilitar a visualização

  5. E, por fim, altero o formato da coluna para tibble, para ser melhor utilizada no R.

clientes_pizzaria <- read.csv(
  "E:/Desktop/Banco de dados - Super Live/Clientes _Pizzaria_RJ.csv", 
  header = TRUE,
  sep = ";",
) %>% 
  janitor::clean_names() %>% 
  mutate(
   endereco_completo = paste0(endereco, ", ", numero, ", ", bairro, "-", cidade),
   Name = endereco,
  ) %>% 
  rename(
    id_cliente = cliente                   ,
  ) %>%
  dplyr::select(
    c(1:3),
    Name,
    endereco_completo,
    everything()
  ) %>% 
  as_tibble()

No code chunk abaixo importo o arquivo em formato .gpkg da pizzaria. Além disso, transformo para o SRC SIRGAS2000.

pizzaria_RJ <- st_read(
  "E:/Desktop/Banco de dados - Super Live/Pizzaria.gpkg"
) %>% 
  st_transform(crs = 4674) #4326 = WGS84, 4674 = SIRGAS2000
FALSE Reading layer `escola_tcnica' from data source 
FALSE   `E:\Desktop\Banco de dados - Super Live\Pizzaria.gpkg' using driver `GPKG'
FALSE Simple feature collection with 1 feature and 1 field
FALSE Geometry type: POINT
FALSE Dimension:     XY
FALSE Bounding box:  xmin: 683707.2 ymin: 7464771 xmax: 683707.2 ymax: 7464771
FALSE Projected CRS: SIRGAS 2000 / UTM zone 23S

3.2 Importando malha municipal do IBGE

Após fazer o download dos dados do site do IBGE1

lim_mun_RJ <- shapefile(
  "E:/Desktop/Banco de dados - Super Live/RJ_Municipios_2021.shp"
) %>% 
  as("sf") 

lim_mun_RJ %>% 
  head(5)
## Simple feature collection with 5 features and 4 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -44.64034 ymin: -23.22766 xmax: -41.78408 ymax: -21.60125
## CRS:           +proj=longlat +ellps=GRS80 +no_defs
##    CD_MUN             NM_MUN SIGLA AREA_KM2                       geometry
## 1 3300100     Angra dos Reis    RJ  813.420 MULTIPOLYGON (((-44.14994 -...
## 2 3300159            Aperibé    RJ   94.542 MULTIPOLYGON (((-42.12536 -...
## 3 3300209           Araruama    RJ  638.276 MULTIPOLYGON (((-42.18387 -...
## 4 3300225              Areal    RJ  110.724 MULTIPOLYGON (((-43.03716 -...
## 5 3300233 Armação dos Búzios    RJ   70.977 MULTIPOLYGON (((-41.91817 -...

4 Análise exploratória de dados (EDA)

Nesta etapa verifico a estrutura do dado: como estão ordenadas as colunas, qual o conteúdo delas, o número de observações totais (ou n) e se temos valores não medidos/faltantes (NA).

Abaixo, temos a visualização da planilha clientes_pizzaria.

Encontramos que temos 46 linhas e 10 colunas.

clientes_pizzaria %>% 
  str()
## tibble [46 × 10] (S3: tbl_df/tbl/data.frame)
##  $ id_cliente       : int [1:46] 1 2 3 5 6 7 8 9 10 11 ...
##  $ endereco         : chr [1:46] "Rua Isabel Alves" "Rua Franca Júnior" "Rua Bocaiúva Cunha" "Rua Sotero dos Reis" ...
##  $ numero           : chr [1:46] "28" "361" "48" "107" ...
##  $ Name             : chr [1:46] "Rua Isabel Alves" "Rua Franca Júnior" "Rua Bocaiúva Cunha" "Rua Sotero dos Reis" ...
##  $ endereco_completo: chr [1:46] "Rua Isabel Alves, 28, Taquara-Rio de Janeiro" "Rua Franca Júnior, 361, Andaraí-Rio de Janeiro" "Rua Bocaiúva Cunha, 48, Gardênia Azul-Rio de Janeiro" "Rua Sotero dos Reis, 107, Praça da Bandeira-Rio de Janeiro" ...
##  $ bairro           : chr [1:46] "Taquara" "Andaraí" "Gardênia Azul" "Praça da Bandeira" ...
##  $ cidade           : chr [1:46] "Rio de Janeiro" "Rio de Janeiro" "Rio de Janeiro" "Rio de Janeiro" ...
##  $ uf               : chr [1:46] "RJ" "RJ" "RJ" "RJ" ...
##  $ pais             : chr [1:46] "Brasil" "Brasil" "Brasil" "Brasil" ...
##  $ cep              : int [1:46] 22723010 20510270 22765529 20270200 20211070 20250001 22723010 20261005 20760070 20270133 ...
clientes_pizzaria %>% 
  skim() 
Table 4.1: Data summary
Name Piped data
Number of rows 46
Number of columns 10
_______________________
Column type frequency:
character 8
numeric 2
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
endereco 0 1 10 26 0 39 0
numero 0 1 2 4 0 39 0
Name 0 1 10 26 0 39 0
endereco_completo 0 1 39 60 0 43 0
bairro 0 1 4 17 0 26 0
cidade 0 1 11 18 0 4 0
uf 0 1 2 2 0 1 0
pais 0 1 6 6 0 1 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
id_cliente 0 1 26.63 15.38 1 13.5 26.5 38.75 54 ▇▇▇▇▆
cep 0 1 21258477.07 1389354.92 20211070 20260030.0 20526350.0 22340295.75 25561120 ▇▁▂▁▁

No code chunk abaixo, armazeno as informações da função skim() em formato tibble na variável eda, para a manipulação de dados dentro do R. Na sequência, identificamos as colunas geradas a partir da função skim().

eda <- clientes_pizzaria %>% 
  skim() %>% 
  as_tibble()
eda %>% 
  names()
value
skim_type
skim_variable
n_missing
complete_rate
character.min
character.max
character.empty
character.n_unique
character.whitespace
numeric.mean
numeric.sd
numeric.p0
numeric.p25
numeric.p50
numeric.p75
numeric.p100
numeric.hist

Existem 8 colunas do tipo character e 2 colunas do tipo numeric.

eda %>% 
  count(skim_type)
## # A tibble: 2 × 2
##   skim_type     n
##   <chr>     <int>
## 1 character     8
## 2 numeric       2

No code chunk abaixo identificamos há diferença no número de endereços e endereços completos, ou seja, temos valores repetidos na coluna endereco. Isso aponta para o fato de termos múltiplos clientes na mesma rua.

eda %>% 
  dplyr::select(
    skim_variable,
    character.n_unique
  )
## # A tibble: 10 × 2
##    skim_variable     character.n_unique
##    <chr>                          <int>
##  1 endereco                          39
##  2 numero                            39
##  3 Name                              39
##  4 endereco_completo                 43
##  5 bairro                            26
##  6 cidade                             4
##  7 uf                                 1
##  8 pais                               1
##  9 id_cliente                        NA
## 10 cep                               NA

4.0.1 Número de NAs

Há 0 valores faltantes.

eda %>% 
  dplyr::select(n_missing) %>% 
  sum()
## [1] 0

4.0.2 Quais bairros possuem mais clientes

eda_rua <- clientes_pizzaria %>% 
  distinct(
    endereco_completo,
    .keep_all = TRUE
  ) %>%
  dplyr::select(
    endereco, numero, endereco_completo, bairro,
  ) %>% 
  group_by(endereco) %>% 
  mutate(n = n()) %>% 
  ungroup() %>% 
  arrange(
    desc(n),
    desc(bairro),
    desc(endereco),
    numero
    ) %>% 
  dplyr::select(
    # -endereco, 
    -numero,
  )
endereco endereco_completo bairro n
Rua Santa Amélia Rua Santa Amélia, 13, Praça da Bandeira-Rio de Janeiro Praça da Bandeira 3
Rua Santa Amélia Rua Santa Amélia, 88, Praça da Bandeira-Rio de Janeiro Praça da Bandeira 3
Rua Santa Amélia Rua Santa Amélia, 881, Praça da Bandeira-Rio de Janeiro Praça da Bandeira 3
Rua Senador Nabuco Rua Senador Nabuco, 23, Vila Isabel-Rio de Janeiro Vila Isabel 2
Rua Senador Nabuco Rua Senador Nabuco, 461, Vila Isabel-Rio de Janeiro Vila Isabel 2
Rua Barão de Itapagipe Rua Barão de Itapagipe, 254, Rio Comprido-Rio de Janeiro Rio Comprido 2
Rua Barão de Itapagipe Rua Barão de Itapagipe, 71, Rio Comprido-Rio de Janeiro Rio Comprido 2
Rua Barra do Pirai Rua Barra do Pirai, 75, Vilar dos Teles-São João de Meriti Vilar dos Teles 1
Rua Sambaitiba Rua Sambaitiba, 43, Vila Rosário-Duque de Caxias Vila Rosário 1
Rua Padre Artola Rua Padre Artola, 11, Vidigal-Rio de Janeiro Vidigal 1

No code chunk acima identificamos onde há mais clientes no mesmo bairro. Através da variável eda_rua percebemos que algumas ruas se repetem. A Rua Santa Amélia, do bairro Praça da Bandeira, é a que possui maior número de observações, com n total igual a 3.

5 Geração de mapas

5.1 Mapa municípios - Rio de Janeiro

Brasil <- getData(
  "GADM",
  country = "Brazil",
  level = 3
) %>%
  st_as_sf()

RJ <- subset(Brasil,
             NAME_1 == "Rio de Janeiro")

# Definindo o SRC
RJ <- RJ %>%
  st_transform(crs = 4674) #4326 = WGS84, 4674 = SIRGAS2000

clientes_pizzaria %>%
  ggplot()+
  geom_sf(
    data = RJ
  )+
  labs(
    title = "Municípios - RJ",
    x = "Longitude",
    y = "Latitude",
    caption = "Elaborado por: Leonardo Fernandes Wink\n26/01/2023"
  )+ 
  theme_bw()+
  theme(
    plot.title = element_text(
        size = 16,
        hjust = 0.5,
        color = "black",
        face = "bold"
      ),
  )
Mapa estático dos municípios do Rio de Janeiro

Figure 5.1: Mapa estático dos municípios do Rio de Janeiro

5.2 Geocodificação

  • Para essa etapa é necessário que se importe o arquivo para o Google Earth Pro e salve em .kml.
  • Nesse code chunk são gerados os campos de lat e long.
clientes_coords_attr <- read_sf(
  "E:/Desktop/Banco de dados - Super Live/Clientes _Pizzaria_RJ.kml"
) %>% 
  st_zm(
    drop = TRUE,
    what = "ZM"
  ) 
clientes_coords_attr <- clientes_coords_attr %>% 
  dplyr::mutate(long = sf::st_coordinates(.)[,1],
                lat = sf::st_coordinates(.)[,2]) %>% 
  st_transform(crs = 4674) #4326 = WGS84, 4674 = SIRGAS2000
clientes_pizzaria_join <- inner_join(
  x = clientes_pizzaria, 
  y = clientes_coords_attr,
  by = "Name"
  )

6 Mapa interativo

Nesta seção geramos os mapas interativos. Você pode dar zoom, arrastar para os lados e clicar nos pontos para saber mais informações a respeito.

6.1 Mapa de localização dos clientes da pizzaria

Gerando o mapa que será base para os demais.

  • Especificando o zoom inicial;

  • Adicionando a quadrícula dos graus (intervalo de 5º em 5º);

  • Definindo o provedor do mapa-base;

    • Se é imagem de satélite (ESRI) ou

    • Software livre, o Open Street Map (OSM)

  • Adicionando o limite dos municípios do estado do Rio de Janeiro;

  • Adicionando a barra de escala no canto inferior direito.

mapa_interativo <- clientes_pizzaria_join %>% 
  leaflet() %>% 
  setView(
    lat = -23,
    lng = -43.2,
    zoom = 8
  ) %>% 
  addSimpleGraticule(
    interval = 5,
    showOriginLabel = FALSE,
  ) %>% 
   addProviderTiles(
    # "Esri.WorldImagery" #Imagem de satélite
    "OpenStreetMap.Mapnik" #OpenStreetMap -> Software livre
  ) %>% 
  addPolygons(
    data = lim_mun_RJ,
    color = "red",
    fill = FALSE,
    weight = 2.5,
    opacity = 1,
  ) %>% 
  addScaleBar(
    # map,
    position = "bottomright",
    options = scaleBarOptions(
      maxWidth = 150,
      metric = TRUE,
      imperial = FALSE,
      updateWhenIdle = TRUE
    )
  )

6.2 Área de influência 1-3km

A partir das áreas de influência, depreende-se a área em que devem ser direcionadas campanhas de marketing, conforme a figura 6.1.

mapa_interativo %>%
  addCircles(
    data = pizzaria_RJ,
    radius = 3000,
    fillOpacity = 0.1,
    color = "green",
    popup = ~paste0(
      "<b>Endereço: </b>", "Rua João Paulo I", ", ", "s/n", "<br>",
      "<b>Bairro: </b>", "Estácio", "<br>",
      "<b>Município: </b>", "Rio de Janeiro", "<br>",
      "<b>CEP: </b>", "-", "<br>",
      "<b>Área de Influência: </b>", "3km",
      sep = " "
    )
  ) %>% 
  addCircles(
    data = pizzaria_RJ,
    radius = 1000,
    fillOpacity = 0.3,
    color = "green",
    popup = ~paste0(
      "<b>Endereço: </b>", "Rua João Paulo I", ", ", "s/n", "<br>",
      "<b>Bairro: </b>", "Estácio", "<br>",
      "<b>Município: </b>", "Rio de Janeiro", "<br>",
      "<b>CEP: </b>", "-", "<br>",
      "<b>Área de Influência: </b>", "1km",
      sep = " "
    )
  ) %>% 
  addCircleMarkers(
    data = clientes_pizzaria_join,
    lng = ~long,
    lat = ~lat,
    radius = 5,
    fillOpacity = 0.6,
    color = "orange",
    popup = ~paste0(
      "<b>Endereço: </b>", {endereco}, ", ", numero, "<br>",
      "<b>Bairro: </b>", bairro, "<br>",
      "<b>Município: </b>", cidade, "<br>",
      "<b>CEP: </b>", cep, "<br>",
      sep = " "
    )
  ) %>% 
  addCircleMarkers(
    data = pizzaria_RJ,
    radius = 8,
    fillOpacity = 1,
    color = "green",
    popup = ~paste0(
      "<b>Endereço: </b>", "Rua João Paulo I", ", ", "s/n", "<br>",
      "<b>Bairro: </b>", "Estácio", "<br>",
      "<b>Município: </b>", "Rio de Janeiro", "<br>",
      "<b>CEP: </b>", "-", "<br>",
      sep = " "
    )
  )

Figure 6.1: Mapa de área de influência

6.3 Mapa de calor

Na figura 6.2, temos o mapa de calor, indicando onde está a maior densidade de clientes espacialmente.

mapa_interativo %>% 
  addCircleMarkers(
    data = clientes_pizzaria_join,
    lng = ~long,
    lat = ~lat,
    radius = 5,
    fillOpacity = 0.6,
    color = "orange",
    popup = ~paste0(
      "<b>Endereço: </b>", {endereco}, ", ", numero, "<br>",
      "<b>Bairro: </b>", bairro, "<br>",
      "<b>Município: </b>", cidade, "<br>",
      "<b>CEP: </b>", cep, "<br>",
      sep = " "
    )
  ) %>% 
  addCircleMarkers(
    data = pizzaria_RJ,
    radius = 8,
    fillOpacity = 1,
    color = "green",
    popup = ~paste0(
      "<b>Endereço: </b>", "Rua João Paulo I", ", ", "s/n", "<br>",
      "<b>Bairro: </b>", "Estácio", "<br>",
      "<b>Município: </b>", "Rio de Janeiro", "<br>",
      "<b>CEP: </b>", "-", "<br>",
      sep = " "
    )
  ) %>% 
  addHeatmap(
    data = clientes_coords_attr,
    # max = 0.01,
    blur = 100,
    radius = 50, #isso aqui na vdd é diametro
    # gradient = "magma"
  ) 

Figure 6.2: Mapa de calor

Informações adicionais

E-mail para contato: leonardofwink@gmail.com

GitHub: https://github.com/leonardofwink/

LinkedIn: https://www.linkedin.com/in/leonardofwink/

Citação

WINK, Leonardo Fernandes. Geomarketing na prática. Rpubs.Porto Alegre - RS, 26 jan. 2023. Disponível em: https://rpubs.com/leonardofwink/geomarketing-na-pratica.