Como comparar duas colunas pelo rstudio

É raro trabalharmos numa base de dados que já esteja, digamos, pronta. Ter de transformar valores de uma variável, excluir outros, remover ou incluir observações, criar novas variáveis é algo quase compulsório numa análise de dados. Apesar disso, poucos cursos acadêmicos e materiais especializados focam na manipulação de dados, isto é, na preparação necessária para transformar informações brutas em formatos adequados para análise.

Nossa abordagem é diferente. Assumimos que manipular e limpar bases de dados são etapas fundamentais numa análise. Também acreditamos que essas etapas não precisam consumir tanto tempo, nem exigir esforço manual repetitivo. Mostraremos neste capítulo que é possível realizar qualquer tipo de transformação em uma base com poucas ferramentas; e que, como vantagem desse método de manipulação, qualquer pessoa poderá replicar nossos procedimentos desde os menores detalhes – normalmente não documentados.

O trajeto que faremos até o fim deste capítulo também envolverá aprender a pensar numa base de dados de forma um pouco diferente do que estamos habituados. Simplesmente empilhar células numa planilha, ou criar tabelas estruturadas de forma arbitrária, não será suficiente. Isso é o que cobrimos na seção 4.1. A partir daí, aprenderemos a aplicaressa visão diretamente no R para aprender as três principais operações de manipulação de dados: cortes, modificações e agrupamentos.. Por último, cobriremos outras funções e operações úteis para quem pretende fazer análises de dados no R.

Para acompanhar o material a seguir, será necessário usar os pacotes indicados abaixo. Trabalharemos com coisas como tibbles, importação de dados e manipulação de vetores; caso não tenha familiaridade com estes tópicos, veja os capítulos 1 e 2 – consultar Wickham and Grolemund (2016) e X também podem ajudar a esclarecer algumas coisas.

install.packages("dplyr") install.packages("tidyr")

Qualquer pessoa minimamente treinada em análise de dados sabe que bases com problemas podem invalidar uma análise: se alimentamos à base valores errados, ou se operacionalizamos uma variável de forma equivocada, teremos erros de mensuração (Frankfort-Nachmias and Nachmias 2007; Wansbeek and Meijer 2008). Por outro lado, duas ou mais pessoas minimamente treinadas podem divergir sobre como estruturar uma base. Imagine, por exemplo, que tenhamos um mini-banco de dados com a quantidade de votos de alguns partidos fictícios. Uma forma razoável de organizar estes dados seria assim.

Tabela 4.1: Duas formas de organizar o mesmo banco de dados

Se repararmos bem, ambas as formas são consistentes. Cada linha ou coluna contém apenas o mesmo tipo de informação – partido ou votos – e é fácil identificar a estrutura de cada base: na primeira, cada linha indica os atributos de um único partido; já na segunda, cada coluna indica a votação do respectivo partido. Temos exemplos destes dois métodos inclusive em bases que já carregamos no capítulo 3: o arquivo exemplo.csv está organizado da primeira forma, enquanto que o arquivo populacao_brasil.xls está organizado da segunda.

Ainda que a segunda forma seja útil para diversas coisas, daqui até o final do livro trabalharemos com a primeira forma, popularizada pelo estatístico e desenvolvedor de R Hadley Wickham (2014) como tidy data. Nesta estrutura, basicamente três regras são seguidas:

    1. Cada variável é uma coluna;
    1. Cada observação é uma linha;
    1. Cada valor está numa única célula.

Em primeiro lugar, o conjunto destes princípios nos indicam que colunas são compostas por variáveis, que servem para indicar atributos de cada observação. Voltando a nossa tabela inicial, votos é uma variável, e portanto está numa coluna, porque reporta a votação de cada partido; o mesmo vale para o nome do partido, na coluna partido; e o mesmo ainda valeria para outros atributos do partido, como número de filiados(as), número de deputados(as), entre outros.

Segundo, linhas indicam os indivíduos ou observações que temos – cada um dos partidos na nossa base, como na tabela anterior. Também podemos ter observações repetidas de um mesmo indivíduo ao longo do tempo, como partido A em 2003 e partido A em 2004; neste caso, ano seria uma nova variável na nossa base. Por fim, cada atributo de cada unidade – partidos no nosso caso – estão numa única célula, o que significa que não temos informações repetidas ou ausentes.

Entre outros, esta forma de estruturação de um banco de dados traz inúmeras vantagens: em primeiro lugar, ela é intuitiva porque aloca colunas e linhas para tipos definidos de informação; em segundo lugar, porque ela é a estrutura comum demandada em análises estatísticas, especialmente em análises de painel, onde cada observação corresponde a um caso observado em diferentes momentos; por fim, porque esta estrutura facilita a estração de informações de uma base, desde variáveis individualmente até amostras da base original (Wickham 2014).

Duas operação resumem tudo o que precisamos fazer para estruturar uma base no formato tidy: espalhar, que consiste em colocar em múltiplas colunas valores que estão em apenas uma, e reunir, que é o inverso disso. Às vezes, presicaremos usar conjuntamente as duas ferramentas para estruturar uma base; em outros casos, apenas uma delas será suficiente. No R, estas ferramentas são encontradas no pacote tidyr, com a função spread servindo para espalhar valores de uma coluna e a função gather para reunir numa única coluna valores dispersos em várias.

Para aprendermos a usar ambas as funções, trabalharemos com um banco de dados sobre o número de homicídios ocorridos anualmente nos estados brasileiros entre 2000 e 2009, que é disponibilizado pelo Ipeadata8 com base nos dados originais do Datasus9. Estes dados estão na pasta de materiais complementares deste livro, numa planilha de Excel chamada homicidios_uf.xls. Para carregá-la (ver capítulo 3), usamos a função read_excel do pacote readxl.

library(readxl) homic <- read_excel("homicidios_uf.xls")

Com a função head, podemos visualizar as primeiras observações deste banco.

## # A tibble: 6 x 13 ## Sigla Codigo Estado `2000` `2001` `2002` `2003` `2004` `2005` `2006` ## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 AC 12 Acre 108 122 151 135 115 125 155 ## 2 AL 27 Alagoas 724 836 989 1041 1034 1211 1617 ## 3 AM 13 Amazonas 559 478 512 561 523 598 697 ## 4 AP 16 Amapá 155 184 181 190 173 196 203 ## 5 BA 29 Bahia 1223 1573 1735 2155 2255 2823 3276 ## 6 CE 23 Ceará 1229 1298 1443 1560 1538 1692 1793 ## # ... with 3 more variables: `2007` <dbl>, `2008` <dbl>, `2009` <dbl>

Dá para perceber claramente que a estrutura deste banco não é tidy: temos várias colunas com alguns anos (que são atributos do momento em que um indivíduo é observado), em vez de uma coluna com número de homicídios e uma coluna para anos. O que gostaríamos de ter, portanto, seria algo mais ou menos assim.

## Sigla Codigo Estado Ano Homicidios ## 1 AC 12 Acre 2000 108 ## 2 AL 27 Alagoas 2000 724 ## 3 AM 13 Amazonas 2000 559 ## 4 AP 16 Amapá 2000 155 ## 5 BA 29 Bahia 2000 1223 ## 6 CE 23 Ceará 2000 1229

Temos, portanto, informação espalhadas em várias colunas que deveriam estar numa única. Para conseguir isto, usamos a função gather. Seu uso é simples, e requer apenas que passemos a ela: o nome do objeto onde está o banco que queremos modificar; dois novos nomes, um para armazenar o nome das colunas que serão reunidas e, o outro, para armazenar os valores destas colunas; e, opcionalmente, o nome das variáveis que queremos preservar como estão no banco. Fazemos isso no banco de homicídios abaixo.

# Carrega o pacote tidyr library(tidyr) # Reune as variaveis de ano espalhadas pela base 'homic' homic <- gather(homic, Ano, Homicidios, -Sigla, -Codigo, -Estado) # Verifica as primeiras observacoes do novo banco head(homic)

