O {dplyr}
é um pacote incrível pois permite realizar operações difíceis de forma iterada e intuitiva. Uma grande facilidade do {dplyr}
é a possibilidade de utilizar os nomes das variáveis sem encapsular com aspas, o que torna a programação mais fluida e compreensível.
Por exemplo, é fácil argumentar que
mtcars %>%
summarise(soma = sum(cyl ^ 2))
é mais intuitivo que
mtcars %>%
summarise(cyl = sum(mtcars$cyl ^ 2))
ou ainda
mtcars %>%
mutate(cyl = sum(mtcars[["cyl"]] ^ 2))
No entanto, ao usar o {dplyr}
com frequência, passamos a querer colocá-lo em todos os contextos possíveis, como novas função ou Shiny apps. Assim, gostaríamos de fazer algo do tipo
minha_fn <- function(dados, variavel) {
dados %>%
summarise(nova_variavel = sum(variavel ^ 2))
}
No entanto, ao experimentar isso, temos o erro
mtcars %>%
minha_fn(cyl)
# > Error: object 'cyl' not found
Você já se deparou com essa situação? É bem frustrante. A verdade é que o tidyverse
foi desenvolvido com foco em facilitar o trabalho de análise, com o custo de dificultar o trabalho de programação.
Porém, graças a avanços recentes no pacote {rlang}
, isso está ficando mais fácil. Nesse post vou mostrar três casos casos comuns de programação com o tidyverse, e suas soluções. Para casos mais complicados, recomendo dar uma olhada no livro sobre Tidyeval.
Para reproduzir esse post, você precisará ter pelo menos a versão
0.4.0
do{rlang}
instalado na sua máquina!
Quero que minha função receba um nome sem aspas
Para isso, podemos usar o quentíssimo operador {{}}
, que foi oficialmente apresentado na useR!2019, em Tolouse. Esse operador informa as funções do {dplyr}
(e seus amigos {tidyr}
, {ggplot2}
etc) que olhem para a variável de dentro da base de dados, ao invés de um objeto supostamente passado como argumento da função.
Com isso, a função anterior fica simples assim:
minha_fn_sem_aspas <- function(dados, variavel) {
dados %>%
summarise(nova_variavel = sum({{variavel}} ^ 2))
}
E sua utilização:
mtcars %>%
minha_fn_sem_aspas(cyl)
nova_variavel |
---|
1324 |
Zero trauma.
Quero que minha função receba uma string
Para isso, teremos de usar o objeto especial .data
. Ele permite que você acesse a informação dos dados antes de aplicar a nova função. É muito similar ao .
do pacote {magrittr}
, para quem já conhece.
minha_fn_com_aspas <- function(dados, variavel) {
dados %>%
summarise(nova_variavel = sum(.data[[variavel]] ^ 2))
}
E sua utilização:
mtcars %>%
minha_fn_com_aspas("cyl")
nova_variavel |
---|
1324 |
Show! Esse provavelmente é o caso da maioria dos Shiny apps, pois acessamos as informações através de input$id_input
, que geralmente é uma string.
Observação: uma diferença essencial entre usar .data
e .
é que o primeiro consegue lidar com grupos, e o segundo não. Por exemplo, esses códigos têm resultados diferentes:
mtcars %>%
group_by(cyl) %>%
summarise(nova_variavel = sum(.data[["cyl"]] ^ 2))
cyl | nova_variavel |
---|---|
4 | 176 |
6 | 252 |
8 | 896 |
mtcars %>%
group_by(cyl) %>%
summarise(nova_variavel = sum(.[["cyl"]] ^ 2))
cyl | nova_variavel |
---|---|
4 | 1324 |
6 | 1324 |
8 | 1324 |
Para a lista completa de diferenças, veja ?rlang::.data
.
Quero que minha função crie uma coluna com nome variável
E se você quiser mudar o nome de nova_variavel
e incluir isso como argumento da função? Nesse caso, é necessário introduzir o operador :=
, e o resto é resolvido com {{}}
:
minha_fn_sem_aspas_novo_nome <- function(dados, variavel, nome) {
dados %>%
summarise({{nome}} := sum({{variavel}} ^ 2))
}
E sua utilização:
mtcars %>%
minha_fn_sem_aspas_novo_nome(cyl, novo_nome)
novo_nome |
---|
1324 |
Curiosamente, essa solução também funciona com as aspas:
mtcars %>%
minha_fn_sem_aspas_novo_nome(cyl, "novo_nome")
novo_nome |
---|
1324 |
Wrap-up
- O pacote que está por trás da programação com
{dplyr}
e amigos é o{rlang}
. - Use
{{variavel}}
quando não quiser colocar aspas no argumento da função. - Use
.data[["variavel"]]
quando quiser colocar aspas no argumento da função. - Use
{{nome}} := ...
quando quiser criar colunas com nomes que estão no argumento da função.
É isso. Happy coding ;)