dbplyr 按动态变量名分组

问题描述

如何使用动态变量名称进行分组?

我的例子:尝试在 Species 列上分组,知道它在 grouping_variable 变量中吗?

library(dplyr)
library(dbplyr)
library(DBI)

# My table
iris_table <- tbl(src = my_db_conn,in_schema(schema = "my_schema",table = "iris_table"))

# The grouping variable
grouping_variable <- "Species"

# My tries
iris_table %>%
  group_by(across(any_of(grouping_variable))) %>%
  summarise(sum_petal_length = sum(Petal.Length))
### ==> returns error

iris_table %>%
  group_by(!!!grouping_variable) %>%
  summarise(sum_petal_length = sum(Petal.Length))
### ==> returns grouping by the character "Species"

我的sessionInfo()

attached base packages:
[1] stats     graphics  Grdevices utils     datasets  methods   base     

other attached packages:
[1] DBI_1.1.0               dbplyr_1.4.4            dplyr_1.0.0             lubridate_1.7.9        

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.5          rstudioapi_0.11     magrittr_1.5        hms_0.5.3           odbc_1.3.0          tidyselect_1.1.0   
 [7] bit_1.1-15.2        R6_2.4.1            rlang_0.4.7         fansi_0.4.1         blob_1.2.1          tools_3.6.2        
[13] utf8_1.1.4          cli_2.0.2           ellipsis_0.3.1      readxl_1.3.1        bit64_0.9-7.1       assertthat_0.2.1   
[19] tibble_3.0.3        lifecycle_0.2.0     Crayon_1.3.4        zip_2.0.4           purrr_0.3.4         tidyr_1.1.0        
[25] vctrs_0.3.2         glue_1.4.1          openxlsx_4.1.5      stringi_1.4.6       cellranger_1.1.0    compiler_3.6.2     
[31] pillar_1.4.6        generics_0.0.2      pkgconfig_2.0.3    

解决方法

这里有两种可能的方法。

(1) 与您已经使用的方法最相似,我们首先必须告诉 R 字符串应该被视为符号:

iris_table %>%
  group_by(!!!syms(grouping_variable)) %>%
  summarise(sum_petal_length = sum(Petal.Length))

注意 syms 之前的 !!!。这种方法使用了 rlang 包的一些特性,这些特性在其他上下文中很有用。但是,它不再是推荐的使用 dplyr 编程的方法。

(2)推荐的这种programming with dplyr方法是:

iris_table %>%
  group_by(.data[[grouping_variable]]) %>%
  summarise(sum_petal_length = sum(Petal.Length))

使用 dbplyr 时,这两种方法都会为您提供正确的 SQL 转换:

data(iris)
iris_table = tbl_lazy(iris,con = simulate_mssql())
# The grouping variable
grouping_variable <- "Species"

# approach 1
iris_table %>%
  group_by(!!!syms(grouping_variable)) %>%
  summarise(sum_petal_length = sum(Petal.Length))
# translation from approach 1
# <SQL>
# SELECT `Species`,SUM(`Petal.Length`) AS `sum_petal_length`
# FROM `df`
# GROUP BY `Species`

# approach 2
iris_table %>%
  group_by(.data[[grouping_variable]]) %>%
  summarise(sum_petal_length = sum(Petal.Length))
# translation from approach 2
# <SQL>
# SELECT `Species`,SUM(`Petal.Length`) AS `sum_petal_length`
# FROM `df`
# GROUP BY `Species`
,

因此,对于 dplyr 1.0.3 版,它运行良好。

grouping_variable <- "Species"

data("iris")
iris_table <- as_tibble(iris) %>%
  group_by(across(any_of(grouping_variable))) %>%
  summarise(sum_petal_length = sum(Petal.Length))

> iris_table
# A tibble: 3 x 2
  Species    sum_petal_length
* <fct>                 <dbl>
1 setosa                 73.1
2 versicolor            213  
3 virginica             278. 

packageVersion("dplyr")
#> [1] '1.0.3'

据我所知,在较旧的 dplyr 版本中,grouping_variable <- sym("Species") 应该可以解决问题。