Introdução

Anteriormente, introduzimos os conceitos básicos de programação no R. Nesse capítulo, iremos conhecer uma poderosa ferramenta de organização de dados no R, o pacote dplyr. Ele será nossa ferramenta básica para manipulação de tabelas. Creio que não haverá um dia sequer em que você use o R sem recorrer ao dplyr.

Por que usar o dplyr?

  • Extraordinária capacidade de transformação dos dados
  • Escrita intuitiva e de fácil leitura
  • Rápido

Funcionamento do dplyr

  • Seis verbos básicos: filter,count, select, arrange, mutate e summarise (além do group_by)
  • Permite trabalhar com dados relacionais data tables
  • Fusões: inner_join, left_join, semi_join, anti_join
  • Funções de agregação
  • Funções janela (window functions) para calcular ranqueamento, balanceamento e diferenças

Carregando o dplyr e o base exemplo

  • dplyr mascara algumas funções do pacote base
# Carregando os pacotes
library(tidyverse)
library(tjsp)

Baixando os dados do TJSP

diretorio <- tempdir()

baixar_cjpg("alienacao parental", aspas = TRUE, diretorio = diretorio)
alienacao_parental <- ler_cjpg(diretorio = diretorio)
  • tbl_df cria uma “data frame local”
  • Data frame local é simplesmente um wrapper de um dataframe para impressão mais atraente e intuitiva.
# converte para data frame local
alienacao_parental <- as.data.frame(alienacao_parental)

r results='hide' # você pode especificar que quer mais linhas print(flights, n=20) # converter para dataframe normal para ver todas as colunta data.frame(head(aliencao_parental))

alienacao_parental <- classificar_sentencas(alienacao_parental, sentenca = julgado, decisao = "decisao")

count: Gera frequências

freq_decisao <- count(alienacao_parental,decisao, sort = TRUE)
View(freq_decisao)

filter: Mantêm linhas usando um critério

  • A abordagem do R Base força a repedir o nome do data frame
  • A abordagem do dplyr é simples para escrever e ler
  • Estrutura de comando para todos os verbos dplyr:
    • primeiro argumento é um data frame
  • o valor resposta é um data frame
  • nada é modificado no lugar
  • Obs: o dplyr geralmente não preserva nomes de linhas
# abordagem dplyr
# obs: você pode usar vírgula ou e comercial (&) para representar condição E
merito <- filter(alienacao_parental, decisao == "improcedente", comarca=="SÃO PAULO")

View(merito)

# Use barra vertical para condição OU
sp_gru <- filter(alienacao_parental, comarca=="SÃO PAULO" | comarca=="Guarulhos")
# você pode também usar o operador %in%
sp_gru<-filter(alienacao_parental, comarca %in% c("SÃO PAULO", "Guarulhos"))

select: Selecionar colunas por nome

  • Abordagem do R base é estranha para escrever e ler
  • abordagem dplyr usa sintaxe similar ao filter
  • Como L SELECT no SQL
# abordagem dplyr
selecao <- select(alienacao_parental, processo, classe, assunto)
# use dois pontos para selecionar múltiplas colunas contiguas e `contains` para selecionar colunas quem contenham certos caracteres no nome
# nota: `starts_with`, `ends_with`, e `matches` (para expressões regulares) também pode ser usada para selecionar colunas por nome

selecao <- select(alienacao_parental, processo, classe, assunto)

selecao <- select(alienacao_parental, classe:foro, contains("decisao"), contains("disponibilizacao"))

selecao <- select(alienacao_parental, 2,5)

“Encadeamento” ou “Pipelining”

  • A maneira comum de realizar múltiplas operações em uma linha é usar aninhamento (nesting)
  • Pipes permitem escrever os comandos numa ordem natural por meio do uso do símbolo %>% (que pode ser pronunciado como “então”)

Método aninhamento

Método de aninhamento para selecionar as colunas classe e assunto para, em seguida, filtrar para assunto Guarda.

classe_assunto <- filter(select(alienacao_parental, classe, assunto), assunto == "Guarda")

método de encadeamento (pipelining)


classe_assunto <- alienacao_parental %>%
  select(classe, assunto) %>%
  filter(assunto == "Guarda")
  • Encadeamento aumenta significativamente a legibilidade quando há muitos comandos
  • O operador é importado automaticamente do pacote magrittr
  • Pode ser usado para substituir comandos aninhados fora do dplyr
# cria dois vetores e calcula a distância euclidiana entre eles
x1 <- 1:5; x2 <- 2:6
sqrt(sum((x1-x2)^2))
# método de encadeamento
(x1-x2)^2 %>%
sum() %>%
sqrt()

arrange: Reordenar linhas

# abordagem dplyr
organiza <- alienacao_parental %>%
  select(classe, assunto) %>%
  arrange(classe)
# use `desc` para ordem decrescente
organiza <- alieancao_parental %>%
  select(classe, assunto) %>%
  arrange(desc(classe))

mutate: Adicionar novas variáveis

  • Cria novas variáveis que são funções das variáveis já existentes
library(lubridate)
alienacao_parental <- alienacao_parental %>%
  mutate(mes = month(disponibilizacao, label = TRUE))

summarise: Reduz as variáveis a valores

  • Especialmente útil com dados a serem agrupados com base em uma ou mais variáveis
  • group_by cria os grupos com base nos quais os verbos irão operar
  • summarise usa a função de agregação para sumariar cada grupo

