Mostrar/ocultar código
# install.packages("nycflights13")
library(tidyverse)
library(nycflights13)
library(gt)10/02/2026
Aula baseada no Capítulo 3 do livro: R for Data Science https://learning.oreilly.com/library/view/r-for-data/9781492097396/ch03.html#data-transform-prerequisites
Nem sempre os dados estão da maneira que queremos. Muitas vezes temos que:
criar novas variáveis
criar sumários para responder perguntas
renomear variáveis
reordenar observações
Por isso, vamos aprender ferramentas para fazer isso usando o pacote dplyr`.
nycflights13 e tidyverseflihgts para explorar os principais verbos do pacote dplyr# install.packages("nycflights13")
library(tidyverse)
library(nycflights13)
library(gt)dados <- flights
glimpse(dados)
# View(dados)dplyr básicoAntes de aprender os verbos (funções), temos que entender o que tem em comum:
O primeiro argumento é sempre um dataframe (base de dados).
Os argumentos subsequentes descrevem em que colunas vamos fazer as operações, usando o nome das variáveis sem aspas
A saída sempre será um novo dataframe.
Para combinar múltiplos verbos, usamos o operador Pipe (|>), que basicamente encadeia as funções. (Atalho no teclado: Ctrl + Shift + M ou Cmd (⌘) + Shift + M) Vamos ver um exemplo:
(se quiser ver um pouco mais sobre os dados: ?flights)
dados |>
filter(dest == "IAH") |>
group_by(year, month, day) |>
summarize(
arr_delay = mean(arr_delay, na.rm = TRUE)
)airports |>
filter(faa == "IAH") |> gt()O que estamos fazendo aqui?
Os verbos do dplyr são organizados em 4 grupos baseado em suas operações:
linhas
colunas
grupos
tabelas
Os verbos mais importantes são:
filter(): escolhe que linhas são mostradas sem alterar a ordem
arrange(): muda a ordem das linhas sem alterar o que é apresentado.
distinct(): encontra linhas com valores únicos, também pode modificar colunas
filter()dados |>
filter(dep_delay > 120)Podemos usar qualquer sinal de comparação: >=, <=, <, == (sinal de igualdade); podemos usar & ou ,para “E” e | para “OU”.
Voos que partiram em 1 de Janeiro:
dados |>
filter(month == 1, day == 1)dados |>
filter(month == 1 | month == 2)%in% para quando o filtro está em uma lista, por exemplo:dados |>
filter(month %in% c(1, 2))arrange()dados |>
arrange(year, month, day, dep_time)desc():dados |>
arrange(desc(dep_delay))O tempo de atraso de saída dep_delay está ordenado do maior para o menor tempo de atraso.
distinct()dados |>
distinct()dados |>
distinct(origin, dest)Temos 224 pares distintos de destino e chegada.
.keep_all = TRUEdados |>
distinct(origin, dest, .keep_all = TRUE)Note que todos os voos estão com data 1 de janeiro, porque encontramos a primeira linha única e depois descartamos o resto.
count() (que veremos mais a frente):dados |>
count(origin, dest, sort = TRUE)In a single pipeline for each condition, find all flights that meet the condition:
Had an arrival delay of two or more hours
Flew to Houston (IAH or HOU)
Were operated by United, American, or Delta
Departed in summer (July, August, and September)
Arrived more than two hours late, but didn’t leave late
Were delayed by at least an hour, but made up more than 30 minutes in flight
Sort flights to find the flights with the longest departure delays. Find the flights that left earliest in the morning.
Sort flights to find the fastest flights. (Hint: Try including a math calculation inside of your function.)
Was there a flight on every day of 2013?
Which flights traveled the farthest distance? Which traveled the least distance?
Does it matter what order you used filter() and arrange() if you’re using both? Why/why not? Think about the results and how much work the functions would have to do.
Verbos importantes:
mutate()
select()
rename()
relocate()
mutate()Adiciona novas colunas que são calculadas a partir de colunas existentes.
Vamos calcular o ganho e a velocidade em milhas por hora.
dados |>
mutate(
ganho = dep_delay - arr_delay,
velocidade = distance / air_time * 60
).before.dados |>
mutate(
ganho = dep_delay - arr_delay,
velocidade = distance / air_time * 60,
.before = 1
).before e .after para inserir as variáveis em qualquer lugar da nossa base de dados. Por exemplo, depois da variável day :dados |>
mutate(
ganho = dep_delay - arr_delay,
velocidade = distance / air_time * 60,
.after = day
).keep . Um argumento particular é o used. Ele especifica que mantenhamos apenas as variáveis usadas nos cálculos.dados |>
mutate(
ganho = dep_delay - arr_delay,
horas = air_time / 60,
ganho_por_hora = ganho/horas,
.keep = "used"
)select()Permite que você selecionae um subconjunto das variáveis do seu dataset.
Por exemplo, selecionar o ano, mês e dia
dados |>
select(year, month, day)Selecionar todas as colunas entre year e day inclusive:
dados |>
select(year:day)dados |>
select(!year:day)dados |>
select(where(is.character)) Há vários funções que podem ajudar na seleção de variáveis:
starts_with("abc")
ends_with("abc")
contains("ijk")
num_range("x", 1:3)
Também podemos renomear variáveis com select() usando o “=”. O novo nome vem do lado esquerdo, e o antigo do lado direito:
dados |>
select(tail_num = tailnum)rename()dados |>
rename(tail_num = tailnum)janitor::clean_names() que fornece uma limpeza automática de maneira útil.relocate()dados |>
relocate(time_hour, air_time).before() e .after() da mesma forma que fizemos com o verbo mutate().dados |>
relocate(year:dep_time, .after = time_hour)dados |>
relocate(starts_with("arr"), .before = dep_time) |>
View()Compare dep_time, sched_dep_time, and dep_delay. How would you expect those three numbers to be related?
Brainstorm as many ways as possible to select dep_time, dep_delay, arr_time, and arr_delay from flights.
What happens if you specify the name of the same variable multiple times in a select() call?
What does the any_of() function do? Why might it be helpful in conjunction with this vector?
variables <- c("year", "month", "day", "dep_delay", "arr_delay")Does the result of running the following code surprise you? How do the select helpers deal with upper- and lowercase by default? How can you change that default?
flights |> select(contains("TIME"))Rename air_time to air_time_min to indicate units of measurement and move it to the beginning of the data frame.
Por que a função abaixo não funciona e o que a mensagem de erro nos diz?
flights |>
select(tailnum) |>
arrange(arr_delay)
#> Error in `arrange()`:
#> ℹ In argument: `..1 = arr_delay`.
#> Caused by error:
#> ! object 'arr_delay' not found|>Atalho: Ctrl/Cmd+Shift+M
Vimos alguns exemplos simples com pipe, mas seu maior uso vem quando combinamos múltiplos verbos para responder à alguma pergunta:
Por exemplo,
Quais os vôos mais rápidos com destino ao aeroporto de Houston (IAH)?
filter(), mutate(), select(), e arrange().dados |>
filter(dest == "IAH") |>
mutate(speed = distance/air_time * 60,
velocidade_km_h = 1.61 * speed) |>
select(year:day, dep_time, carrier, flight, speed, velocidade_km_h) |>
arrange(desc(speed)) |> View()Principais verbos:
group_by()
summarize()
group_by()Divide a sua base de dados em grupos úteis para a sua análise.
dados |>
group_by(month)Fazendo somente essa operação não muda muita coisa, mas agora vemos que os dados estão agrupados, e qualquer operação que realizarmos, será feita dentro de cada grupo.
summarize()A operação mais importante de um grupo é o sumário de informações dentro de cada grupo.
Daí, teremos uma única linha para cada grupo e seu sumário, respectivamente.
Calculando o atraso de partidas por mês.
dados |>
group_by(month) |>
summarize(
atraso_medio = mean(dep_delay, na.rm = TRUE)
)Qual foi o mês com mais atrasos?
dados |>
group_by(month) |>
summarize(
atraso_medio = mean(dep_delay, na.rm = TRUE)
) |>
arrange(desc(atraso_medio))dados |>
group_by(year, month) |>
summarize(qtd_voos = n()) |>
ungroup() |>
arrange(desc(qtd_voos))sumario_voos <- dados |>
group_by(month) |>
summarize(
qtd_voos = n(),
atraso_medio = mean(dep_delay, na.rm = TRUE)
)slice\_df |> slice_head(n = 1) -> mostra a primeira linha de cada grupo.
df |> slice_tail(n = 1) -> mostra a última linha de cada grupo.
df |> slice_min(x, n = 1) -> Mostra a linha com o menor valor da coluna x.
df |> slice_max(x, n = 1) -> Mostra a linha com maior valor da coluna x.
df |> slice_sample(n = 1) -> Mostra uma linha aleatória.
Mostrando as duas primeiras linhas:
sumario_voos |>
slice_head(n = 2)# A tibble: 2 × 3
month qtd_voos atraso_medio
<int> <int> <dbl>
1 1 27004 10.0
2 2 24951 10.8
sumario_voos |>
slice_tail(n = 2)# A tibble: 2 × 3
month qtd_voos atraso_medio
<int> <int> <dbl>
1 11 27268 5.44
2 12 28135 16.6
sumario_voos |>
slice_min(qtd_voos, n = 1)# A tibble: 1 × 3
month qtd_voos atraso_medio
<int> <int> <dbl>
1 2 24951 10.8
sumario_voos |>
slice_max(qtd_voos, n = 1)sumario_voos |>
slice_sample(n = 1)dados |>
group_by(dest) |>
slice_max(arr_delay, n = 1) |>
relocate(dest)Podemos usar a função ungroup(), para remover o agrupamento.
Isso é importante para se fazer algumas operações considerando todo o dataset ao invés somente dos grupos.
Which carrier has the worst average delays? Challenge: Can you disentangle the effects of bad airports versus bad carriers? Why/why not? (Hint: Think about flights |> group_by(carrier, dest) |> summarize(n()).)
Find the flights that are most delayed upon departure from each destination.
How do delays vary over the course of the day. Illustrate your answer with a plot.
What happens if you supply a negative n to slice_min() and friends?
Explain what count() does in terms of the dplyr verbs you just learned. What does the sort argument to count() do?
Suppose we have the following tiny data frame:
df <- tibble(
x = 1:5,
y = c("a", "b", "a", "a", "b"),
z = c("K", "K", "L", "L", "K")
)
Write down what you think the output will look like; then check if you were correct and describe what group_by() does.
df |>
group_by(y)Write down what you think the output will look like; then check if you were correct and describe what arrange() does. Also comment on how it's different from the group_by() in part (a).
df |>
arrange(y)Write down what you think the output will look like; then check if you were correct and describe what the pipeline does.
df |>
group_by(y) |>
summarize(mean_x = mean(x))Write down what you think the output will look like; then check if you were correct and describe what the pipeline does. Then, comment on what the message says.
df |>
group_by(y, z) |>
summarize(mean_x = mean(x))Write down what you think the output will look like; then check if you were correct and describe what the pipeline does. How is the output different from the one in part (d)?
df |>
group_by(y, z) |>
summarize(mean_x = mean(x), .groups = "drop")Write down what you think the outputs will look like; then check if you were correct and describe what each pipeline does. How are the outputs of the two pipelines different?
df |>
group_by(y, z) |>
summarize(mean_x = mean(x))
df |>
group_by(y, z) |>
mutate(mean_x = mean(x))