Artigo escrito com a colaboração de Larisse Annie Saldanha
No tidy evaluation, todas as funções de citação são, na verdade, funções de quase-citação, porque também oferecem suporte à citação. Onde a quotation é o ato de capturar uma expressão não avaliada, unquotation é a capacidade de avaliar seletivamente partes de uma expressão citada.
Juntos, isso é chamado quase-quotação. A quase-quotação facilita a criação de funções que combinam o código escrito pelo autor da função com o código escrito pelo usuário da função. Isso ajuda a resolver uma grande variedade de problemas desafiadores.
Um argumento citado é capturado pela função e é processado de algum jeito personalizado. Se você não tiver certeza se um argumento é citado ou avaliado, tente executar o código fora da função. Se não funcionar ou fizer algo diferente, esse argumento precisa ser citado.
Unquoting
Unquoting é a habilidade de avaliar seletivamente partes de uma expressão citada de outra forma. Use bang bang `!!` para citar um único argumento numa dada função. Por exemplo:
```{r} x <- expr(-1) expr(f(!!x,y)) ``` <!-- ![](img/Diagrama1.PNG) -->
A função `quote()` é equivalente à função `expr()`. Ela simplesmente retorna o argumento. Veja:
```{r echo=TRUE} quote(x+y) ```
Assim como chamamos objetos, `!!` também funciona para símbolos e constantes:
```{r echo=TRUE} a <- sym("y") b <- 1 expr(f(!!a, !!b)) ```
Formalmente, `quo()` e `expr()` são funções de quase-citação, bang bang `!!` é um operador de citação, e `!!!` é um operador de divisão de citação. Estes termos tem um rico histórico em linguagens Lisp, e em linguagens modernas como Julia e Racket.
O operador `!!!` toma uma lista de expressões e insere ela no local do operador. Por exemplo:
```{r echo=TRUE} xs <- exprs(1,a,-b) expr(f(!!!xs,y)) ```
```{r echo=TRUE} ys <- set_names(xs, c("a","b","c")) expr(f(!!!ys,d=4)) ```
Exemplo 1
Os exemplos que serão mostrados, serão do banco de dados `iris` do R.
```{r echo=TRUE} head(iris) ```
Suponha que todas as plantas deste banco de dados pertencem à novas espécias, **pallida** e queremos atualizar os valores da coluna que correspondem às espécies. Usamos então `mutate()`:
```{r echo=TRUE} mutate(iris, Species = "Pallida") %>% head() ```
Por definição, o `dplyr` cita o nome e avalia o valor. Por isso, podemos facilmente trocar o lado do valor do par por um objeto e, novamente, ele é avaliado e obtemos um resultado idêntico.
```{r echo=TRUE} targetValue = "Pallida" mutate(iris, Species = targetValue) %>% head() ```
Quando tentamos especificar o valor por um nome, não funciona. Ele somente cria uma coluna.
```{r echo=TRUE} targetColumn = "Species" mutate(iris, targetColumn = "Pallida") %>% head() ```
Uso do Operador bang bang `!!`
Como dito anteriormente, o propósito deste operador é citar o argumento. Então, se antes citarmos o nome e avaliar o valor, a citação do nome resolveria nosso problema? Infelizmente não completamente. Mas com o uso do operador `:= (definição)` resolvemos completamente o problema.
```{r echo=TRUE} targetColumn = "Species" mutate(iris, !!targetColumn := "Pallida") %>% head() ```
E mais:
```{r echo=TRUE} targetColumn = "Species" mutate(iris, !!targetColumn := targetValue) %>% head() ```
Uso em Outras Funções do `dplyr`
```{r echo=TRUE} a <-"Species" filter(iris, !!a == "versicolor") %>% head() ```
Não funciona, já que `a` é um símbolo e queremos que ele seja avaliado em `Species`. Para funcionar, criamos um símbolo. Precisamos transformar o caracter string `”Species”` em símbolo.
```{r echo=TRUE} a <-"Species" filter(iris, !!rlang :: sym(a) == "versicolor") %>% head() ```
Exemplo 2
Banco de Dados `Starwars` do R, onde:
- Mass: Peso (kg)
- Height: Altura (cm)
- BMI: Body Mass Index
```{r echo= TRUE} head(starwars) starwars <- mutate(starwars, height = height / 100) transmute(starwars, bmi = mass / height^2) ```
```{r eval=FALSE, include=FALSE} x <- "height" transmute(starwars, bmi = mass / (!!x)^2) ```
```{r echo=TRUE} x <- sym("height") transmute(starwars, bmi = mass / (!!x)^2) ```
```{r echo=TRUE} starwars %>% group_by(species) %>% summarise(avg = mean(height)) ```
```{r} mean_by <- function(data, var, group) { data %>% group_by(group) %>% summarise(avg = mean(var)) } # mean_by(starwars, "species", "height") #> Erro: Column `group` is unknown ```
Logo, os argumentos `group` e `var` precisam ser citados:
```{r} mean_by <- function(data, var, group) { var <- sym(var) group <- sym(group) data %>% group_by(!! group) %>% summarise(avg = mean(!! var)) } mean_by(starwars,"height","species") ```
Uso Típico do operador
`calcula_percentual_linha <- function(data, linha, coluna, indicador){` \ `var1 <- sym(linha)` \ `var2 <- sym(coluna)` \ `indicador <- sym(indicador)` \ \ `tab <- data %>% ` \ `group_by(!!var1,!!var2) %>%` \ `summarise(Total=sum(!!indicador,na.rm = T)) %>%` \ `mutate(` \ `%` `= (Total/sum(Total))` \ `) %>% ` \ `dplyr::select(-Total) %>%` \ `arrange(!!var2,!!var1) %>%` \ `pivot_wider(names_from = DescLinha, values_from = `%`, values_fill = list(`%` = 0))` \ \ `tab` \ \ `}`
Curtiu nosso conteúdo? Siga-nos nas redes sociais! Estamos no Facebook, Instagram e LinkedIn.