## Cria função para obter remuneração dos juízes
remuneracao_trepr <- function(url = ""){

remuneracao <- tempfile(fileext=".csv")


download.file(url = url, destfile = remuneracao)

readr::read_delim(remuneracao, 
    ";", escape_double = FALSE, locale = locale(encoding = "ISO-8859-1"), 
    trim_ws = TRUE, skip = 6)
}
## Extrai remuneração

link <- "https://apps.tre-pr.jus.br/internet2/download/downloadbyID.do?id=1564683604739509&modelo=branco&nome=AnexoVJJul2019.csv"

rem <- remuneracao_trepr(url=link)

## Corrigir os nomes

#install.packages("janitor")
library(janitor)
rem <- clean_names(rem)
flights %>%
  group_by(Dest) %>%
  summarise(avg_delay = mean(ArrDelay, na.rm=TRUE))
  • summarise_all permite você aplicar a mesma função de sumarização para múltiplas colunas de uma vez
  • Nota: mutate_all também está disponível
# Para cada companhia, calcule a porcentagem de voos cancelados ou alterados
flights %>%
  group_by(UniqueCarrier) %>%
  summarise_at(c("Cancelled", "Diverted"), mean)
# para cada companhia, calcule os atrasos  mínimos e máximos de chegada e partida
flights %>%
  group_by(UniqueCarrier) %>%
  summarise_at(vars(contains("Delay")),funs(min(., na.rm=TRUE), max(., na.rm=TRUE)))
  • A função n() conta o número de linhas em um grupo
  • A função n_distinct(vector) conta o número de ítens únicos naquele vetor
# para cada dia do ano, contar o número de total de voos e classifique em ordem descendente
flights %>%
  group_by(Month, DayofMonth) %>%
  summarise(flight_count = n()) %>%
  arrange(desc(flight_count))
# reescrevendo de forma mais simples com a função tally
flights %>%
  group_by(Month, DayofMonth) %>%
  tally(sort = TRUE)
# para cada destino, contar o número de voos e o número de aviões diferentes que voaram para lá.
flights %>%
  group_by(Dest) %>%
  summarise(flight_count = n(), plane_count = n_distinct(TailNum))
  • Agrupar pode ser útil sem necessariamente sumariar
# para cada destino, mostre o número de voos cancelados e não cancelados
flights %>%
  group_by(Dest) %>%
  select(Cancelled) %>%
  table() %>%
  head()

Funções janela

  • Funções de agregação (exemplo mean) tomam n valores e retornam um valor
  • Window function
    tomam n valores e retornam n valores
  • Inclem-se aqui funções de ranqueamento e classificação (como min_rank), funções de contrabaleceamento (lead and lag), e funções cumulativas (like cummean).
# para cada companhia, calcule quais foram os dois dias do país em que houve maiores atrasos nas partidas
# nota: o menor  (não o maior) valor é ranqueado como 1, de modo que você deve usar `desc` para ranquear pelo maior valor
flights %>%
  group_by(UniqueCarrier) %>%
  select(Month, DayofMonth, DepDelay) %>%
  filter(min_rank(desc(DepDelay)) <= 2) %>%
  arrange(UniqueCarrier, desc(DepDelay))
# reescreva de maneira mais simples com a função `top_n`
flights %>%
  group_by(UniqueCarrier) %>%
  select(Month, DayofMonth, DepDelay) %>%
  top_n(2) %>%
  arrange(UniqueCarrier, desc(DepDelay))
# Para cada mês, calcule o número de voos e a mudança em relação ao mês anterior
flights %>%
  group_by(Month) %>%
  summarise(flight_count = n()) %>%
  mutate(change = flight_count - lag(flight_count))
# Rescreva novamente simplificando com a função `tally` 
flights %>%
  group_by(Month) %>%
  tally() %>%
  mutate(change = n - lag(n))

Outras funções úteis e convenientes

# Seleção aleatória de um número fixo de linhas, sem substituição
flights %>% sample_n(5)
# Seleção aleatória de de uma fração de linhas, com substituição
flights %>% sample_frac(0.25, replace=TRUE)
# Abordagem do R base para ver os os objetos
str(flights)
# Abordagem dplyr: melhor formatação e se adapta à largura de sua tela
glimpse(flights)

Conexão com base relacionais

  • dplyr pode se conectar com bases relacionais como se elas estivessem carregadas em um data frame.
  • Uso da mesma sintaxe de data frames locais
  • Somente gera SELECT declarações
  • Atualmente suporta SQLite, PostgreSQL/Redshift, MySQL/MariaDB, BigQuery e MonetDB
  • O exemplo abaixo é baseado no SQLite contendo a base hflights
  • Instruções para criar databases está em databases vignette
# conectar a uma base SQLite contendo dados hflights 
my_db <- src_sqlite("my_db.sqlite3")
# conectar a uma tablea SQLite na base
flights_tbl <- tbl(my_db, "hflights")
# exemplo de query usando dplyr
flights %>%
  select(UniqueCarrier, DepDelay) %>%
  arrange(desc(DepDelay))
  • Você mesmo pode escrever comandos SQL
  • dplyr pode informar ao SQL que pretende rodar o plano de execução de sql
# envie comandos SQL para o data frame
tbl(my_db, sql("SELECT * FROM hflights LIMIT 100"))
# peça ao dplyr pelo SQL comando
flights_tbl %>%
  select(UniqueCarrier, DepDelay) %>%
  arrange(desc(DepDelay)) %>%
  explain()

Recursos