Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tidy Eval: Using {{var}} inside a nesting function not possible?

I was trying to use tidyr::complete inside my function while providing the variable names using {{}}. This works fine, however, when I add a nesting function to combine two variables I get an error. Please see the minimal example below.

library(tidyverse)
library(rlang)

df <- tibble(
  group1 = c(1:2, 1),
  group2 = c("c", "c", "c"),
  item_id = c(1:2, 2),
  item_name = c("a", "b", "b"),
  value1 = 1:3,
  value2 = 4:6
)

my_complete <- function(data, var1, var2, var3, var4, var5, var6){
  data %>%
    tidyr::complete({{var1}}, {{var3}})
}

my_complete(df, var1 = group1, var2 = group2, var3 = item_id, var4 = item_name, var5 = value1, var6 = value2)

This works and the output is:

# A tibble: 4 x 6
  group1 item_id group2 item_name value1 value2
   <dbl>   <dbl> <chr>  <chr>      <int>  <int>
1      1       1 c      a              1      4
2      1       2 c      b              3      6
3      2       1 NA     NA            NA     NA
4      2       2 c      b              2      5

When I however combine two variables with nesting I get an error.


my_complete_nesting <- function(data, var1, var2, var3, var4, var5, var6){
  data %>%
    tidyr::complete(nesting({{var1}}, {{var2}}), nesting({{var3}}, {{var4}}))
}

my_complete_nesting(df, var1 = group1, var2 = group2, var3 = item_id, var4 = item_name, var5 = value1, var6 = value2)
 Error in .f(.x[[i]], ...) : object 'group1' not found 

Maybe I am missing something but I can just not get it to work. I thought I understood how to use {{}}. When I use the alternative expression of variable <- enquo(variable) and !!variable I get the same problem. So it is not specifically {{}} that is causing the problem but rather the way I use tidy eval here. I would like to get the following output:

df %>%
  tidyr::complete(nesting(group1, group2), nesting(item_id, item_name))

# A tibble: 4 x 6
  group1 group2 item_id item_name value1 value2
   <dbl> <chr>    <dbl> <chr>      <int>  <int>
1      1 c            1 a              1      4
2      1 c            2 b              3      6
3      2 c            1 a             NA     NA
4      2 c            2 b              2      5

I would really appreciate some help with this problem. Maybe I am just missing something simply but I cannot seem to find the problem.

Thanks!

like image 509
jpquast Avatar asked Jul 02 '20 14:07

jpquast


1 Answers

This is actually an example where you don't want to use quosures. A quosure captures an expression as well as the context where it should be evaluated. In your case, it captures the global environment, where group1 is not defined. This is why you get an "object not found" error, when nesting() attempts to resolve the expression.

Because you want group1 to be evaluated in the context of the data frame (and not in the global context), the proper mechanism to use here is ensym():

my_complete_nesting <- function(data, var1, var2, var3, var4, var5, var6){
  data %>%
    tidyr::complete(nesting(!!ensym(var1), !!ensym(var2)), 
                    nesting(!!ensym(var3), !!ensym(var4)))

}

## Now works
my_complete_nesting(df, var1 = group1, var2 = group2, 
                    var3 = item_id, var4 = item_name, 
                    var5 = value1, var6 = value2)
like image 121
Artem Sokolov Avatar answered Oct 28 '22 14:10

Artem Sokolov