【问题标题】:R Quasiquotation & tidyeval for dynamic variable references in R in own functionsR Quasiquotation & tidyeval 用于 R 中自己函数中的动态变量引用
【发布时间】:2020-03-09 15:32:51
【问题描述】:

我正在尝试在我自己的函数中使用 R 中 tidyverse 的准引用来解决问题。我在这里读过这个:Passing a list of arguments to a function with quasiquotation 和这里的全部内容:https://tidyeval.tidyverse.org/

但我仍然无法正常工作。

假设我有以下数据:

dat <- data.frame(time   = runif(20),
                  group1 = rep(1:2, times = 10),
                  group2 = rep(1:2, each = 10),
                  group3 = rep(3:4, each = 10))

我现在要做的是编写一个函数来执行以下操作:

  • 获取数据集
  • 指定包含时间的变量(注意,在另一个数据集中,这可能称为“小时”或“qtime”或其他)
  • 指定我要对哪些组进行操作/统计

所以我希望用户做的是使用如下函数:

test_function(data = dat, time_var = "time", group_vars = c("group1", "group3"))注意,下次我可能会选择不同的分组变量或不选择。

假设在我想要的函数中:

  • 计算时间变量的某些统计数据,例如分位数。注意:我想通过我的分组变量来拆分它

这是我最近的尝试之一:

test_function <- function(data, time_var = NULL, group_vars = NULL)
{
# Note I initialize the variables with NULL, since e.g. the user might not specify a grouping 

and I want to check for that in my function at some point)
time_var <- enquo(time_var)
group_vars <- enquos(group_vars)

# Here I try to group by my grouping variables
temp_data <- data %>%
    group_by_at(group_vars) %>%
    mutate(!!sym(time_var) := !!sym(time_var) / 60)

# Here I'm calculating some stats  
time_stats <- temp_data %>%
    summarize_at(vars(!!time_var), list(p0.1_time   = ~quantile(., probs = 0.1, na.rm = T),
                                        p0.2_time   = ~quantile(., probs = 0.2, na.rm = T),
                                        p0.3_time   = ~quantile(., probs = 0.3, na.rm = T),
                                        p0.4_time   = ~quantile(., probs = 0.4, na.rm = T),
                                        p0.5_time   = ~quantile(., probs = 0.5, na.rm = T),
                                        p0.6_time   = ~quantile(., probs = 0.6, na.rm = T),
                                        p0.7_time   = ~quantile(., probs = 0.7, na.rm = T),
                                        p0.8_time   = ~quantile(., probs = 0.8, na.rm = T),
                                        p0.9_time   = ~quantile(., probs = 0.9, na.rm = T),
                                        p0.95_time  = ~quantile(., probs = 0.95, na.rm = T)))

}

我的代码有什么问题? IE。我特别与 !!, !!!, sym, enquo, enquos 的事情作斗争。为什么 group_by_at 东西不需​​要 !!东西,而我的汇总和变异确实需要它?

【问题讨论】:

  • 您一次只能问一个问题。使用带有示例输入和所需输出的明确reproducible example 专注于一个明确的问题。要求“提示”或“最佳方式”做事而不定义“最佳”的确切含义的广泛问题在这里是题外话。
  • 我编辑了我的问题,使它们现在更加集中。我发现不被“允许”询问“提示”和“最佳方式”有点令人困惑。在我目前学习 R 的阶段,这些(不同的)意见对我来说很有价值,尤其是在没有正确或错误答案的情况下。
  • @G.Grothendieck 我希望这更接近你的期望。

标签: r tidyeval quosure


【解决方案1】:

进行这些更改:

  • 使用symsyms 而不是enquoenquos
  • 分别使用!!!!!
  • 创建po 为列表,然后使用unnest_wider 展开成列
  • quantile 已经矢量化,所以我们不需要 map
  • mutate 可以直接合并到 quantile 调用中以消除它
  • 将管道合并为一个管道
  • 使用TRUE 而不是T,因为后者可以被同名的变量屏蔽,而没有变量可以称为TRUE
  • 我们可以使用普通的group_bysummarize
  • 样本数据中没有group3,所以我们改用group2
  • 如果没有time_var,这将毫无意义,因此请删除默认值 NULL

这给出了以下代码

test_function <- function(data, time_var, group_vars = NULL) {
  p <- c(1:9/10, 0.95)
  time_var <- sym(time_var)
  group_vars <- syms(group_vars)
  data %>%
    group_by(!!!group_vars) %>%
    summarize(po = list(quantile(!!time_var / 60, p, na.rm = TRUE))) %>%
    ungroup %>%
    unnest_wider(po)
}

test_function(data = dat, time_var = "time", group_vars = c("group1", "group2")) 

给予:

# A tibble: 4 x 12
  group1 group2   `10%`   `20%`   `30%`   `40%`   `50%`   `60%`   `70%`   `80%`   `90%`   `95%`
   <int>  <int>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>
1      1      1 0.00237 0.00432 0.00654 0.00903 0.0115  0.0120  0.0124  0.0133  0.0147  0.0154 
2      1      2 0.00244 0.00251 0.00281 0.00335 0.00388 0.00410 0.00432 0.00493 0.00591 0.00640
3      2      1 0.00371 0.00381 0.00468 0.00632 0.00796 0.0101  0.0122  0.0136  0.0143  0.0147 
4      2      2 0.00385 0.00538 0.00630 0.00660 0.00691 0.00725 0.00759 0.00907 0.0117  0.0130 

【讨论】:

  • 不错。这段代码看起来很棒。我现在也至少看到了我的一个错误。将组变量作为字符串提供时,我需要使用 sym 而不是 enquo 在将它们作为变量列表提供时使用。昨天晚上我还再次阅读了 tidyeval 文档,现在(连同您的代码)对整个主题有了更多的了解。
猜你喜欢
  • 1970-01-01
  • 2017-03-18
  • 1970-01-01
  • 2020-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-18
  • 2018-12-05
相关资源
最近更新 更多