-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy path06-pipe.Rmd
225 lines (154 loc) · 6.45 KB
/
06-pipe.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# Pipe {#pipe}
```{r, include=FALSE}
library(magrittr)
```
O operador `%>%` (*pipe*) foi uma das grandes revoluções recentes do R, tornando a escrita e leitura de códigos mais intuitiva e compreensível. Ele foi introduzido por [Stefan Milton Bache](https://github.com/smbache) no pacote `magrittr`, cujo nome é uma referência ao famoso quadro do pintor belga René Magritte *La Trahison des images (Ceci n'est pas une pipe)*.
```{r, echo=FALSE, fig.cap="Reprodução do quadro La Trahison des images (Ceci n’est pas une pipe). do pintor René Magritte."}
knitr::include_graphics("assets/img/pipe/ceci-nest-pas-une-pipe.jpg")
```
Para começar a utilizar o *pipe*, instale e carregue o pacote `magrittr`.
```{r eval=FALSE}
install.packages("magrittr")
library(magrittr)
```
## 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.
```{r, eval=FALSE}
# As duas linhas abaixo são equivalentes.
f(x, y)
x %>% f(y)
```
Nos casos mais simples, o *pipe* parece não trazer grandes vantagens. Agora, veja como fica um caso com mais etapas.
```{r}
# Vamos calcular a raiz quadrada da soma dos valores de 1 a 4. Primeiro, sem o pipe.
x <- c(1, 2, 3, 4)
sqrt(sum(x))
# Agora com o pipe.
x %>% sum() %>% sqrt()
```
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.
```{r, eval=FALSE}
# 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.
```{r}
# 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()
```
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 `%>%`.
```{r, collapse = TRUE, eval = FALSE}
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 `%>%`.
```{r, collapse = TRUE, eval = FALSE}
x <- rnorm(100)
x.pos <- x[x>0]
media <- mean(x.pos)
saida <- round(media, 1)
```
**3.** Sem rodar, diga qual a saída do código abaixo. Consulte o help das funções caso precise.
```{r, collapse = TRUE, eval = FALSE}
2 %>%
add(2) %>%
c(6, NA) %>%
mean(na.rm = T) %>%
equals(5)
```
## Outros operadores
O pacote `{magrittr}` possui outros operadores, que, embora sejam menos utilizados, também são úteis. São eles:
- *Assignment operator* `%<>%`
- *Operador tee* `%T>%`
- *Exposition operator* `%$%`
Imagine que queremos tirar a raiz quadrada de um vetor de números.
```{r}
x <- c(1, 2, 3, 4, 5)
x %>% sqrt()
```
Se quisermos sobrescrever o objeto `x` com a raiz quadrada dos seus valores, basta utilizarmos o nosso bom e velho operador de atribuição `<-`.
```{r}
x <- x %>% sqrt()
```
Podemos, no entanto, utilizar o operador `%<>%` para reescrever o código acima de uma maneira mais compacta.
```{r}
x <- c(1, 2, 3, 4, 5)
x %<>% sqrt()
```
Além de mandar o objeto `x` para o primeiro argumento da função `sqrt()`, assim como o `%>%` faria, esse operador também salva o resultado da operação de volta no objeto `x`, o sobrescrevendo.
Este operador pode ser usado sempre que desejamos fazer algo da forma
```{r, eval = FALSE}
objeto <- objeto %>%
funcao_1() %>%
funcao_2() %>%
...
funcao_n()
```
O operador `%T>%` retorna o valor do comando anterior a ele, não o resultado do lado direito como o `%>% ` faz. O seguinte exemplo vai imprimir na tela os valores de 1 a 10. Se usássemos o pipe, o código retornaria a soma dos dez números.
```{r}
1:10 %T>% sum() %>% cat()
```
Neste caso, o operador não parece fazer sentido e apenas deixa o código mais complicado, mas se desejamos usar funções como `cat()` ou `plot()` que não retornam nada, o operador se torna muito útil.
```{r}
# Vamos imprimir na tela os valores de 1 a 10 e depois soma-los.
1:10 %T>%
cat() %>%
sum()
```
O operador `%$%` pode ser utilizado para *expor* as colunas de um *data frame* para a função aplicada no lado direito.
```{r}
# Podemos chamar qualquer coluna da base diretamente.
mtcars %$% mean(mpg)
```
Se não ficou claro o que esse operador está fazendo, imagine que ele transforma todas as colunas da base em objetos (assim como a nefasta função `attach()`), mas sem salvar nada no nosso *environment*.
```{r}
mtcars %$%
mpg %>%
mean() %>%
sqrt()
```
Ele faz um papel equivalente ao operador `$`.
```{r}
mtcars$mpg
mtcars %$% mpg
```
Para mais informações sobre o `pipe` e outras funções do pacote `{magrittr}`, visite a página [Ceci n'est pas un pipe](http://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html).