R:创建带有省略号参数的函数时的词法范围问题

R: Lexical Scoping issue when creating a function with ellipsis argument

我在 R 中制作了很多频率 tables 并且正在编写我自己的快速频率 table (qft) 函数,当我 运行 进入我认为是词法范围问题。这是我的功能版本不起作用

library("tidyverse")

data(mtcars)

qft_bad<-function(data,...){
  ft<-data.frame(with(data, table(...)))
  ft<-ft[ft$Freq!=0,]
  return(ft)
}

tst_bad<-qft_bad(mtcars,cyl,gear)

您会注意到,如果您尝试 运行 qft_bad(),则会产生错误 "Error in table(...) : object 'cyl' not found"。作为解决方法,我编写了以下函数,它确实产生了预期的结果,但需要的输入略有不同。

qft_good<-function(data,...){
      nmes<-c(...)
      vars<-dplyr::select(data,...)
      ft<-data.frame(table(vars))
      ft<-ft[ft$Freq!=0,]
      colnames(ft)[1:length(nmes)]<-nmes
      return(ft)
}

tst_good<-qft_good(mtcars,"cyl","gear")

我猜 qft_bad() 不起作用,因为 R 试图评估输入数据集之外的参数,但我不太清楚具体细节这个问题(with() 函数有问题吗?)。

由于 qft_good() 对于我的目的来说效果很好,我主要是为了我自己的 R 启蒙而问这个问题。谁能更好地解释我的 qft_bad() 函数中发生了什么,或者创建一个不需要您在引号中列出变量名称的 qft 函数版本(正如您必须在 qft_good() 中那样)?

您可以使用 rlang 中的 quosures 来捕获 ... 中的参数,然后取消引用将它们拼接到 select 调用中:

library(tidyverse)
library(rlang)

qft <- function(data, ...){
  args <- enquos(...)
  vars <- select(data, !!!args)
  ft <- data.frame(table(vars))
  ft[ft$Freq != 0, ]
}

qft(mtcars, cyl, gear)
#  cyl gear Freq
#1   4    3    1
#2   6    3    2
#3   8    3   12
#4   4    4    8
#5   6    4    4
#7   4    5    2
#8   6    5    1
#9   8    5    2