datacubeR

Esta es de las cosas más avanzadas en R

Tidy Evaluation

Tidyeval

picture of me

Ahora estaba navegando por Twitter cuando me encontré con este otro problema.

El problema

Se presenta la siguiente función:

library(dplyr)
#> 
a <- sample(letters[1:5], 500, rep = TRUE)
b <- sample(1:10, 500, rep = TRUE)
df1 <- data.frame(a, b)
 
dummy_function <- function(data, var1, var2){
  # Creating summary statistics
  df <- data %>%
    group_by(var1, var2) %>%
    summarise(n=n()) %>%
    group_by(var1) %>%
    mutate(perc=100*n/sum(n))
    
  df
}
dummy_function(df1, a, b)
#> Error: Column `var1` is unknown

Created by the reprex package (v0.3.0)

Este es un típico problema, creado a través de reprex (Les recomiendo siempre utilizar reprex para postear sus problemas en Internet, es más fácil que los ayuden así)

En este caso tenemos un problema generado por una de las características más geniales del tidyverse: Non-Standard Evaluation.

Non-Standard Evaluation se refiere a la habilidad de que algunas funciones en R, en particular del tidyverse, pueden recibir argumentos (en especial variables) sin la necesidad de comillas. (Esto es algo que Python envidia muchísimo de R, y según lo que he leído no es posible de aplicar en Python, aunque hay algunos esfuerzos para hacerlo).

iris %>% 
  select(Species) %>%
  head(10)

Como se puede ver, para llamar la variable Species no es necesario utilizar comillas, R no reconoce Species como un objeto si no como una variable dentro del objeto iris. En el caso de realizar la misma operación pero utilizando Standard Evaluation, sería algo así:

head(iris["Species"], 10)

Entonces, el error presentado en el problema reportado viene porque hay un group_by() que utiliza var1 y var2 como argumentos en forma de NSE. El problema es que argumentos de una función pasan como función, por lo tanto group_by() no los reconoce como variables dentro de data.

NSE es una tremenda feature de R, pero en general es muy dificil de trabajar con ella en especial en funciones, porque R inicialmente no sabe si interpretar un elemento sin comills como un objeto o como una variable.

Lo bueno es que el paquete rlang ayuda infinitamente a poder mejorar esto por medio del operador curly-curly.

Acá dejo un video de Hadley Wickham explicando muy en fácil como funciona este nuevo operador.

La solución

Gracias a la explicación de Hadley, la solución es súper sencilla con rlang. Sólo se requiere aplicar el operador curly-curly a var1 y var2 y luego group_by() reconocerá que son variables y no objetos.

library(rlang)
a <- sample(letters[1:5], 500, rep = TRUE)
b <- sample(1:10, 500, rep = TRUE)
df1 <- data.frame(a, b)

dummy_function <- function(data, var1, var2){
  df <- data %>%
    group_by(, ) %>%
    summarise(n=n()) %>%
    group_by() %>%
    mutate(perc=100*n/sum(n))
  df}
dummy_function(df1, a, b)
Go to top