library(raster)
## Loading required package: sp
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:raster':
## 
##     intersect, select, union
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(stringdist)
library(maps)
library(ggplot2)
library(ggrepel)
library(ggmap)
library(mapdata)
library(knitr)
opts_chunk$set(echo = TRUE,
               message = TRUE,
               cache = TRUE,
               dev="png", 
               dev.args=list(type="cairo"),
               dpi=96)

Lendo

As linhas a partir de 516 (fora o header) estão vazias e vão ser excluídas.

stp <- read.csv("igor.csv", strip.white = TRUE)

stp <- stp[1:516,]

Nomes de cidades e caracteres

cidades <- stp$Cidade %>% unique %>% print
##  [1] são paulo               São Paulo              
##  [3] Recife                   Rio de Janeiro          
##  [5] recife                   Maceió                 
##  [7] Fortaleza                Olinda                  
##  [9] Recfie                   RECIFE                  
## [11] Brasilia                 jaboatao                
## [13] Brasília                Itabaiana               
## [15] Sao Paulo                Belém                  
## [17] Campinas                 Londrina                
## [19] osasco                   Sta de Parnaiba         
## [21] Ouricuri                 Jaboatão dos Guararapes
## [23] Natal                    Feira de Santana        
## [25] olinda                   Serra Talhada           
## [27] Triunfo-PE               Abreu e Lima            
## [29] Jaboatao dos Guararapes  João Pessoa            
## [31] Aracaju                  Cambridge               
## [33] SÃO PAULO               Teresiba                
## [35] Santos                   Belo Horizonte          
## [37] Paulista                 jaboatão dos guararapes
## [39] RIO DE JANEIRO           Camaragibe              
## [41] Cruzeiro do Sul          RJ                      
## [43] Macaé                   OLINDA                  
## [45] São Carlos              sao carlos              
## [47] Porto Alegre             cha grande              
## [49] petrolina               
## 50 Levels:  Abreu e Lima Aracaju Belém Belo Horizonte ... Triunfo-PE

Os nomes das cidades apresentam problema na representação dos caracteres e na standardização. Há grafias diferentes (por exemplo, “Recfie” e “Recife”), não há uniformidade no uso de maiúsculas e há caracteres especiais mal interpretados.

Aparentemente, houve problema na exportação do texto e os caracteres foram lidos usando a codificação errada, por exemplo: “Macaé”" está grafado “Macaé”. Como não sei nem o character set usado para escrever os nomes nem o usado na leitura, vou fazer uma busca para tentar encontrar uma conversão adequada entre character sets.

Selecionamos quatro problemas de conversão de caracteres (é, ã, í, ó) e vamos passar eles entre todas as possibilidades de conversão de character sets possíveis em R. Antes, vamos ver a quantidade de operações que serão realizadas.

conversoes <- length(iconvlist())^2*4

pares.possiveis <- length(iconvlist())^2 %>%
  as.integer %>%
  format(scientific = FALSE,
         big.mark = ".",
         decimal.mark = ",")


conversoes.pretty <- conversoes %>%
  as.integer %>%
  format(scientific = FALSE,
         big.mark = ".",
         decimal.mark = ",")

O oferece 374 grupos de caracteres, totalizando 139.876 conversões possíveis. Como vamos analisar quatro problemas, serão feitas no total 559.504 conversões. O tempo e esforço computacional necessários para realizar estas operações é considerável.

Vamos distribuir os resultados das conversões em quatro matrizes com o nome de cidades que contém os caracteres mal interpretados.

start.time <- Sys.time()

macae <- matrix(nrow = length(iconvlist()),
            ncol = length(iconvlist()))

sao <- matrix(nrow = length(iconvlist()),
            ncol = length(iconvlist()))

brasilia <- matrix(nrow = length(iconvlist()),
            ncol = length(iconvlist()))

maceio <- matrix(nrow = length(iconvlist()),
            ncol = length(iconvlist()))

for(r in 1:length(iconvlist())){
  for(c in 1:length(iconvlist())){
    
  tryCatch( {macae[r,c] <- iconv(x = "é",
                              from = iconvlist()[r],
                              to = iconvlist()[c])},
           error=function(e){})
  }
}

for(r in 1:length(iconvlist())){
  for(c in 1:length(iconvlist())){
    
    tryCatch( {sao[r,c] <- iconv(x = "ã",
                               from = iconvlist()[r],
                               to = iconvlist()[c])},
              error=function(e){})
  }
}

for(r in 1:length(iconvlist())){
  for(c in 1:length(iconvlist())){
    
    tryCatch( {brasilia[r,c] <- iconv(x = cidades[13] %>% as.character,
                               from = iconvlist()[r],
                               to = iconvlist()[c])},
              error=function(e){})
  }
}

