6.1 O operador pipe
A ideia do operador %>%
(pipe) é bem simples: usar o valor resultante da expressão do lado esquerdo como primeiro argumento da função do lado direito.
# As duas linhas abaixo são equivalentes.
f(x, y)
%>% f(y) x
Nos casos mais simples, o pipe parece não trazer grandes vantagens. Agora, veja como fica um caso com mais etapas.
# Vamos calcular a raiz quadrada da soma dos valores de 1 a 4. Primeiro, sem o pipe.
<- c(1, 2, 3, 4)
x sqrt(sum(x))
## [1] 3.162278
# Agora com o pipe.
%>% sum() %>% sqrt() x
## [1] 3.162278
O caminho que o código x %>% sum %>% sqrt
seguiu foi enviar o objeto x
como argumento da função sum()
e, em seguida, enviar a saida da expressão sum(x)
como argumento da função sqrt()
. Observe que escrevemos o código na mesma ordem em que as operações são realizadas. A utilização de parênteses após o nome das funções não é necessário, mas recomendável.
Se você ainda não está convencido com o poder do pipe, fica que vai ter bolo!
No exemplo abaixo, vamos ilustrar um caso em que temos um grande número de funções aninhadas. Veja como a utilização do pipe transforma um código confuso e difícil de ser lido em algo simples e intuitivo.
# Receita de bolo sem pipe. Tente entender o que é preciso fazer.
esfrie(
asse(
coloque(
bata(
acrescente(
recipiente(
rep("farinha", 2),
"água",
"fermento",
"leite",
"óleo"
), "farinha",
ate = "macio"
), duracao = "3min"
), lugar = "forma",
tipo = "grande",
untada = TRUE
), duracao = "50min"
), lugar = "geladeira",
duracao = "20min"
)
# Veja como o código acima pode ser reescrito utilizando-se o pipe. Agora realmente se parece com uma receita de bolo.
recipiente(rep("farinha", 2), "água", "fermento", "leite", "óleo") %>%
acrescente("farinha", ate = "macio") %>%
bata(duracao = "3min") %>%
coloque(lugar = "forma", tipo = "grande", untada = TRUE) %>%
asse(duracao = "50min") %>%
esfrie(lugar = "geladeira", duracao = "20min")
Às vezes, queremos que o resultado do lado esquerdo vá para outro argumento do lado direito, que não o primeiro. Para isso, utilizamos um .
como marcador.
# Queremos que o dataset seja recebido pelo segundo argumento (data=) da função "lm".
%>%
airquality na.omit() %>%
lm(Ozone ~ Wind + Temp + Solar.R, data = .) %>%
summary()
##
## Call:
## lm(formula = Ozone ~ Wind + Temp + Solar.R, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -40.485 -14.219 -3.551 10.097 95.619
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -64.34208 23.05472 -2.791 0.00623 **
## Wind -3.33359 0.65441 -5.094 1.52e-06 ***
## Temp 1.65209 0.25353 6.516 2.42e-09 ***
## Solar.R 0.05982 0.02319 2.580 0.01124 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 21.18 on 107 degrees of freedom
## Multiple R-squared: 0.6059, Adjusted R-squared: 0.5948
## F-statistic: 54.83 on 3 and 107 DF, p-value: < 2.2e-16
O pipe é a força da gravidade dentro do tidyverse
. Veremos nos próximos capítulos como as funções de diferentes pacotes interagem perfeitamente graças a esse operador.
Exercícios
1. Reescreva a expressão abaixo utilizando o %>%
.
round(mean(sum(1:10)/3), digits = 1)
Dica: utilize a função magrittr::divide_by()
. Veja o help da função para mais informações.
2. Reescreva o código abaixo utilizando o %>%
.
<- rnorm(100)
x
<- x[x>0]
x.pos
<- mean(x.pos)
media
<- round(media, 1) saida
3. Sem rodar, diga qual a saída do código abaixo. Consulte o help das funções caso precise.
2 %>%
add(2) %>%
c(6, NA) %>%
mean(na.rm = T) %>%
equals(5)