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)
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,]
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)
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)
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
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