for(r in 1:length(iconvlist())){
  for(c in 1:length(iconvlist())){
    
    tryCatch( {maceio[r,c] <- iconv(x = "ó",
                               from = iconvlist()[r],
                               to = iconvlist()[c])},
              error=function(e){})
  }
}

end.time <- Sys.time()

tempo.conversao <- difftime(end.time, start.time, units = "mins") %>% as.numeric

tempo.conversao.pretty <- tempo.conversao %>%
  as.numeric() %>%
  round(2) %>%
  format(scientific = FALSE,
         big.mark = ".",
         decimal.mark = ",")

velocidade <- conversoes/tempo.conversao
velocidade.pretty <- velocidade %>%
  round(2) %>%
  format(scientific = FALSE,
         big.mark = ".",
         decimal.mark = ",")  

Todas essas operações de conversão duraram 31,38 minutos. Já que foram feitas 559.504 conversões, a velocidade foi de 17.830,06 conversões por minuto.

Agora, vamos analisar quais conversões deram os resultados esperados nos diferentes casos.

macae.index <- grep("^é$", macae)
sao.index <- grep("^ã$", sao)
brasilia.index <- grep("^Brasília$", brasilia)
maceio.index <- grep("^ó$", maceio)

match <- c(macae.index, sao.index, brasilia.index, maceio.index) %>%
  unique %>%
  cbind("macaé", "são", "brasília", "maceió", "to", "from")

colnames(match) <- c("index", "macae", "sao", "brasilia", "maceio", "to", "from")

for(i in 1:nrow(match)){
  if(match[i,1] %in% macae.index){
    match[i,2] <- TRUE
  } else {
    match[i,2] <- FALSE
  }
  
  if(match[i,1] %in% sao.index){
    match[i,3] <- TRUE
  } else {
    match[i,3] <- FALSE
  } 

  if(match[i,1] %in% brasilia.index){
    match[i,4] <- TRUE
  } else {
    match[i,4] <- FALSE
  } 
  
  if(match[i,1] %in% maceio.index){
    match[i,5] <- TRUE
  } else {
    match[i,5] <- FALSE
  } 
  
  match[i,6] <- iconvlist()[match[i,1] %>%
                              as.numeric %/%
                              length(iconvlist())]
  match[i,7] <- iconvlist()[match[i,1] %>% as.numeric %% length(iconvlist())]
}

match <- match %>%
  as.data.frame %>%
  filter(macae == TRUE & sao == TRUE & brasilia == TRUE & maceio == TRUE)

Há 93 conversões possíveis que resolvem os quatro problemas de conversão. Vamos testar a conversão de UTF-8 para iso_8859-1.

cidades.std <- iconv(cidades, from = "UTF-8", to = "iso_8859-1") %>% print
##  [1] "são paulo"               "São Paulo"              
##  [3] "Recife"                  "Rio de Janeiro"         
##  [5] "recife"                  "Maceió"                 
##  [7] "Fortaleza"               "Olinda"                 
##  [9] "Recfie"                  "RECIFE"                 
## [11] "Brasilia"                "jaboatao"               
## [13] "Brasília"                "Itabaiana"              
## [15] "Sao Paulo"               "Belém"                  
## [17] "Campinas"                "Londrina"               
## [19] "osasco"                  "Sta de Parnaiba"        
## [21] "Ouricuri"                "Jaboatão dos Guararapes"
## [23] "Natal"                   "Feira de Santana"       
## [25] "olinda"                  "Serra Talhada"          
## [27] "Triunfo-PE"              "Abreu e Lima"           
## [29] "Jaboatao dos Guararapes" "João Pessoa"            
## [31] "Aracaju"                 "Cambridge"              
## [33] "SÃO PAULO"               "Teresiba"               
## [35] "Santos"                  "Belo Horizonte"         
## [37] "Paulista"                "jaboatão dos guararapes"
## [39] "RIO DE JANEIRO"          "Camaragibe"             
## [41] "Cruzeiro do Sul"         "RJ"                     
## [43] "Macaé"                   "OLINDA"                 
## [45] "São Carlos"              "sao carlos"             
## [47] "Porto Alegre"            "cha grande"             
## [49] "petrolina"

Funcionou! Vamos corrigir esse e outros problemas para deixar o data set mais limpinho. Vamos: 1. mudar o nome das colunas (os caracteres estranhos introduzidos atrapalham o código);
2. converter os caracteres nos campos Cidade e Projeto;
3. eliminar espaços desnecessários;
4. pôr tudo em minúscula.

