Dando continuidade a série de posts sobre mesclagem de dados no R, hoje falarei sobre a função inner_join()
do pacote {dplyr}
. Na primeira parte, demonstrei como podemos mesclar dois ou mais conjuntos de dados usando a função left_join()
. Seguindo em frente, utilizarei os mesmos conjuntos de dados do primeiro post, que podem ser baixados clicando aqui.
Pacotes e importação dos dados
Todo esse processo inicial é semelhante ao do primeiro post: carregamos os pacotes que serão usados e em seguida importamos os dados para o R. Como já descrevi esse processo com mais detalhes na parte I, serei breve dessa vez para não se tornar repetitivo.
library(readr)
library(dplyr)
library(purrr)
O {readr}
serve para fazermos a leitura e importação dos dados para o R; o {dplyr}
serve para manejarmos os dados;
e o {purrr}
tem funções que simplificam o processo de loop e será útil entre outras coisas para importar todos os conjuntos de dados de uma única vez.
arquivos_csv <- list.files(
path = "./dados/",
pattern = "*.csv",
full.names = TRUE
)
arquivos_csv
## [1] "./dados/2010-leftjoin.csv" "./dados/2011-leftjoin.csv"
## [3] "./dados/2012-leftjoin.csv"
mortes_infantis <- map(
arquivos_csv,
read_csv2,
locale(encoding = "latin1"),
col_names = TRUE,
col_types = "ccccdi"
) %>%
set_names(2010:2012)
mortes_infantis
## $`2010`
## # A tibble: 2,386 x 6
## cod_ibge regiao uf municipio total ano
## <chr> <chr> <chr> <chr> <dbl> <int>
## 1 1100015 Norte RO Alta Floresta D'Oeste 5 2010
## 2 1100023 Norte RO Ariquemes 29 2010
## 3 1100049 Norte RO Cacoal 14 2010
## 4 1100064 Norte RO Colorado do Oeste 2 2010
## 5 1100072 Norte RO Corumbiara 1 2010
## 6 1100080 Norte RO Costa Marques 1 2010
## 7 1100098 Norte RO Espigão D'Oeste 3 2010
## 8 1100106 Norte RO Guajará-Mirim 13 2010
## 9 1100114 Norte RO Jaru 8 2010
## 10 1100122 Norte RO Ji-Paraná 31 2010
## # ... with 2,376 more rows
##
## $`2011`
## # A tibble: 2,384 x 6
## cod_ibge regiao uf municipio total ano
## <chr> <chr> <chr> <chr> <dbl> <int>
## 1 1100015 Norte RO Alta Floresta D'Oeste 3 2011
## 2 1100023 Norte RO Ariquemes 15 2011
## 3 1100049 Norte RO Cacoal 14 2011
## 4 1100056 Norte RO Cerejeiras 2 2011
## 5 1100072 Norte RO Corumbiara 1 2011
## 6 1100080 Norte RO Costa Marques 1 2011
## 7 1100098 Norte RO Espigão D'Oeste 6 2011
## 8 1100106 Norte RO Guajará-Mirim 5 2011
## 9 1100114 Norte RO Jaru 2 2011
## 10 1100122 Norte RO Ji-Paraná 10 2011
## # ... with 2,374 more rows
##
## $`2012`
## # A tibble: 2,313 x 6
## cod_ibge regiao uf municipio total ano
## <chr> <chr> <chr> <chr> <dbl> <int>
## 1 1100015 Norte RO Alta Floresta D'Oeste 1 2012
## 2 1100023 Norte RO Ariquemes 14 2012
## 3 1100049 Norte RO Cacoal 12 2012
## 4 1100056 Norte RO Cerejeiras 3 2012
## 5 1100064 Norte RO Colorado do Oeste 2 2012
## 6 1100080 Norte RO Costa Marques 2 2012
## 7 1100098 Norte RO Espigão D'Oeste 1 2012
## 8 1100106 Norte RO Guajará-Mirim 3 2012
## 9 1100114 Norte RO Jaru 6 2012
## 10 1100122 Norte RO Ji-Paraná 10 2012
## # ... with 2,303 more rows
A função list.files()
lista todos os arquivos csv contidos na pasta "dados/"
e nos retorna um vetor, já a função purrr::map()
itera sobre cada elemento desse vetor e aplica a função readr::read_csv2()
em cada um deles nos retornando uma lista de data frames.
dplyr::inner_join()
A função inner_join()
possui os mesmos argumentos do left_join()
:
inner_join(x, y, by = NULL, copy = FALSE, suffix = c(".x", ".y"), ...)
A diferença entre as duas é que, enquanto left_join()
nos retorna todas as linhas de x
, todas as colunas de x
e y
e preenche com NA
as linhas em x
que não possuem uma correspondente em y
, inner_join()
retorna somente as linhas de x
onde existem valores correpondentes em y
, ou seja, teremos como retorno um novo conjunto de dados em que estarão presentes somente as linhas que são comuns entre ambos. Além disso, inner_join()
também retorna todas as colunas de x
e y
.
Novamente, x
e y
correspondem aos conjuntos de dados que desejamos unir, enquanto by
recebe o nome da coluna (ou colunas, pode ser mais de uma) que servirá como chave para unir os dados. by = "nome da coluna"
é usado quando o nome da coluna é o mesmo em ambos os conjuntos de dados e by = c("nome da coluna em x" = "nome da coluna em y")
quando os nomes das colunas são diferentes. Como sempre, exemplos podem nos ajudar a entender melhor como as coisas acontecem.
Exemplo
Admita que tenhamos dois conjuntos de dados com o desempenho dos alunos do ensino fundamental de determinada escola do Brasil em dois anos diferentes: 2019 e 2020. E desejamos unir esses dados trazendo somente os alunos que estão presentes nos dois anos para verificar se houve uma melhora ou piora no desempenho de cada um deles de um ano para o outro.
alunos_2019 <- tibble::tribble(
~ matricula, ~ nome, ~ media,
10, "João", 7.1,
11, "José", 8.5,
12, "Maria", 5.2
)
alunos_2020 <- tibble::tribble(
~ matricula, ~ nome, ~ media,
9, "Joana", 8.0,
10, "João", 9.0,
11, "José", 5.4,
12, "Maria", 8.7,
13, "Ana", 10.0,
14, "Francisco", 4.3
)
Podemos utilizar a coluna com o número da matrícula como chave para unir os dados passando-a para o argumento by
:
alunos_2019 %>%
inner_join(alunos_2020, by = "matricula")
## # A tibble: 3 x 5
## matricula nome.x media.x nome.y media.y
## <dbl> <chr> <dbl> <chr> <dbl>
## 1 10 João 7.1 João 9
## 2 11 José 8.5 José 5.4
## 3 12 Maria 5.2 Maria 8.7
Repare que, como as colunas nome
e media
existem nas duas tabelas, é acrescentado automaticamente um sufixo em cada uma delas para evitar nomes de colunas repetidos. Nesse caso, .x
é o sufixo referente as colunas do data frame alunos_2019
e .y
é o sufixo referente as colunas de alunos_2020
. É possível alterar esses nomes passando os sufixos que desejamos acrescentar para o argumento suffix
. Dessa forma:
alunos_2019 %>%
inner_join(alunos_2020, by = "matricula", suffix = c("_2019", "_2020"))
## # A tibble: 3 x 5
## matricula nome_2019 media_2019 nome_2020 media_2020
## <dbl> <chr> <dbl> <chr> <dbl>
## 1 10 João 7.1 João 9
## 2 11 José 8.5 José 5.4
## 3 12 Maria 5.2 Maria 8.7
Note que a ordem que os sufixos são passados importa! Como os dados referentes ao ano de 2019 vem primeiro, passamos primeiro o sufixo de 2019 e depois o de 2020. Se fosse ao contrário, seria assim:
alunos_2020 %>%
inner_join(alunos_2019, by = "matricula", suffix = c("_2020", "_2019"))
## # A tibble: 3 x 5
## matricula nome_2020 media_2020 nome_2019 media_2019
## <dbl> <chr> <dbl> <chr> <dbl>
## 1 10 João 9 João 7.1
## 2 11 José 5.4 José 8.5
## 3 12 Maria 8.7 Maria 5.2
Juntando os conjuntos de dados
Feito essa explicação, agora vamos juntar os conjuntos de dados que foram importados lá no ínicio mantendo somente os municípios que estão presentes em todos os anos (2010, 2011 e 2012). Como chave para unir os dados utilizarei a coluna cod_ibge
, que possui o código IBGE de 7 digítos para cada município.
Uma das maneiras de unir nossos dados é assim:
mortes_infantis_inner <- mortes_infantis[["2010"]] %>%
inner_join(
mortes_infantis[["2011"]],
by = "cod_ibge",
suffix = c("_2010", "_2011")
) %>%
inner_join(mortes_infantis[["2012"]], by = "cod_ibge")
Ok. Parece bom. Mas e se pudéssemos simplificar isso deixando nosso código mais limpo e legível? Com purrr::reduce()
isso é possível!
mortes_infantis_inner <- reduce(
mortes_infantis,
inner_join,
by = "cod_ibge",
suffix = c("_2010", "_2011")
)
Para a função reduce()
passamos a lista que contém os data frames que queremos juntar e a função inner_join()
com os seus devidos argumentos. Simples assim! É incrível o que conseguimos fazer utilizando o {purrr}
.
Agora, temos um novo conjunto de dados que contém somente os municípios que estavam presentes em todos os anos:
glimpse(mortes_infantis_inner)
## Rows: 1,447
## Columns: 16
## $ cod_ibge <chr> "1100015", "1100023", "1100049", "1100080", "1100098", ~
## $ regiao_2010 <chr> "Norte", "Norte", "Norte", "Norte", "Norte", "Norte", "~
## $ uf_2010 <chr> "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO", "~
## $ municipio_2010 <chr> "Alta Floresta D'Oeste", "Ariquemes", "Cacoal", "Costa ~
## $ total_2010 <dbl> 5, 29, 14, 1, 3, 13, 8, 31, 3, 7, 307, 2, 2, 25, 2, 1, ~
## $ ano_2010 <int> 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2~
## $ regiao_2011 <chr> "Norte", "Norte", "Norte", "Norte", "Norte", "Norte", "~
## $ uf_2011 <chr> "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO", "~
## $ municipio_2011 <chr> "Alta Floresta D'Oeste", "Ariquemes", "Cacoal", "Costa ~
## $ total_2011 <dbl> 3, 15, 14, 1, 6, 5, 2, 10, 6, 6, 254, 1, 4, 21, 3, 1, 7~
## $ ano_2011 <int> 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2011, 2~
## $ regiao <chr> "Norte", "Norte", "Norte", "Norte", "Norte", "Norte", "~
## $ uf <chr> "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO", "~
## $ municipio <chr> "Alta Floresta D'Oeste", "Ariquemes", "Cacoal", "Costa ~
## $ total <dbl> 1, 14, 12, 2, 1, 3, 6, 10, 3, 3, 270, 1, 3, 26, 2, 2, 7~
## $ ano <int> 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2012, 2~
Como esperado, foi acrescentado o sufixo _2010
para as colunas do ano 2010 e _2011
para as colunas do ano 2011. As últimas 5 colunas sem sufixo, são referentes ao ano de 2012. Note que agora temos diversas colunas com região, UF e município, no entanto, como sei que o conteúdo é o mesmo para todas elas, podemos jogar fora essas colunas repetidas:
mortes_infantis_inner <- mortes_infantis_inner %>%
select(
!(contains(c("regiao", "uf", "municipio", "ano")) &
ends_with(c("_2010", "_2011"))),
-ano
) %>%
rename(total_2012 = total) %>%
relocate(c(regiao, uf, municipio), .after = cod_ibge)
Para remover todas as colunas desejadas, peço para a função select()
do {dplyr}
selecionar somente as colunas que simultaneamente não contenham em seus nomes as palavras "regiao"
, "uf"
, "municipio"
ou "ano"
e termine com os sufixos "_2010"
ou "_2011"
. Após isso, apenas renomeio e reposiciono as outras colunas com dplyr::rename()
e dplyr::relocate()
, respectivamente.
glimpse(mortes_infantis_inner)
## Rows: 1,447
## Columns: 7
## $ cod_ibge <chr> "1100015", "1100023", "1100049", "1100080", "1100098", "110~
## $ regiao <chr> "Norte", "Norte", "Norte", "Norte", "Norte", "Norte", "Nort~
## $ uf <chr> "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO", "RO",~
## $ municipio <chr> "Alta Floresta D'Oeste", "Ariquemes", "Cacoal", "Costa Marq~
## $ total_2010 <dbl> 5, 29, 14, 1, 3, 13, 8, 31, 3, 7, 307, 2, 2, 25, 2, 1, 5, 4~
## $ total_2011 <dbl> 3, 15, 14, 1, 6, 5, 2, 10, 6, 6, 254, 1, 4, 21, 3, 1, 7, 39~
## $ total_2012 <dbl> 1, 14, 12, 2, 1, 3, 6, 10, 3, 3, 270, 1, 3, 26, 2, 2, 7, 37~
Concluído todo o processo, agora é só exportar os dados:
write.csv2(
mortes_infantis_inner,
file = "./dados-inner/mortes_infantis_inner.csv",
row.names = FALSE
)
É isso. Finalizo por aqui. O código completo desse post está disponível no meu GitHub.
Até a próxima 👋.