You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编写函数:为何dplyr select()支持引号列名但df$col_name不行?

关于tidy evaluation的三个常见问题解答

我一直在学习tidy evaluation(整洁评估)的相关内容,但实际写代码时遇到了和所学不符的情况,我的函数如下:

ttsplit = function(prepped_data, outcome_column){
  
  sample <- sample(c(TRUE, FALSE), nrow(prepped_data), replace=TRUE, prob=c(0.7,0.3))
  train  <- prepped_data[sample, ]
  test   <- prepped_data[!sample, ]
  
  Xtrain = train %>% 
    select(!outcome_column)
  
  ytrain = train$outcome_column
  
  Xtest = test %>% 
    select(!outcome_column)
  
  ytest = test$outcome_column
  
  return(list(Xtrain, ytrain, Xtest, ytest))
}

我的数据结构(简化版):

model1data <- structure(list(Id = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), LotArea = c(8450, 
9600, 11250, 9550, 14260, 14115, 10084, 10382, 6120, 7420), SalePrice = c(208500, 
181500, 223500, 140000, 250000, 143000, 307000, 2e+05, 129900, 
118000)), row.names = c(NA, -10L), class = c("tbl_df", "tbl", 
"data.frame"))

问题1:为什么select()语句不用{{outcome_column}}也能正常运行?

因为你调用函数时传入的是字符串形式的列名(比如"SalePrice"),而dplyr的select()函数本身就支持直接使用字符串来指定列名。!outcome_column在这里是对字符串变量的否定选择,dplyr可以直接解析这个字符串,不需要额外用{{}}解引用。

{{}}(大括号语法)主要用于处理裸变量输入的场景——也就是当你调用函数时直接写列名(不带引号,比如ttsplit(model1data, SalePrice)),这时候需要{{}}把裸变量转换成dplyr能识别的列引用。

问题2:ytrain = train$outcome_column返回NULL,该如何正确解引用?

$是基础R的操作符,它会严格按字面量匹配列名——也就是说train$outcome_column会去找名为outcome_column的列,而不是去读取变量outcome_column里存储的字符串值,所以会返回NULL并报错。

正确的做法是用基础R的[[ ]]操作符,它支持接收字符串变量来访问列:

ytrain = train[[outcome_column]]
ytest = test[[outcome_column]]

train${{outcome_column}}无效的原因是:{{}}是tidy eval的语法,仅在dplyr等支持整洁评估的函数内部生效,而$是基础R的操作符,不识别这种语法。

问题3:为什么函数外直接运行df$'column_name'能正常工作?

在基础R中,$操作符支持直接使用字符串字面量来指定列名。当你写model1data$'SalePrice'时,引号里的SalePrice会被直接当作列名去匹配,这是$操作符的原生语法,和函数内部的变量引用场景完全不同——这里没有变量替换的过程,直接是字面量匹配。

内容的提问来源于stack exchange,提问作者Maggie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 00:07:41