names(stp) <- c("Projeto", "Cidade", "UF", "ID.de.Transacao", "Status", "Valor.Total", "Taxa.de.Transacao", "Valor.Liquido", "Data.da.Doacao")

stp$Projeto <- iconv(stp$Projeto, from = "UTF-8", to = "iso_8859-1")

stp$Cidade <- stp$Cidade %>%
  iconv(from = "UTF-8", to = "iso_8859-1") %>%
  tolower %>%
  gsub(pattern = "^\\s+|\\s+$", replacement = "")

cidades <- stp$Cidade %>% unique

Para continuar a padronização dos nomes de cidades, vamos calcular as distâncias entre todas as sequências de caracteres representando ocorrênciais individuais de nomes de cidades, com a ajuda da função stringdist. Depois, vamos criar grupos contendo palavras cujo score de distância entre si é inferior a 3. Isto deve agrupar todas as sequências de caracteres similares.

cidades.group <- vector(mode = "list", length = length(cidades))

for(i in 1:length(cidades)){
  
  dist <- stringdist(cidades, cidades[i])
  
  misspell <- which(dist < 3)
  
  cidades.group[[i]] <- c(cidades[misspell],
                          cidades[i]) %>%
    unique
}

cidades.group <- cidades.group %>% unique

Há 36 cidades diferentes, algumas com grafias diferentes. Vou mudar manualmente cada uma. (Provavelmente, se eu tivesse mudado manualmente desde o começo teria sido muito mais fácil e rápido, mas enfim).

stp$Cidade <- stp$Cidade %>%
  gsub(pattern = "ã", replacement = "a") %>%
  gsub(pattern = "recfie", replacement = "recife") %>%
  gsub(pattern = "í", replacement = "i") %>%
  gsub(pattern = "^jaboatao$", replacement = "jaboatao dos guararapes") %>%
  gsub(pattern = "é", replacement = "e") %>%
  gsub(pattern = "ó", replacement = "o") %>%
  gsub(pattern = "\\<sta\\>", replacement = "santana") %>%
  gsub(pattern = "triunfo-pe", replacement = "triunfo") %>%
  gsub(pattern = "teresiba", replacement = "teresina") %>%
  gsub(pattern = "rj", replacement = "rio de janeiro")

Vamos também converter os valores nas colunas referentes a valores monetários. Elas estão em formato de fator; vamos:
1. transformá-las em caracteres;
2. eliminar os caracteres não-numéricos;
3. transformar em valores numéricos.

stp[,6:8] <- stp[,6:8] %>%
  lapply(as.character) %>%
  lapply(gsub, pattern = ",| |R\\$", replacement = "") %>%
  sapply(FUN = as.numeric)

Encontrando cidades

Vamos identificar matches entre nossos nomes de cidades e as cidades presentes na base de dados *maps::world.cities*. Vamos criar uma tabela mostrando essas equivalências.

cidades_brasileiras <- world.cities %>%
  filter(country.etc == "Brazil") %>%
  select(name) %>%
  `[[` (1) %>%
  tolower

cidades.doadoras <- stp$Cidade %>% unique

cidade.match <- rep("?", length(cidades.doadoras)) %>% as.list

for(i in 1:length(cidades.doadoras)){
  
   tryCatch({matches <- cidades.doadoras[i] %>%
    agrep(x = cidades_brasileiras, value = T)},
    error=function(e){})
 
  if(length(matches) == 0) {
    cidade.match[i] <- NA
  
  } else if(length(matches) == 1){
    cidade.match[i] <- matches
  
  } else if(length(matches) > 1){
    dist <- stringdist(cidades.doadoras[i], matches)
    lowest.dist <- which(dist == min(dist))
  
    if(length(lowest.dist) > 1){
     cidades.doadoras[[i]] <- matches[lowest.dist]
      
    } else if(length(lowest.dist) == 1){
      cidade.match[i] <- matches[lowest.dist]
    }}}

match.table <- cidade.match %>%
  unlist %>%
  cbind(cidades.doadoras, NA) %>%
  as.data.frame %>%
  `names<-`(c("match", "cidades.doadoras", "index")) %>%
  transmute(match = as.character(match),
            cidades.doadoras = as.character(cidades.doadoras),
            index = as.numeric(index))

for(i in 1:nrow(match.table)){
  if(!match.table$match[i] %>% is.na){
    match.table$index[i] <- match.table$match[i] %>%
      match(cidades_brasileiras)
  }
}

Antes de levar as coordenadas para o mapa, vamos ver quais as cidades para as quais não encontramos equivalente entre as cidades brasileiras de world.cities.

match.table %>%
  filter(is.na(index))