## # A tibble: 6 x 5 ## Sigla Codigo Estado Ano Homicidios ## <chr> <chr> <chr> <chr> <dbl> ## 1 AC 12 Acre 2000 108 ## 2 AL 27 Alagoas 2000 724 ## 3 AM 13 Amazonas 2000 559 ## 4 AP 16 Amapá 2000 155 ## 5 BA 29 Bahia 2000 1223 ## 6 CE 23 Ceará 2000 1229

E, com isso, obtemos o resultado desejado – uma base tidy. De forma mais detalhada, a função gather possui três argumentos obrigatórios: data, que é o nome do objeto onde está o banco; key, que é o nome que iremos dar à variável que armazenará o nome das variáveis reunidas; e value, que é o nome da variável que armazenará os valores das variáveis reunidas. Vamos usar a mesma função, agora passando tudo explicitamente.

# Reune variaveis espalhadas no banco homic homic <- read_excel("homicidios_uf.xls") homic <- gather(data = homic, key = Data, value = Mortes, -Sigla, -Codigo, -Estado) # Visualiza o banco head(homic)

## # A tibble: 6 x 5 ## Sigla Codigo Estado Data Mortes ## <chr> <chr> <chr> <chr> <dbl> ## 1 AC 12 Acre 2000 108 ## 2 AL 27 Alagoas 2000 724 ## 3 AM 13 Amazonas 2000 559 ## 4 AP 16 Amapá 2000 155 ## 5 BA 29 Bahia 2000 1223 ## 6 CE 23 Ceará 2000 1229

Ao mudar os nomes passados para key e value, o nome das variáveis muda no banco. Os hífens seguidos dos nomes das variáveis originais indicam para a função quais colunas queremos manter como estão no banco.

Para desfazer esta operação, usamos a função inversa a gather, que é spread. Diferentemente da primeira, precisamos passar para ela apenas o nome das variáveis que queremos espalhar por colunas. Como dá para ver no exemplo abaixo, isto diz para o R criar uma variável para cada valor na variável Data e preencher elas com os valores existentes na variável Mortes. Como resultado geral, deste modo, o número de colunas do banco aumenta, mas o número de linhas diminui.

# Espalha valores por colunas homic <- spread(homic, Data, Mortes) # Visualiza o banco head(homic)

## # A tibble: 6 x 13 ## Sigla Codigo Estado `2000` `2001` `2002` `2003` `2004` `2005` `2006` ## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 AC 12 Acre 108 122 151 135 115 125 155 ## 2 AL 27 Alagoas 724 836 989 1041 1034 1211 1617 ## 3 AM 13 Amazonas 559 478 512 561 523 598 697 ## 4 AP 16 Amapá 155 184 181 190 173 196 203 ## 5 BA 29 Bahia 1223 1573 1735 2155 2255 2823 3276 ## 6 CE 23 Ceará 1229 1298 1443 1560 1538 1692 1793 ## # ... with 3 more variables: `2007` <dbl>, `2008` <dbl>, `2009` <dbl>

Com estas duas funções podemos tanto colocar em várias colunas valores que estavam agrupados numa única (último exemplo) quanto colocar numa mesma coluna valores que estavam espalhados por várias outras (primeiro exemplo). Na sequência, começaremos a usar o pacote dplyr para manipular bases de dados, mas, quando necessário, recorreremos a spread e gather para estruturar inicialmente elas em formato tidy.

Com uma base estruturada de forma adequada, podemos realizar outras operações nela (na verdade, frequentemente precisamos realizar operações tidy em várias etapas de uma limpeza de dados). Vamos nos concentrar neste capítulo em três, que chamamos aqui de verbos: cortar, para remover observações ou variáveis; modificar, para criar ou alterar variáveis e observações; e agrupar, para realizar modificações em grupos. Resumidamente, para cada tipo específico de tarefa de manipulação, usaremos uma função do pacote dplyr, conforme descrito abaixo.

