Até agora, partimos de uma única base de dados e fizemos diversas transformações: mudamos de nomes de variáveis, computamos novas variáveis, selecionamos linhas e colunas, agrupamos e ordenamos. A partir de agora vamos aprender a combinar data frames diferentes usando as funções do tipo join do pacote dplyr do tidyverse. Vamos começar abrindo os pacotes necessários:
library(tidyverse)
No lugar de uma amostra dos dados, como no tutorial anterior, utilizaremos no começo deste tutorial os dados de pagamento do Programa Bolsa Família em um município de pequeno porte: Borá, cidade do interior de São Paulo.
Vamos começar importando os dados do mês de janeiro de cada um dos anos para o município de Borá, que foram extraídos dos dados baixados no Portal da Transparência.
Se você estiver com tempo em sala de aula, faça como exercício a construção desses dados (em vez de baixá-los do repositório do curso). A recomendação é baixar os dados manualmente no Portal da Transparência, abrí-los com a função fread (projetado para grandes conjuntos de dados) do pacote data.table e selecionar as linhas de Borá com a função filter do pacote dplyr. Se não estiver com tempo, use o código abaixo.
pagamentos11 <- read_delim("https://raw.githubusercontent.com/leobarone/FLS6397/master/data/pagamentos11.csv", delim = ";", col_names = T)
pagamentos17 <- read_delim("https://raw.githubusercontent.com/leobarone/FLS6397/master/data/pagamentos17.csv", delim = ";", col_names = T)
Veja que os dados são semelhantes e têm a mesma estrutura. Esperamos, entretanto, que haja variação entre os anos e que os beneficiários e os valores pagos não sejam os mesmos, seja por que as pessoas entraram e saíram do programa ao longo do tempo, seja por que mudaram de município, seja por que os valores sofreram alteração em virtude de reajuste e mudanças na estrutura das famílias.
Como descobrir tais mudanças? Como saber quem estava em 2011 e também em 2017? Como calcular a variação dos valores para cada beneficiário? Não podemos responder a nenhuma dessas perguntas enquanto os dados estão isolados em tabelas separadas - precisamos juntá-las.
Examine as bases de dados “pagamentos11” e “pagamentos17” antes de começarmos a trabalhar com elas. Faça também as seguintes alterações:
# 2011
pagamentos11 <- pagamentos11 %>%
rename(nis = `NIS Favorecido`, nome = `Nome Favorecido`, valor = `Valor Parcela`) %>%
mutate(valor = gsub(",", "", valor), valor = as.numeric(valor)) %>%
select(nis, nome, valor)
# 2017
pagamentos17 <- pagamentos17 %>%
rename(nis = `NIS Favorecido`, nome = `Nome Favorecido`, valor = `Valor Parcela`) %>%
mutate(valor = gsub(",", "", valor), valor = as.numeric(valor)) %>%
select(nis, nome, valor)
Tendo as bases preparadas e sabendo que os beneficiários variam entre os anos, podemos começar a “juntá-las”.
O elemento essencial dos “joins”, ou seja, das combinações de bases de dados, é que haja (ao menos) uma variável que associe observações em uma base com observações em outras. Algumas variáveis costumam ser candidatas naturais para tal tarefa: CPF, NIS e Título de Eleitor, para indíviduos, Código de município e UF para unidades político-administrativas, e dia, mês e ano para unidades de tempo. Mas, veremos adiante, podemos ser criativos e utilizar diversas outras “chaves” para conectar tabelas. O identificador que temos disponível em nossos dados é o NIS.
“Letf join” e “right join” são os nomes dados às combinações que mantém todas as linhas de uma das bases de dados, mesmo sem haver correspondente na outra tabela, e inclui apenas os dados da segunda base que encontram correspondência na primeira tabela.
Vamos operar os dois “joins” e ver o que ocorre. Primeiro, “left join”:
comb_left <- pagamentos11 %>% left_join(pagamentos17, by = "nis")
Veja que informamos ao R que a variável que conecta as tabelas- a chave - é “nis” informando o parâmetro “by”.
Quantas linhas resultaram da combinação? Exatamente o mesmo número de linhas de “pagamentos11”. Use o View para ver o resultado.
Note que há duas variáveis de valor, uma com final “.x” e outra com o final “.y”. Isso ocorre por que as duas bases tem os mesmos nomes de variáveis. “.x” significa que a variável veio da primeira tabela do “join” e “.y”, da segunda. O mesmo ocorre com a variável “nome”. Vamos aproveitar e renomeá-las:
comb_left <- comb_left %>% rename(valor11 = valor.x, nome11 = nome.x,
valor17 = valor.y, nome17 = nome.y)
Note que em diversas observações o valor e o nome para 2017 contém “NA”, que é o símbolo do R para “missing values”. O que isso significa? Significa que aquelas observações existiam em 2011, mas não em 2017. Ao não encontrar correspondência, o R manteve a observação (e os dados ‘da esquerda’), mas não inseriu nenhum valor nas variáveis ‘da direita’.
Se o número de linhas da combinação é o mesmo de 2011, onde estão as observações de 2017 que faltam? Não foram incluídas. O “left join” garante que todas as observações de 2011 sejam mantidas, mesmo sem correspondência, mas exclui todas as observações de 2017 que não encontrem par em 2011.
Vamos deixar de lado rapidamente esta primeira combinação e realizar o “right join” das mesmas tabelas:
comb_right <- pagamentos11 %>% right_join(pagamentos17, by = "nis")
Novamente, vamos renomear as variáveis:
comb_right <- comb_right %>% rename(valor11 = valor.x, nome11 = nome.x,
valor17 = valor.y, nome17 = nome.y)
Veja que agora há “missing values” nos valores e nomes de 2011. O “right join” preserva todas as observações de 2017, mesmo sem correspondência em 2011, e não inclui nenhum de 2011 que não encontre correspondência.
Note que “left” e “right” são exatamente a mesma operação, mas com as tabelas em posições (x e y, 1a e 2a, etc) invertidas.
E se quisermos apenas as observações que estão, com certeza, em ambos os anos? Usamos o “inner join”. Veja o resultado (já renomeado):
comb_inner <- pagamentos11 %>% inner_join(pagamentos17, by = "nis") %>%
rename(valor11 = valor.x, nome11 = nome.x,
valor17 = valor.y, nome17 = nome.y)
Agora, não há “missing values”. Quantas linhas resultaram da combinação? Permanecem na combinação apenas os casos que estão presentes em ambas tabelas.
Finalmente, o “full join” adota o critério oposto: inclui todas as observações de ambos tabelas, não importando se há ou não correspondência, e insere “missing values” nos dois lados onde não há correspondência:
comb_full <- pagamentos11 %>% full_join(pagamentos17, by = "nis") %>%
rename(valor11 = valor.x, nome11 = nome.x,
valor17 = valor.y, nome17 = nome.y)
Os quatro tipos de “join” apresentados anteriormente cobrem a totalidade de situações de combinação entre tabelas a partir de um “chave”, ou seja, de um índice ou variável que permita estabelecer a relação entre elas.
Há, porém, dois outros tipos de “joins” disponíveis no R bastante úteis.
Se quisermos trabalhar apenas em uma única base de dados, por exemplo, pagamentos11, mas queremos saber quais das observações de 2011 também estão na tabela de 2017, então utilizamos a função semi_join. O resultado será semelhante ao da aplicação de inner_join, mas sem que novas colunas com os dados de 2017 tenham sido criadas:
comb_semi <- pagamentos11 %>% semi_join(pagamentos17, by = "nis")
Quantas linhas resultaram? Compare com o número de observações que aparecem para os dois anos nos resultados de left_join.
Por fim, anti_join, tem comportamento semelhante a semi_join, mas, em vez de retornar as observações de 2011 que têm correspondência em 2017, retorna as que nâo têm par em 2017:
comb_anti <- pagamentos11 %>% anti_join(pagamentos17, by = "nis")
Respire fundo e gaste um tempo refletindo sobre os “joins”. Você acabou de aprender como operar bancos de dados relacionais e pode parecer bastante difícil num primeiro momento.
Vamos supor que queremos calcular os valores total, médio, máximo, etc, por município e, a seguir, apresentar esses valores como colunas para cada observação. Uma maneira eficiente de fazer isso é usando a combinação de tabelas. Vamos ver como voltando ao exemplo da amostra de saques do Programa Bolsa Família em 2017.
Abra a base de dados e faça as transformações necessárias (renomear variáveis e transformar a variável valor em numérica) antes de prosseguir. Tente fazê-lo sem olhar a resposta abaixo.
saques_amostra_201701 <- read_delim("https://raw.githubusercontent.com/leobarone/FLS6397/master/data/saques_amostra_201701.csv", delim = ";", col_names = T)
saques_amostra_201701 <- saques_amostra_201701 %>%
rename(uf = UF,
munic = `Nome Município`,
cod_munic = `Código SIAFI Município`,
nome = `Nome Favorecido`,
valor = `Valor Parcela`,
mes = `Mês Competência`,
data_saque =`Data do Saque`) %>%
select(uf, munic, cod_munic, nome, valor, mes, data_saque) %>%
mutate(valor_num = as.numeric(gsub(",", "", valor)))
Para criar agregações cumulativas, vamos construir uma tabela agrupada por município usando group_by e summarise:
valores_munic <- saques_amostra_201701 %>%
group_by(cod_munic) %>%
summarise(contagem = n(),
soma = sum(valor_num),
media = mean(valor_num),
mediana = median(valor_num),
desvio = sd(valor_num),
minimo = min(valor_num),
maximo = max(valor_num))
Note que agora temos dois data frames, o original e “valores_munic”, que pode ser combinados utilizando a variável “cod_munic”. Usando left_join podemos levar as colunas da nova tabela à base de dados original:
saques_amostra_201701 <- saques_amostra_201701 %>%
left_join(valores_munic, by = "cod_munic")
Use View para observar que a base de dados original tem agora 7 novas colunas com informações agregadas por município (e que, portanto, se repetem para observações de um mesmo município).
Na verdade, na prática não precisamos criar a tabela de resumo separada e juntá-la novamente; o mesmo resultado pode ser obtido com mutate no lugar de summarize no pedido original:
valores_munic_mutate <- saques_amostra_201701 %>%
group_by(cod_munic) %>%
mutate(contagem = n(),
soma = sum(valor_num),
media = mean(valor_num),
mediana = median(valor_num),
desvio = sd(valor_num),
minimo = min(valor_num),
maximo = max(valor_num))