bangbang-13

Bang bang operator no R

Esse bang bang não tem nada a ver com os filmes do velho oeste! No artigo de hoje explicamos melhor e com exemplos como usar esse operador do R.

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.

Share the Post:

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Related Posts