Tabela 4.2: Operações básicas de manipulações com dplyr
Filtrar linhas filter filter(df, ...)
Selecionar linhas slice slice(df, ...)
Selecionar variáveis select select(df, ...
Modificar/criar variáveis mutate mutate(df, ...)
Agrupar observações group_by group_by(df, ...)
Sumarizar observações summarise summarise(df, ...)

Enquanto que slice e filter fazem operações horizontais (elas cortam linhas de um banco de dados), select faz operações verticais (ela corta, ou reordena, colunas); mutate, por sua vez, faz operações dos dois tipos, já que podemos usá-la para modificar apenas algumas observações de uma variável quanto adicionar, ou remover, colunas a uma base. Por fim, group_by serve para agrupar observações num banco, algo útil para realizar modificações diferentes em cada um deles.

Para exemplificar estas funções, trabalharemos com alguns dados sobre as despesas realizadas por todas as capitais brasileiras no ano de 2012, disponibilizados pela Secretaria do Tesouro Nacional em seu website.10 A base está no arquivo capitais.Rda nos materiais complementares, e pode ser carregada com load. Feito isto, ela ficará salva na memória no objeto capitais no formato tibble (ver capítulo 2).

A base capitais tem 26 observações e 8 variáveis. Podemos ver a estrutura dela com head.

## # A tibble: 6 x 8 ## regiao uf capital populacao despesa_total despesa_assistencia… ## <chr> <chr> <chr> <dbl> <dbl> <dbl> ## 1 Nordeste SE ARACAJU 587701 1150364953. 31383656. ## 2 Norte PA BELEM 1410430 2110549149 58105215 ## 3 Sudeste MG BELO HORIZ… 2395785 6917817946. 172347581. ## 4 Norte RR BOA VISTA 296959 491953689. 14018664. ## 5 Centro-O… MS CAMPO GRAN… 805397 2290844087. 39604187. ## 6 Centro-O… MT CUIABA 561329 1302650057. 32016290. ## # ... with 2 more variables: despesa_saude <dbl>, despesa_educacao <dbl>

Começaremos a usar o dplyr para selecionar e filtrar observações. Para fazer isto indicando apenas a posição delas, usamos slice – passamos um vetor para a função indicando a posição das linhas que queremos remover. Alguns exemplos.

# Carrega o pacote dplyr library(dplyr) # Seleciona apenas as duas primeiras observações do banco capitais slice(capitais, 1:2)

## # A tibble: 2 x 8 ## regiao uf capital populacao despesa_total despesa_assistencia_soci… ## <chr> <chr> <chr> <dbl> <dbl> <dbl> ## 1 Nordeste SE ARACAJU 587701 1150364953. 31383656. ## 2 Norte PA BELEM 1410430 2110549149 58105215 ## # ... with 2 more variables: despesa_saude <dbl>, despesa_educacao <dbl>

# Seleciona apenas a primeira e a quinta observações do banco capitais slice(capitais, c(1, 5))

## # A tibble: 2 x 8 ## regiao uf capital populacao despesa_total despesa_assistencia_… ## <chr> <chr> <chr> <dbl> <dbl> <dbl> ## 1 Nordeste SE ARACAJU 587701 1150364953. 31383656. ## 2 Centro-Oe… MS CAMPO GR… 805397 2290844087. 39604187. ## # ... with 2 more variables: despesa_saude <dbl>, despesa_educacao <dbl>

# Seleciona apenas as 100 primeiras observações do banco capitais cap1 <- slice(capitais, 1:100) # Remove as 10 primeiras observacoes do banco capitais cap2 <- slice(capitais, -c(1:10)) # Número de linhas de cada uma linhas <- c(nrow(capitais), nrow(cap1), nrow(cap2)) linhas

## [1] 26 26 16

Se slice nos permite remover linhas baseadas nas suas posições, a outra função para cortar horizontalmente, filter, é muito mais flexível. Com ela, podemos especificar condições para remover observações (e.g., remover observações de capitais cuja despesa total no ano de 2012 seja maior ou menor que algum valor) ou combinações de várias condições. Ela é útil, portanto, para filtrar observações com base em um ou mais critérios, como mostram os exemplos abaixo.

# Seleciona apenas observacoes com populacao maior que 2 milhoes habitantes cap1 <- filter(capitais, populacao > 2000000) cap1

## # A tibble: 5 x 8 ## regiao uf capital populacao despesa_total despesa_assistencia_… ## <chr> <chr> <chr> <dbl> <dbl> <dbl> ## 1 Sudeste MG BELO HORIZ… 2395785 6917817946. 172347581. ## 2 Nordeste CE FORTALEZA 2500194 4137588203. 78034074. ## 3 Sudeste RJ RIO DE JAN… 6390290 18702324296. 565052833. ## 4 Nordeste BA SALVADOR 2710968 3618049094. 40981531. ## 5 Sudeste SP SAO PAULO 11376685 36400104976. 919021471. ## # ... with 2 more variables: despesa_saude <dbl>, despesa_educacao <dbl>

# Seleciona apenas observacoes da regiao sul cap2 <- filter(capitais, regiao == "Sul") cap2

## # A tibble: 3 x 8 ## regiao uf capital populacao despesa_total despesa_assistencia_s… ## <chr> <chr> <chr> <dbl> <dbl> <dbl> ## 1 Sul PR CURITIBA 1776761 5115609915. 117962804. ## 2 Sul SC FLORIANOPOL… 433158 1080743166. 33082667. ## 3 Sul RS PORTO ALEGRE 1416714 4122115448. 146233833. ## # ... with 2 more variables: despesa_saude <dbl>, despesa_educacao <dbl>

# Número de linhas de cada uma linhas <- c(nrow(capitais), nrow(cap1), nrow(cap2)) linhas

## [1] 26 5 3

Outros exemplos.

# Seleciona observacoes com populacao maior que 500 mil e menor que 1 milhao filter(capitais, populacao > 500000 & populacao < 1000000) # ou filter(capitais, populacao > 500000, populacao < 1000000) # Seleciona observacoes com despesa em saude maior que 250 milhoes e # despesa em educacao maior que 300 milhoes filter(capitais, despesa_saude / 1000000 > 250, despesa_educacao / 1000000 > 300)

Note que, por fazer testes lógicos (que retornam TRUE ou FALSE, geralmente feitos com os operadores lógicos vistos no capítulo 1), filter pode ser usada para realizar tarefas como remover observações com missings (função is.na()) ou valores extremos. ### Selecionar e ordenar variáveis

Assim como às vezes é necessário selecionar apenas algumas observações de um banco para trabalharmos, selecionar variáveis também pode ser útil, especialmente para remover as que não usaremos numa análise. Para realizar este tipo de operação, usamos a função select11 do pacote dplyr.

# Seleciona apenas as variaveis uf, capital e populacao do banco cap1 <- select(capitais, uf, capital, populacao) head(cap1)

## # A tibble: 6 x 3 ## uf capital populacao ## <chr> <chr> <dbl> ## 1 SE ARACAJU 587701 ## 2 PA BELEM 1410430 ## 3 MG BELO HORIZONTE 2395785 ## 4 RR BOA VISTA 296959 ## 5 MS CAMPO GRANDE 805397 ## 6 MT CUIABA 561329

# Remove a variavel populacao cap2 <- select(capitais, -populacao) head(cap2)

## # A tibble: 6 x 7 ## regiao uf capital despesa_total despesa_assistenci… despesa_saude ## <chr> <chr> <chr> <dbl> <dbl> <dbl> ## 1 Nordeste SE ARACAJU 1150364953. 31383656. 391263344. ## 2 Norte PA BELEM 2110549149 58105215 595930546 ## 3 Sudeste MG BELO HOR… 6917817946. 172347581. 2029533813. ## 4 Norte RR BOA VISTA 491953689. 14018664. 105492562. ## 5 Centro-… MS CAMPO GR… 2290844087. 39604187. 734214086. ## 6 Centro-… MT CUIABA 1302650057. 32016290. 366936045. ## # ... with 1 more variable: despesa_educacao <dbl>

O primeiro argumento da função select é o banco de dados que queremos manipular, seguido do nome das variáveis que queremos manter, separadas por vírgula; se quisermos excluir uma variável, colocamos um sinal de subtração, -, antes do seu nome.

Além destes usos, também podemos selecionar colunas com select com base na posição delas.

# Mantem apenas a 1a e a 3a colunas cap1 <- select(capitais, 1, 3) head(cap1)

## # A tibble: 6 x 2 ## regiao capital ## <chr> <chr> ## 1 Nordeste ARACAJU ## 2 Norte BELEM ## 3 Sudeste BELO HORIZONTE ## 4 Norte BOA VISTA ## 5 Centro-Oeste CAMPO GRANDE ## 6 Centro-Oeste CUIABA

# Exclui as colunas 2 e 4 cap2 <- select(capitais, -2, -4)

Para diminuir a quantidade de código que precisamos escrever, também podemos usar dois pontos, :, como em vetores, para selecionar colunas.

# Mantem as colunas entre uf e despesa_total cap1 <- select(capitais, uf:despesa_total) head(cap1)

## # A tibble: 6 x 4 ## uf capital populacao despesa_total ## <chr> <chr> <dbl> <dbl> ## 1 SE ARACAJU 587701 1150364953. ## 2 PA BELEM 1410430 2110549149 ## 3 MG BELO HORIZONTE 2395785 6917817946. ## 4 RR BOA VISTA 296959 491953689. ## 5 MS CAMPO GRANDE 805397 2290844087. ## 6 MT CUIABA 561329 1302650057.

# Mantem as colunas de 2 a 4 cap2 <- select(capitais, 2:4) # Mantem as colunas entre uf e populacao e a coluna despesa_saude cap3 <- select(capitais, uf:populacao, despesa_saude)

Outros exemplos de seleção, e também de reordenamento, de colunas.

# Exclui a 1 e a 3 colunas select(capitais, -c(1, 3)) # Exclui as colunas despesa_total, despesa_assistencia_social e despesa_saude select(capitais, -c(despesa_total:despesa_saude)) # Reordena a posicao das colunas select(capitais, populacao, capital, uf, regiao, despesa_total:despesa_educacao) # Inverte a ordem das colunas select(capitais, 8:1)

O dplyr não serve apenas para filtrar e selecionar observações e variáveis. Das funções de modificação, a mais útil do pacote é a mutate, que serve para alterar variáveis ou adicionar novas a um banco (elas são incluídas no fim do banco, logo após todas as demais variáveis existentes). Podemos usá-la, por exemplo, para calcular a despesa total per capita das capitais brasileiras em 2012 – que é igual a despesas total dividida pelo número de habitantes de cada capital.

# Adiciona a variavel despesa_per_capita ao banco cap1 <- mutate(capitais, despesa_per_capita = despesa_total / populacao) # Estatisticas descritivas da nova variavel summary(cap1$despesa_per_capita)

## Min. 1st Qu. Median Mean 3rd Qu. Max. ## 1219 1629 2054 2201 2757 4377

Como mostra o exemplo anterior, só precisamos passar o nome do banco para a função, o nome da nova variável a ser criada, sem aspas, e o conteúdo dela. Além da economia de caracteres, a função mutate também traz a vantagem de nos permitir usar as variáveis já existentes do banco para criar uma nova. Intuitivamente, o que ela faz é nos dar acesso às demais variáveis de forma vetorizada: se quisermos criar uma nova variável que seja igual a o logaritmo natural da variável população, portanto, mutate aplicará o log a cada elemento da variável populacao.

# Cria uma variavel que e' igual ao log de populacao cap1 <- mutate(capitais, log_populacao = log(populacao)) cap1 <- select(cap1, capital, log_populacao) head(cap1)

## # A tibble: 6 x 2 ## capital log_populacao ## <chr> <dbl> ## 1 ARACAJU 13.3 ## 2 BELEM 14.2 ## 3 BELO HORIZONTE 14.7 ## 4 BOA VISTA 12.6 ## 5 CAMPO GRANDE 13.6 ## 6 CUIABA 13.2

Com a mesma sintaxe, podemos criar mais de uma variável por vez.

# Cria tres variaveis ao mesmo tempo mutate(capitais, despesa_saude_per_capita = despesa_saude / populacao, despesa_educacao_per_capita = despesa_educacao / populacao, despesa_assistencia_social = despesa_assistencia_social / populacao )

Modificar variáveis que já temos (isto deve ser feito com cautela, já que substituirá o conteúdo anterior da variável, caso o resultado seja salvo em cima do data.frame original).

# Variavel de populacao por mil habitantes mutate(capitais, populacao = populacao / 1000)

Além de ser possível criar variáveis que possuam valores únicos, como um indicador do ano em que estes dados de despesas das capitais foram coletados.

# Cria uma variavel indicando o ano mutate(capitais, ano = 2012)

Outro uso importante de mutate é em operações condicionais, como criar uma variável que assume um determinado valor se uma condição for verdadeira (e.g., a população do município no banco capitais é maior que 500 mil habitantes) e outro valor, caso esta condicação seja falsa. Para tanto, usamos mutate em conjunto com if_else12, que também é uma função do pacote dplyr.

# Cria uma variavel que indica municipios com mais de 500 mil habitantes mutate(capitais, capitais_grandes = if_else(populacao > 500000, "Maior", "Menor"))

summarise, assim como mutate, é usada para modificar variáveis num banco. Mas, diferentemente desta última, ela agrega as informações, retornando um resumo dos dados numa única observação. Exemplo de uso da função: somar a população de todas as capitais.

# Soma a populacao de todas as capitais summarise(capitais, populacao_capitais = sum(populacao))

## # A tibble: 1 x 1 ## populacao_capitais ## <dbl> ## 1 43578158

A sintaxe desta função é semelhante a da função mutate: em primeiro lugar, como de praxe, passamos o nome do banco de dados para a função; depois, passamos o nome da variável que queremos criar seguida do operador de igualdade e do valor que queremos criar. Deve ficar claro, contudo, que só é possível usar esta função para agregar informações. Podemos somar valores de variáveis, calcular estatísticas descritivas (média e desvio-padrão, como veremos abaixo), entre outros. Mais alguns exemplos.

# Calcula a soma de gastos de todas as capitais summarise(capitais, gastos_capitais = sum(despesa_total)) # Calcula a soma de gastos em educacao e em saude summarise(capitais, gastos_educacao = sum(despesa_educacao) gastos_saude = sum(despesa_saude) ) # Calcula o numero de capitais no banco (o mesmo que nrow faria) summarise(capitais, n_capitais = n())

Em alguns casos, modificar inteiramente uma variável não é algo desejável. Imagine, por exemplo, que seja necessário adicionar uma variável à base capitais que seja igual à população das capitais de cada região, isto é, uma variável que some a população de todas as capitais de cada região (e.g., população de Porto Alegre + população de Curitiba + população de Florianópolis para a região Sul).

Usamos a função group_by para realizar esta operação. Intuitivamente, o que ela faz é dividir um banco em vários sub-bancos, especificados por uma ou mais variáveis. No exemplo abaixo, usamos ela para quebrar o banco por região para, aí sim, aplicar mutate para somar a população das capitais de cada região.

# Agrupa o banco capitais por regiao cap_regiao <- group_by(capitais, regiao) # Soma a populacao das capitais cap_regiao <- mutate(cap_regiao, pop_regiao = sum(populacao)) # Resultado (usando select para selecionar algumas variaveis) select(cap_regiao, regiao, capital, pop_regiao)

## # A tibble: 26 x 3 ## # Groups: regiao [5] ## regiao capital pop_regiao ## <chr> <chr> <dbl> ## 1 Nordeste ARACAJU 11737204 ## 2 Norte BELEM 5017906 ## 3 Sudeste BELO HORIZONTE 20495922 ## 4 Norte BOA VISTA 5017906 ## 5 Centro-Oeste CAMPO GRANDE 2700493 ## 6 Centro-Oeste CUIABA 2700493 ## 7 Sul CURITIBA 3626633 ## 8 Sul FLORIANOPOLIS 3626633 ## 9 Nordeste FORTALEZA 11737204 ## 10 Centro-Oeste GOIANIA 2700493 ## # ... with 16 more rows

Note que o valor da variável pop_regiao que criamos é igual dentro de cada região. Podemos usar a mesma lógica para calcular: o desvio-padrão da população de cada região, a média da população, entre outros.

cap_regiao <- group_by(capitais, regiao) cap_regiao <- mutate(cap_regiao, media_pop_regiao = mean(populacao), desvio_pop_regiao = sd(populacao)) # Resultado (usando select para selecionar algumas variaveis) select(cap_regiao, regiao, capital, media_pop_regiao, desvio_pop_regiao)

## # A tibble: 26 x 4 ## # Groups: regiao [5] ## regiao capital media_pop_regiao desvio_pop_regiao ## <chr> <chr> <dbl> <dbl> ## 1 Nordeste ARACAJU 1304134. 787062. ## 2 Norte BELEM 716844. 644916. ## 3 Sudeste BELO HORIZONTE 5123980. 4868088. ## 4 Norte BOA VISTA 716844. 644916. ## 5 Centro-Oeste CAMPO GRANDE 900164. 394843. ## 6 Centro-Oeste CUIABA 900164. 394843. ## 7 Sul CURITIBA 1208878. 695496. ## 8 Sul FLORIANOPOLIS 1208878. 695496. ## 9 Nordeste FORTALEZA 1304134. 787062. ## 10 Centro-Oeste GOIANIA 900164. 394843. ## # ... with 16 more rows

Há um detalhe importante: enquanto ela estiver agrupada, todas as operações que realizarmos nela serão feitas nos grupos. Para evitar isto, usamos ungroup.

# Agrupa a base cap_regiao <- group_by(capitais, regiao) # A base esta agrupada, como da pra ver com class class(cap_regiao)

## [1] "grouped_df" "tbl_df" "tbl" "data.frame"

# Desagrupa a base cap_regiao <- ungroup(cap_regiao) # Agora ela nao esta mais agrupada class(cap_regiao)

## [1] "tbl_df" "tbl" "data.frame"

Talvez o uso mais interessante de group_by seja em conjunto com a função summarise, que vimos anteriormente. Trabalhando com as duas, é possível resumir várias informações por grupo. Podemos repetir o exemplo anterior, calculando a média e o desvio-padrão da população de cada região como exemplo.

cap_regiao <- group_by(capitais, regiao) # Usa summarise em vez de mutate cap_regiao <- summarise(cap_regiao, media_pop_regiao = mean(populacao), desvio_pop_regiao = sd(populacao)) # Resultado (usando select para selecionar algumas variaveis) select(cap_regiao, regiao, media_pop_regiao, desvio_pop_regiao)

## # A tibble: 5 x 3 ## regiao media_pop_regiao desvio_pop_regiao ## <chr> <dbl> <dbl> ## 1 Centro-Oeste 900164. 394843. ## 2 Nordeste 1304134. 787062. ## 3 Norte 716844. 644916. ## 4 Sudeste 5123980. 4868088. ## 5 Sul 1208878. 695496.

A base retornada é bem menor, e preserva apenas uma observação por região (para quem usa outros softwares de análise de dados, isto é o equivalente a agregar informações). Em outras bases, que veremos adiante, usaremos este recurso para resumir bases bem maiores de dados usando uma combinação de diversas variáveis (como ano e país, ou ano e estato e município).

O exemplo anterior mostra como alterar algumas variáveis, agrupando elas ou não, de forma individual. No mais das vezes, é isso o que precisamos: transformar apenas uma ou duas variáveis, ou ainda resumir múltiplas informações usando group_by. Em outros casos, contudo, precisamos fazer uma alteração em muitas variáveis ao mesmo tempo: imagine, por exemplo, ter de transformar em logaritmo 50 variáveis; com o que vimos anteriormente, isso equivaleria a repetir essa transformação também 50 vezes, uma para cada variável. Algo mais ou menos assim:

# Processo para transformar 50 variaveis (exemplo hipotetico) df <- mutate(df, var1 = log(var1), var2 = log(var2), var3 = log(var3), ... # O codigo continuaria ate chegarmos em var50 )

Como é possível perceber, esse processo seria muito ineficiente, apesar de ser funcional. Para evitá-lo, o pacote dplyr oferece algumas funções específicas que servem exatamente para realizar esse processo em múltiplas variáveis simultaneamente. Basicamente, essas funções são: mutate_all, mutate_at e mutate_if, para transformar variáveis; e summarise_all, summarise_at e summarise_if para resumir dados previamente agrupados por group_by. Elas funcionam exatamente como suas equivalentes mais simples, as diferenças são indicadas pelo sufixo de cada uma: _all serve para aplicar a mesma transformação em todas as variáveis de um data.frame ou tibble; _at, por sua vez, especifica apenas algumas variáveis que serão transformadas; e, por fim, _if é usada para aplicar transformações apenas em variáveis que atendam a algum requisito (por exemplo, transformar apenas variáveis que sejam numeric). A tabela abaixo resume essas informações.

Tabela 4.3: Usos das funções _all, _at e _if
_all summarise_all Resume as informações de todas as variáveis de um banco
_all mutate_all Transforma todas as variáveis de um banco
_at summarise_at Resume as informações de apenas algumas variáveis
_at mutate_at Transforma apenas algumas variáveis
_if summarise_if Resume as informações de variáveis que atendam a algum critério
_if mutate_if Transforma as variáveis que atendam a algum critério

Alguns ajudam a entender como cada uma funciona. Novamente, usaremos nosso banco sobre as capitais do Brasil, disponíveis no objeto capitais. Para começar, vamos usar as funções com suxico _all para calcular algo simples: a soma de todos os valores de todas as variáveis do nosso banco (como ela possui variáveis não-numéricas, como o nome da capital, usaremos antes a função select, vista anteriormente, para removê-las).

# Remove variaveis nao-numericas do banco (- exclui as variaveis indicadas) cap_numericas <- select(capitais, -regiao, -uf, -capital) # Soma todos os valores das demais variaveis summarise_all(cap_numericas, sum)

## # A tibble: 1 x 5 ## populacao despesa_total despesa_assisten… despesa_saude despesa_educacao ## <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 43578158 108579739469. 2668345178. 24681041035. 20759693825.

O resultado, como visto, é uma única observação para cada variável, cujo conteúdo é igual a soma de todas as observações em cada um: população, por exemplo, retornou a soma da população de todas as capitais no banco. O que é preciso notar, entretanto, é funcionamento simples da função: tudo o que é necessário é passar o nome do banco de dados usado e função que se quer aplicar em cada uma – é necessário ter cuidado, entretanto, porque funções numéricas não podem ser usadas em bancos que contém informações não-numéricas, assim como funções usadas em character não podem ser usadas em variáveis numéricas. Podemos usar a mesma lógica para calcular, também, a média e o desvio-padrão de cada variável.

# Media dos valores das demais variaveis summarise_all(cap_numericas, mean)

## # A tibble: 1 x 5 ## populacao despesa_total despesa_assisten… despesa_saude despesa_educacao ## <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 1676083 4176143826. 102628661. 949270809. 798449762.

# Desvio dos valores das demais variaveis summarise_all(cap_numericas, sd)

## # A tibble: 1 x 5 ## populacao despesa_total despesa_assisten… despesa_saude despesa_educacao ## <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 2345416. 7486807095. 199117498. 1339629251. 1506233844.

E se precisarmos declarar argumentos opcionais das funções? Para isso, temos a seguinte opção, que consiste simplesmente em colocar essa opção na sequência do seu nome:

# Adiciona um argumento a funcao mean (para remover NA) summarise_all(cap_numericas, mean, na.rm = T)

## # A tibble: 1 x 5 ## populacao despesa_total despesa_assisten… despesa_saude despesa_educacao ## <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 1676083 4176143826. 102628661. 949270809. 798449762.

No geral, portanto, a summarise_all é uma ferramenta potente, que pode simplificar enormemente o trabalho de resumir informações. mutate_all, nesse ponto, não é muito diferente, só que, em vez de resumir informações, ela transforma todas as variáveis de um banco. Por exemplo, podemos usá-la para transformar em log todas as variáveis do banco cap_numericas:

# Adiciona um argumento a funcao mean (para remover NA) mutate_all(cap_numericas, log)

## # A tibble: 26 x 5 ## populacao despesa_total despesa_assiste… despesa_saude despesa_educacao ## <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 13.3 20.9 17.3 19.8 18.9 ## 2 14.2 21.5 17.9 20.2 19.7 ## 3 14.7 22.7 19.0 21.4 20.9 ## 4 12.6 20.0 16.5 18.5 18.5 ## 5 13.6 21.6 17.5 20.4 20.0 ## 6 13.2 21.0 17.3 19.7 19.4 ## 7 14.4 22.4 18.6 20.8 20.5 ## 8 13.0 20.8 17.3 19.2 19.3 ## 9 14.7 22.1 18.2 21.0 20.4 ## 10 14.1 21.8 16.5 20.7 20.2 ## # ... with 16 more rows

Como nos exemplos anteriores, tudo o que mutate_all faz, portanto, é aplicar uma mesma função em todas as variáveis do banco, tornando desnecessário a aplicação de mutate reiteradamente para cada variável. As outras funções, com sufixos _at e _if funcionam de maneira similar, mas possuem diferenças básicas que são bantantes úteis. Nos exemplos anteriores, por exemplo, tivemos de criar uma base chamada cap_numericas para usar summarise_all e mutate_all, uma vez que as variáveis do banco original, capitais, são de classes diferentes. Como dito, isso impede que usemos funções numéricas em casos onde existem variáveis não-numéricas, e assim por diante. É nesse ponto que entram as funções _at e _if.

# Usa summarise_at para calcular a media de apenas algumas variaveis do banco summarise_at(capitais, vars(populacao, despesa_total), mean)

## # A tibble: 1 x 2 ## populacao despesa_total ## <dbl> <dbl> ## 1 1676083 4176143826.

# Usa summarise_if para calcular a media apenas de variaveis numericas summarise_if(capitais, is.numeric, mean)

## # A tibble: 1 x 5 ## populacao despesa_total despesa_assisten… despesa_saude despesa_educacao ## <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 1676083 4176143826. 102628661. 949270809. 798449762.

Notadamente, a principal diferença desse código em relação ao anterior é que, neles, controlamos especificamente quais variáveis seriam sumarizadas: no caso da função summarise_at, fizemos isso declarando, explicitamente, quais variáveis queríamos resumir logo após o nome do banco; já no caso da função summarise_if, usamos um critério (is.numeric, que retorna TRUE apenas para variáveis numéricas), especificando que apenas variáveis numéricas deveriam ser resumidas. Dizendo de novo: funções _at servem para declararmos quais variáveis devem ser utilizadas (fazemos isso com a outra função, vars, que recebe o nome das variáveis desejadas); funções _if, por sua vez, são usadas para incluir na operação apenas variáveis que atendem a alguma condição (que declaramos logo após o nome do objeto contendo os dados). Dessa forma, temos total controle sobre quais variáveis entram, e quais não, nas operações de sumarização. O mesmo vale para as funções mutate_at e mutate_if, também úteis – talvez até mais que as anteriores, já que nos permitem rapidamente arrumar uma grande quantidade de variáveis num banco.

# Transforma apenas tres variaveis em log mutate_at(capitais, vars(populacao:despesa_saude), log) # usamos : como visto com select()

## # A tibble: 26 x 8 ## regiao uf capital populacao despesa_total despesa_assistencia… ## <chr> <chr> <chr> <dbl> <dbl> <dbl> ## 1 Nordeste SE ARACAJU 13.3 20.9 17.3 ## 2 Norte PA BELEM 14.2 21.5 17.9 ## 3 Sudeste MG BELO HORI… 14.7 22.7 19.0 ## 4 Norte RR BOA VISTA 12.6 20.0 16.5 ## 5 Centro-O… MS CAMPO GRA… 13.6 21.6 17.5 ## 6 Centro-O… MT CUIABA 13.2 21.0 17.3 ## 7 Sul PR CURITIBA 14.4 22.4 18.6 ## 8 Sul SC FLORIANOP… 13.0 20.8 17.3 ## 9 Nordeste CE FORTALEZA 14.7 22.1 18.2 ## 10 Centro-O… GO GOIANIA 14.1 21.8 16.5 ## # ... with 16 more rows, and 2 more variables: despesa_saude <dbl>, ## # despesa_educacao <dbl>

# Transforma todas as variaveis numericas em raiz quadrado mutate_if(capitais, is.numeric, sqrt)

## # A tibble: 26 x 8 ## regiao uf capital populacao despesa_total despesa_assistencia… ## <chr> <chr> <chr> <dbl> <dbl> <dbl> ## 1 Nordeste SE ARACAJU 767. 33917. 5602. ## 2 Norte PA BELEM 1188. 45941. 7623. ## 3 Sudeste MG BELO HORI… 1548. 83173. 13128. ## 4 Norte RR BOA VISTA 545. 22180. 3744. ## 5 Centro-O… MS CAMPO GRA… 897. 47863. 6293. ## 6 Centro-O… MT CUIABA 749. 36092. 5658. ## 7 Sul PR CURITIBA 1333. 71523. 10861. ## 8 Sul SC FLORIANOP… 658. 32875. 5752. ## 9 Nordeste CE FORTALEZA 1581. 64324. 8834. ## 10 Centro-O… GO GOIANIA 1155. 54334. 3922. ## # ... with 16 more rows, and 2 more variables: despesa_saude <dbl>, ## # despesa_educacao <dbl>

Esse é o básico do funcionamento dessas funções. Como vimos, elas são extremamente flexíveis, mas mal tocamos em outros usos delas, como substituir missings em todas as variáveis de um banco ao mesmo tempo (a dica, aqui, é usar a função if_else em conjunto com a função is.na), usar funções complexas, ou mais de uma função, nessas operações, entre outros. Caso queira saber mais sobre esses e outras aplicações, a dica é procurar a documentação delas para checar outros exemplos (?summarise_at, por exemplo). De qualquer forma, apenas com isso já é possível simplificar enormemente a aplicação de tarefas repetidas na transformação e resumo de variáveis.

Embora não seja o objetivo desse capítulo cobrir todas as possibilidades de manipulação de bancos de dados, algumas das quais são raramente necessárias, existem algumas funções que podem ser extremamente úteis em algumas situações. Reordenar observações de acordo com os valores de uma variável (por exemplo, ordenando o banco capitais pelo tamanho de suas populações) poderia ser uma delas. Selecionar aleatoriamente apenas algumas observações de um banco para realizar algum tipo de teste, outra. E, seguindo nos exemplos, apenas renomear alguma variável. Enfim, todas essas tarefas podem ser resolvidas usando dplyr. Nesta última subseção, listamos algumas funções, disponíveis no pacote, que nos ajudam a resolver esses problemas mais específicos (é recomendável reproduzir esses exemplos para fixar as funções de interesse). Seguem:

# arrange() serve para ordenar as observacoes de um banco head(capitais)

## # A tibble: 6 x 8 ## regiao uf capital populacao despesa_total despesa_assistencia… ## <chr> <chr> <chr> <dbl> <dbl> <dbl> ## 1 Nordeste SE ARACAJU 587701 1150364953. 31383656. ## 2 Norte PA BELEM 1410430 2110549149 58105215 ## 3 Sudeste MG BELO HORIZ… 2395785 6917817946. 172347581. ## 4 Norte RR BOA VISTA 296959 491953689. 14018664. ## 5 Centro-O… MS CAMPO GRAN… 805397 2290844087. 39604187. ## 6 Centro-O… MT CUIABA 561329 1302650057. 32016290. ## # ... with 2 more variables: despesa_saude <dbl>, despesa_educacao <dbl>

head(arrange(capitais, populacao))

## # A tibble: 6 x 8 ## regiao uf capital populacao despesa_total despesa_assistencia_s… ## <chr> <chr> <chr> <dbl> <dbl> <dbl> ## 1 Norte TO PALMAS 242070 584961477. 20624102. ## 2 Norte RR BOA VISTA 296959 491953689. 14018664. ## 3 Sudeste ES VITORIA 333162 1458392579. 43461295. ## 4 Norte AC RIO BRANCO 348354 495861081 18704896. ## 5 Norte AP MACAPA 415554 506401565. 6743489. ## 6 Sul SC FLORIANOPO… 433158 1080743166. 33082667. ## # ... with 2 more variables: despesa_saude <dbl>, despesa_educacao <dbl>

# rename() serve para renomear uma variavel (nome atual vem na frente, seguido do nome antigo) names(capitais) # nomes atuais

## [1] "regiao" "uf" ## [3] "capital" "populacao" ## [5] "despesa_total" "despesa_assistencia_social" ## [7] "despesa_saude" "despesa_educacao"

capitais <- rename(capitais, populacao_novo = populacao) names(capitais) # novos nomes

## [1] "regiao" "uf" ## [3] "capital" "populacao_novo" ## [5] "despesa_total" "despesa_assistencia_social" ## [7] "despesa_saude" "despesa_educacao"

capitais <- rename(capitais, populacao = populacao_novo, SAUDE = despesa_saude) names(capitais) # nomes novos 2

## [1] "regiao" "uf" ## [3] "capital" "populacao" ## [5] "despesa_total" "despesa_assistencia_social" ## [7] "SAUDE" "despesa_educacao"

# sample_n() sorteia apenas algumas obsvervacoes de um banco sample_n(capitais, 2) # sorteia duas capitais

## # A tibble: 2 x 8 ## regiao uf capital populacao despesa_total despesa_assistenc… SAUDE ## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> ## 1 Nordeste AL MACEIO 953393 1530192466. 22125734. 4.45e8 ## 2 Centro-… GO GOIANIA 1333767 2952160894. 15382878. 9.78e8 ## # ... with 1 more variable: despesa_educacao <dbl>

sample_n(capitais, 3) # sorteia tres capitais

## # A tibble: 3 x 8 ## regiao uf capital populacao despesa_total despesa_assistenc… SAUDE ## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> ## 1 Norte RR BOA VIS… 296959 491953689. 14018664. 1.05e8 ## 2 Norte PA BELEM 1410430 2110549149 58105215 5.96e8 ## 3 Sul PR CURITIBA 1776761 5115609915. 117962804. 1.06e9 ## # ... with 1 more variable: despesa_educacao <dbl>

Até agora, vimos como fazer as principais operações de manipulação de dados: aprendemos que o formato mais adequado para um banco é o tidy, e que podemos transformar qualquer base para esse formato usando gather e spread; vimos também que, na maioria dos casos, manipular uma base envolve dominar apenas três operações (cortes, modificações e agrupamentos), e que essas podem ser adaptadas (caso das funções _at, por exemplo) ou combinadas (group_by e mutate, e.g.) para resolver quase todos os problemas de limpeza encontrados em bases de dados reais. Ainda assim, mesmo sabendo tudo isso, é bem provável que não ainda não possamos fazer análises para responder questões concretas, e isso por um motivo muito simples: raramente todas as informações que precisamos estão contidas numa mesma base de dados. Se quisermos saber se pobreza tem relação com a competição eleitoral num município, por exemplo, teremos de combinar informações de fontes diferentes, socioeconômicas e eleitorais. Da mesma forma, se nosso objetivo for comparar os resultados eleitorais de um partido em duas eleições diferentes, provavelmente precisaremos juntar bancos diferentes. Em muitos outros casos, enfim, precisaremos adicionar variáveis de outras fontes. Assim, sem saber como unir múltiplos bancos de dados, dificilmente teríamos o conhecimento necessário para conduzir uma análise de dados, do início ao fim.

Aprender a juntar bases de dados, mais uma vez, é algo relativamente simples. Usando o pacote dplyr, podemos realizar esse tipo de operação – e isso de várias maneiras, controlando exatamente como essa junção será feita. Para as operações mais simples, usaremos duas funções em particular: left_join() e bind_rows(). Vamos começar pela primeira. Antes, contudo, iremos nos deter num exemplo específico, que envolve as duas bases de dados que usamos até agora: a sobre a taxa de homicídios nos estados, salva no objeto homic, e a sobre despesas das capitais brasileiras em 2012, salva no objeto capitais. Como já vimos, as duas bases possuem variáveis que indicam a sigla dos estado brasileiros. No caso da base homic, essa variável chama-se Sigla (podemos acessá-la com homic$Estado); já no caso da base sobre as capitais, essa variável intitula-se uf. Em resumo, cada uma possui informações diferentes, mas ambas compartilham a informação específica acerca do estado onde essas informações são mensuradas. O que faremos, agora, é unir essas bases a partir das informações comuns que compartilham. Assim, observações sobre a Bahia numa das bases será unida com informações sobre a Bahia na outra; do mesmo modo, observações sobre Minas gerais serão unidas com observações de Minas Gerais na outra. De forma visual, o que faremos será o seguinte:

# Une as duas bases base_unida <- left_join(capitais, homic, by = c("uf" = "Sigla")) # Exibe o nome das variaveis na base unida names(base_unida)

## [1] "regiao" "uf" ## [3] "capital" "populacao" ## [5] "despesa_total" "despesa_assistencia_social" ## [7] "SAUDE" "despesa_educacao" ## [9] "Codigo" "Estado" ## [11] "2000" "2001" ## [13] "2002" "2003" ## [15] "2004" "2005" ## [17] "2006" "2007" ## [19] "2008" "2009"

O resultado dessa operação indica que a base final, chamada base_unida, passou a conter 20 variáveis, o que significa que efetivamente juntamos as variáveis dos dois bancos de acordo com a informação que elas compartilhavam. Além de termos as informações sobre as despasas da capitasi brasileiras, dessa forma, nossa base final agora contém variáveis sobre o número de homicídios em cada estado brasileiro. De forma geral, portanto, o que vimos é que a função left_join nos permitiu criar um banco de dados que combina variáveis de dois outros bancos, e que essa combinação é feita a partir de uma variável comum em ambos: as informações da Bahia de um banco foram unidas às informações da Bahia no outro, e assim por diante.

De forma mais prática, a função left_join possui três argumentos principais. O primeiro indica a primeira base de dados usada na junção dos dados; a segunda, a outra base que será unida à primeira; por fim, usamos o argumento by para indicar quais variáveis são comuns nas duas bases. Esse último argumento é o principal da função, já que é com ele que informamos ao R como unir as variáveis. No caso, isso é declarado usando um vector (função c()) onde indicamos qual variável do primeiro banco, capitais, servirá como índice das observações do segundo banco, homic. Assim, o resultado é que declaramos ao R que by = c("uf" = "Sigla") significa que uf e Sigla contêm a sigla dos estados brasileiros e, dessa forma, os valores em cada uma dessas variáveis encontra uma correspondência na outra.

O que podemos tirar de lição geral desse exemplo, portanto, é que para adicionarmos variáveis a um banco de dados a partir de informações específicas (Bahia com Bahia, Minas com Minas, etc.) precisamos de variáveis que possuam valores comuns em duas bases. Isso significa que não podemos combinar duas bases que não partilhem informações comuns: só foi possível cominar as bases homic e capitais porque ambas têm uma variável com a sigla das unidades da federação brasileiras, e é a partir delas que junção das bases é feita: como BA numa das bases é igual à BA na outra, o R entende que as linhas que contém essa informação em ambas devem ser mantidas lado a lado, assim como MG e MG são entendidas pela função como valores comuns. Dessa maneira, o que a função left_join faz é combinar bases diferentes a partir de valores comuns de variáveis de ambas.

left_join, contudo, é apenas uma das funções contidas no pacote dplyr para juntar duas bases. Além disso, ela realiza essa operação de forma específica: como o left_ indica, ela junta valores da segunda base passada à função (no nosso exemplo, homic) para a primeira. A consequência desse procedimento, desse modo, é que todas as observações do primeiro banco (capitais) são preservadas, e as da segunda base são usadas para preencher os casos comuns. Um exemplo ajuda a entender esse processo: caso a primeira base tenha as siglas dos 27 estados brasileiros (contando com o Distrito Federal) e, a segunda, apenas 20, a base final manterá as 27 observações da primeira base, deixando os 7 estados que não têm correspondência como missing na segunda. Podemos explorar esse compartamento com um exemplo fictício.

# Cria uma base com 2 observacoes e duas variaveis df <- data.frame(x = 1:2, y = 10:11) df

## x y ## 1 1 10 ## 2 2 11

# Cria uma base com 1 observacao e duas variaveis df2 <- data.frame(x = 2:3, z = 99:100) df2

## x z ## 1 2 99 ## 2 3 100

# Une as duas bases com left_join base_final <- left_join(df, df2, by = c("x" = "x")) base_final

## x y z ## 1 1 10 NA ## 2 2 11 99

O exemplo é bastante claro: a base df possui duas observações; a base df2, por sua vez, apenas uma; x é a variável comum entre elas, e as usamos para unir as duas bases; mas como df2 não possui x == 2, o resultado final é uma base com missing na variável z, que estava presente na base df2. Se quisermos alterar esse compartamento da função, preservarndo os valores da segunda base, usamos outra função, a à right_join.

# Une as duas bases com right_join right_join(df, df2, by = c("x" = "x"))

## x y z ## 1 2 11 99 ## 2 3 NA 100

O resultado, agora, é que temos um missing na variável y, que está na base df. Podemos manter as variáveis disponíveis nas duas bases, combinando o máximo possível de informações em cada uma, usando a função full_join.

# Une as duas bases com full_join full_join(df, df2, by = c("x" = "x"))

## x y z ## 1 1 10 NA ## 2 2 11 99 ## 3 3 NA 100

Dessa vez, o resultado é um banco com três observações que preserva todos os valores de cada base e que, além disso, adiciona missings às células que não encontraram correspondência em cada base. O que importa observar, entretanto, é que o dplyr possui funções específicas para cada operação de junção de dados baseada em valores comuns de dois bancos diferentes. Outro detalhe importante: quando uma banco possui valores duplicados nas variáveis declaradas em by (e.g., se BA aparecer em duas observações diferentes) elas também serão duplicadas na base final usando tanto rigth_, left_ ou full_join. Como diz a documentação das funções (que pode ser consultada com ?full_join), “Se houver múltiplas combinações entre x e y, todas elas serão retornadas.”13

Brevemente, podemos ver algumas outras dessas funções de _join, que podem ser úteis em alguns contextos.

# Cria uma base ficticia base1 <- data.frame(A = 1:5, B = letters[1:5]) base2 <- data.frame(X = rnorm(5), B = letters[3:7]) # inner_join mantem apenas valores com correspondencia nas duas bases inner_join(base1, base2, by = c("B" = "B"))

## A B X ## 1 3 c 1.86118774 ## 2 4 d -0.05562058 ## 3 5 e 0.43340640

# anti_join faz o contrario: mantem apenas valores sem correspondecia entre bases anti_join(base1, base2, by = c("B" = "B"))

## A B ## 1 1 a ## 2 2 b

Por fim, uma última operação de união de dados pode ser útil em alguns casos: os binds_. Diferentemente das funções _join, que juntam bancos de dados fazendo cruzamentos com base em variáveis comuns em ambas, binds_ servem para empilhar bancos, isto é, adicionar mais observações ou mais colunas a um banco. Um simples exemplo ajuda na compreensão.

# Cria duas bases ficticias df1 <- data.frame(x = 1:3, y = letters[1:3]) df2 <- data.frame(x = 4:6, y = letters[4:6]) # Empilha as bases pelas observacoes bind_rows(df1, df2)

## x y ## 1 1 a ## 2 2 b ## 3 3 c ## 4 4 d ## 5 5 e ## 6 6 f

# Une as bases pelas colunas bind_cols(df1, df2)

## x y x1 y1 ## 1 1 a 4 d ## 2 2 b 5 e ## 3 3 c 6 f

Apesar de simples, as funções bind_rows e bind_cols, portanto, podem ser usadas para acrescentar novas variáveis, ou mais observações, a uma banco. Dois detalhes devem ser entendidos: primeiro, não é possível unir bases com número de observações diferentes com bind_cols; já no caso da bind_rows, é necessário atentar para a classe das variáveis – caso uma variável x seja numeric numa base e, digamos, character em outra, teremos erro – e o nome delas, caso contrário o seguinte pode ocorrer:

# Exemplo de bind_rows em bancos com variaveis diferentes df1 <- data.frame(x = 1:3, y = letters[1:3]) df2 <- data.frame(z = 4:6, y = letters[4:6]) # Empilha as bases pelas observacoes bind_rows(df1, df2)

## x y z ## 1 1 a NA ## 2 2 b NA ## 3 3 c NA ## 4 NA d 4 ## 5 NA e 5 ## 6 NA f 6

As funções vistas até agora, conforme dito no começo desse capítulo, cobrem o principal da análise de dados – raramente encontraremos bancos de dados que precisem ser arrumados com outras ferramentas. Isso, contudo, não significa que a limpeza de uma banco de dados real será fácil. Ao contrário, normalmente precisaremos combinar várias das funções vistas, às vezes de forma alternada. Como é possível imaginar, isso frequentemente nos força a escrever inúmeras linhas de código. Vamos tomar, como exemplo, a primeira base de dados com que trabalhos, sobre os homícidios nos estados brasileiros, organizando ela em formato tidy, removendo observações de anos anterior a 2005 e removendo algumas variáveis desnecessárias, como o código dos estados.

# Carrega o pacote readxl para abrir planilhas de excel # E os pacotes dplyr e tidyr, para manipular dados library(readxl) library(dplyr) library(tidyr) # Carrega a base de homicidios homic <- read_excel("homicidios_uf.xls") # Transforma a base para formato tidy homic <- gather(homic, ano, homicidios, -Sigla, -Codigo, -Estado) # Filtra observacoes anteriores a 2005 homic <- filter(homic, ano > 2005) # Remove variaveis desnecessarias homic <- select(homic, -Codigo) # Base final homic

## # A tibble: 108 x 4 ## Sigla Estado ano homicidios ## <chr> <chr> <chr> <dbl> ## 1 AC Acre 2006 155 ## 2 AL Alagoas 2006 1617 ## 3 AM Amazonas 2006 697 ## 4 AP Amapá 2006 203 ## 5 BA Bahia 2006 3276 ## 6 CE Ceará 2006 1793 ## 7 DF Distrito Federal 2006 769 ## 8 ES Espírito Santo 2006 1774 ## 9 GO Goiás 2006 1409 ## 10 MA Maranhão 2006 925 ## # ... with 98 more rows

Apesar de funcional, o código é cansativo. Precisamos, primeiramente, redigir o nome do objeto com os dados, homic, oito vezes, usar o operador de atribuição, <-, quatro e, além disso, tivemos de realizar cada operação uma a uma antes de prosseguir. Toda essa repetição não passou desapercebida por outras pessoas e, principalmente em decorrência disso, o operador %>%, chamado pipe, foi criado. Com ele, todo esse processo pode ser reduzido da seguinte forma:

# Limpa a base de homicidios homic <- read_excel("homicidios_uf.xls") %>% gather(ano, homicidios, -Sigla, -Codigo, -Estado) %>% filter(ano > 2005) %>% select(-Codigo) # Base final homic

## # A tibble: 108 x 4 ## Sigla Estado ano homicidios ## <chr> <chr> <chr> <dbl> ## 1 AC Acre 2006 155 ## 2 AL Alagoas 2006 1617 ## 3 AM Amazonas 2006 697 ## 4 AP Amapá 2006 203 ## 5 BA Bahia 2006 3276 ## 6 CE Ceará 2006 1793 ## 7 DF Distrito Federal 2006 769 ## 8 ES Espírito Santo 2006 1774 ## 9 GO Goiás 2006 1409 ## 10 MA Maranhão 2006 925 ## # ... with 98 more rows

Os dois exemplos produzem o mesmo resultado, mas o segundo não apenas é muito mais enxuto como, também, melhor organizado. É por essa razão que os pipes são crescentemente usados pela comunidade de R ao redor do mundo, fazendo com que não seja incomum encontrarmos códigos na internet que os usem. Apenas por isso, já vale o esforço de entender como eles funcionam. Para usá-lo, podemos simplesmente carregar o pacote dplyr, que o contém, ou instalar e carregar o pacote magrittr.14

Em termos simples, pipes nada mais são do que operadores. Assim como usamos <- para atribuir valores a um objeto, ou + para somar dois valores numéricos, pipes servem para ligar dois processos: no caso específico, para jogar os resultados de uma sequência para outra. Para dois dos maiores popularizadores dessa forma de escrever código (Wickham and Grolemund 2016), as vantagens dela são principalmente duas: primeiro, ela reduz a repetição de códigos desnecessários, evitando que, a cada passo de uma análise, seja necessário criar ou salvar os resultados em algum objeto (i.e., usando homic <- várias vezes, como no primeiro original); segundo, isso traz a vantagem de dar mais ênfase aos verbos, funções no R, já que cada linha de código aplica alguma transformação e, por isso mesmo, qualquer código pode passar a ser lido como uma sequência de processos do tipo carrega %>% seleciona %>% filtar %>% une, por exemplo.

Vamos focar em alguns exemplos mais simples por um momento.

# Carrega o pacote dplyr (que possui os pipes) library(dplyr) # Calcula a raiz quadrada de 4 x <- 4 sqrt(4)

## [1] 2

# Calcula a raiz quadrada de 4 usando pipes x %>% sqrt()

## [1] 2

O resultado, novamente, é o mesmo, mas o processo é diferente. No segundo caso, o %>% atua jogando o valor da linha anterior, salvo no objeto x, para a função da próxima linha. E isso, como vimos anteriormente, pode prosseguir com a adição de novos pipes.

4 %>% sqrt() %>% # Calcula a raiz quadrada de 4 sum(14) %>% # Adiciona 14 ao resultado da linha anterior sqrt() # Calcula a raiz quadrada do resultado da linha anterior

## [1] 4

Traduzindo o código, o que fizemos foi simplesmente jogar o 4 da primeira linha para a segunda, onde a função sqrt – cabe notar aqui que, como o valor a ela foi alimentado pelo pipe na linha anterior, não foi preciso suprir nenhum argumento, deixando ela vazia, sqrt(). Após calcularmos a raiz quadrada de 4, que é 2, usando um pipe para jogar esse resultado para a função na linha seguinte, sum, onde o valor foi somado a 14. Por fim, do resultado de 2 + 14 (sum(2, 14)), calculamos novamente a raiz quadrada com a função sqrt. O exemplo é trivial, mas a ideia por detrás dele, não: pipes permitem encadear várias sequências de operações, sem a necessidade de codificarmos, etapa por etapa, cada uma delas. O mesmo código, agora sem pipes.

x <- sqrt(4) # Calcula a raiz quadrada de 4 x <- sum(x, 14) # Adiciona 14 ao resultado da linha anterior x <- sqrt(x) # Calcula a raiz quadrada do resultado da linha anterior x

## [1] 4

Como é possível ver, o uso de pipes simplifica enormente a tarefa de emendar funções no R, mas, certamente, essa pode não ser a forma mais natural de pensar em um código. Trabalhar com pipes exige algum esforço de adaptação no início, embora os ganhos de produtividade e clareza na criação de scripts sejam grandes o suficiente para compensar o seu uso. Em todo o caso, daqui até o final deste livro não usaremos pipes, embora acreditemos que seja um bom exercício adaptar os exemplos que trabalhos adiante para inclui-los.

Wickham, Hadley, and Garrett Grolemund. 2016. “R for Data Science.” Sebastopol, CA: O’Reilly. http://​ r4ds.​ had.​ co.​ nz.

Frankfort-Nachmias, Chava, and David Nachmias. 2007. Study Guide for Research Methods in the Social Sciences. Macmillan.

Wansbeek, Tom, and Erik Meijer. 2008. “Measurement Error and Latent Variables.” A Companion to Theoretical Econometrics. John Wiley & Sons, 162.

Wickham, Hadley. 2014. “Tidy Data.” Journal of Statistical Software 59 (10). Foundation for Open Access Statistics: 1–23.