##   match        cidades.doadoras index
## 1  <NA> jaboatao dos guararapes    NA
## 2  <NA>                 triunfo    NA
## 3  <NA>               cambridge    NA
## 4  <NA>              cha grande    NA

Cambridge é uma cidade do exterior. Vamos deixá-la fora do mapa por enquanto. Uma pesquisa mais detalhada revela que Jaboatão dos Guararapes está registrado como “Jaboatao”, portanto, pode ser incluído na tabela.

match.table$match[match("jaboatao dos guararapes",
                        match.table$cidades.doadoras)] <- "jaboatao"

match.table$index[match("jaboatao dos guararapes",
                        match.table$cidades.doadoras)] <- match("jaboatao",
                                                     cidades_brasileiras)

As cidades restantes não constam em world.cities. Vamos procurar por fora informações suficientes sobre essas cidades para criar objetos mapeáveis.

modelo <- world.cities %>% filter(name == "Recife")

cha.grande <- modelo
triunfo <- modelo

cha.grande[,1:6] <- list("Cha Grande", "Brazil", 21274, -8.24, -35.46, 0)

triunfo[,1:6] <- list("Triunfo", "Brazil", 15264, -7.84, -38.10, 0)

Mapeando cidades e valores

Vamos pegar as informações geográficas de cada cidade e criar um novo objeto com elas.

cidades.doadoras.deluxe.edition <- matrix(NA, nrow = nrow(match.table),
                                          ncol = ncol(modelo))

colnames(cidades.doadoras.deluxe.edition) <- names(modelo)

world.cities.br <- world.cities %>%
  filter(country.etc == "Brazil")

for(i in 1:nrow(match.table)){
 a <- world.cities.br[match.table$index[i],] %>% as.list
 
 if(match.table$cidades.doadoras[i] == "cha grande"){
   a <- cha.grande %>% as.list
   
   } else if(match.table$cidades.doadoras[i] == "triunfo"){
     a <- triunfo %>% as.list
     }
 
 for(j in 1:length(a)){
  cidades.doadoras.deluxe.edition[i, j] <- a[[j]]
   
 }
} 

cidades.mapa <- cidades.doadoras.deluxe.edition %>%
  na.omit %>%
  as.data.frame

cidades.mapa$lat <- cidades.mapa$lat %>%
  paste %>%
  as.numeric

cidades.mapa$long <- cidades.mapa$long %>%
  paste %>%
  as.numeric

Vamos checar como ficam essas cidades no mapa.

br <- map_data("world", "Brazil")

ggplot() + 
  theme_dark() +
  geom_polygon(data = br,
               aes(x=long, y = lat, group = group),
               fill = "darkblue") + 
  geom_point(data = cidades.mapa,
             aes(x = long, y = lat),
             color = "yellow", size = 1) +
  coord_fixed(1.1)

Legal. Vamos agora inserir o valor total doado por cada cidade, computado a partir das doações totais (sem taxa de transação descontada), e colocar na tabela de informações de cidades.mapa. Na base world.cities, a última coluna é usada para assinalar, na forma de fator, se a cidade é uma capital. Como não vamos usar essa informação, vamos aproveitar a coluna para guarda o valor total de doação de cada cidade.

valores.cidade <-stp %>%
  group_by(Cidade) %>%
  summarise(sum(Valor.Total)) %>%
  as.data.frame

names(cidades.mapa)[6] <- "total.doado"
cidades.mapa$total.doado <- cidades.mapa$total.doado %>%
  as.numeric

for(i in 1:nrow(cidades.mapa)){
  k <- cidades.mapa$name[i] %>%
    tolower %>%
    match(valores.cidade$Cidade)

  cidades.mapa$total.doado[i] <- valores.cidade$`sum(Valor.Total)`[k]
  
  if(is.na(k)){
    print(cidades.mapa$name[i])
  }

  }
## [1] Jaboatao
## 33 Levels: Abreu e Lima Aracaju Belem Belo Horizonte ... Triunfo

Não conseguimos uma equivalência para a cidade de Jaboatão dos Guararapes porquê ela está nomeada “Jaboatao” na base de dados de world.cities. Vamos resolver este caso.

valor.jaboatao <- valores.cidade %>%
  filter(Cidade == "jaboatao dos guararapes") %>%
  select('sum(Valor.Total)') %>%
  `[[`(1)

k <- match("Jaboatao", cidades.mapa$name)


cidades.mapa$total.doado[8] <- valor.jaboatao

Vamos botar tudo no mapa; agora, o tamanho do ponto representando a cidade indica a faixa do seu valor total de doação.

stp.mapa <- ggplot() + 
  theme_dark() +
  geom_polygon(data = br,
               aes(x=long, y = lat, group = group),
               fill = "black") + 
  geom_point(data = cidades.mapa,
             aes(x = long, y = lat, size = total.doado),
             alpha = 0.7, fill = "red", shape = 21, color = "black") +
  scale_size_continuous(range = c(2, 13))

stp.mapa

Vamos dar um zoom no Sudeste, em torno de Rio de Janeiro e São Paulo.

br1 <-getData('GADM', country='BRA', level=1)
sudeste.lat <- c(-18, -25)
sudeste.long <- c(-50, -40)

cidades.SE <- cidades.mapa %>%
  filter(lat <= sudeste.lat[1],
         lat >= sudeste.lat[2],
         long >= sudeste.long[1],
         long <= sudeste.long[2])

stp.mapa.SE <- stp.mapa +
  geom_path(data = br1,
            aes(long, lat, group = group),
            color = "darkgray", linetype = 1, size = 0.7) +
  coord_map(xlim = sudeste.long, ylim = sudeste.lat) +
  geom_text_repel(data = cidades.SE,
            aes(label = name, x = long, y = lat),
            color = "white")

stp.mapa.SE

Vamso dar um zoom no Nordeste.

nordeste.lat <- c(-2, -15)
nordeste.long <- c(-45, -32)

cidades.NE <- cidades.mapa %>%
  filter(lat <= nordeste.lat[1],
         lat >= nordeste.lat[2],
         long >= nordeste.long[1],
         long <= nordeste.long[2])

stp.mapa.NE <- stp.mapa +
  geom_path(data = br1,
            aes(long, lat, group = group),
            color = "darkgray", linetype = 3, size = 0.7) +
  coord_map(xlim = nordeste.long, ylim = nordeste.lat) +
  geom_text_repel(data = cidades.NE,
            aes(label = name, x = long, y = lat),
            color = "white")

stp.mapa.NE

Vamos dar um zoom ainda maior, desta vez no entorno de Recife.

Recife.lat <- c(-7, -9)
Recife.long <- c(-36, -34.5)

cidades.Rec <- cidades.mapa %>%
  filter(lat <= Recife.lat[1],
         lat >= Recife.lat[2],
         long >= Recife.long[1],
         long <= Recife.long[2])

stp.mapa.Rec <- stp.mapa +
  geom_path(data = br1,
            aes(long, lat, group = group),
            color = "darkgray", linetype = 1, size = 0.7) +
  coord_map(xlim = Recife.long, ylim = Recife.lat) +
  geom_text_repel(data = cidades.Rec,
            aes(label = name, x = long, y = lat),
            color = "white")

stp.mapa.Rec

Observações

Informações da seção

sessionInfo()
## R version 3.4.1 (2017-06-30)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 15063)
## 
## Matrix products: default
## 
## locale:
## [1] LC_COLLATE=Portuguese_Brazil.1252  LC_CTYPE=Portuguese_Brazil.1252   
## [3] LC_MONETARY=Portuguese_Brazil.1252 LC_NUMERIC=C                      
## [5] LC_TIME=Portuguese_Brazil.1252    
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] bindrcpp_0.2       mapdata_2.2-6      ggmap_2.6.1       
##  [4] ggrepel_0.6.5      ggplot2_2.2.1      knitr_1.16        
##  [7] maps_3.2.0         stringdist_0.9.4.6 dplyr_0.7.2       
## [10] raster_2.5-8       sp_1.2-5          
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_0.12.12      compiler_3.4.1    plyr_1.8.4       
##  [4] bindr_0.1         tools_3.4.1       digest_0.6.12    
##  [7] evaluate_0.10.1   tibble_1.3.3      gtable_0.2.0     
## [10] lattice_0.20-35   pkgconfig_2.0.1   png_0.1-7        
## [13] rlang_0.1.1       mapproj_1.2-5     yaml_2.1.14      
## [16] parallel_3.4.1    proto_1.0.0       stringr_1.2.0    
## [19] RgoogleMaps_1.4.1 rprojroot_1.2     grid_3.4.1       
## [22] glue_1.1.1        R6_2.2.2          jpeg_0.1-8       
## [25] rmarkdown_1.6     reshape2_1.4.2    magrittr_1.5     
## [28] codetools_0.2-15  backports_1.1.0   scales_0.4.1     
## [31] htmltools_0.3.6   assertthat_0.2.0  geosphere_1.5-5  
## [34] colorspace_1.3-2  labeling_0.3      stringi_1.1.5    
## [37] lazyeval_0.2.0    munsell_0.4.3     rjson_0.2.15