R语言中非标准求值的定义、传递‘未定义变量’的方法及ggplot列名参数传递原理问询
嘿,我来用最直白的方式给你拆解这两个问题,完全不用纠结那些晦涩的术语~
1. 什么是非标准求值?R语言里怎么传递“未定义变量”?
先从你熟悉的标准求值说起:平时你写a <- 5; mean(a),这里a会先被算出具体的值5,再传给mean()函数——函数拿到的是最终的数值,而不是a这个变量名本身,这就是标准求值的逻辑:先算值,再传参。
那非标准求值就是反过来:函数不会立刻把你传入的参数算出具体值,而是先把你写的**表达式(比如变量名、一段小代码)**原封不动地“抓”下来,然后在函数内部自己决定什么时候、在哪里去计算这个表达式的值。
举个简单的例子:你用subset(iris, Species == "setosa")的时候,全局环境里根本没有Species这个变量,但subset()不会报错——因为它用了非标准求值,它知道要去iris这个数据框里找Species对应的列,而不是去全局环境找。
至于怎么传递“未定义变量”?其实就是利用支持非标准求值的函数,或者自己写函数的时候用R里的工具(比如enquo()、!!这些)来实现:
比如自己写一个简单的提取列的函数:
get_column <- function(data, col_name) { # 捕获传入的列名表达式(比如你写的domgross_2013) col_expr <- enquo(col_name) # 在传入的data里提取这个列 dplyr::pull(data, !!col_expr) } # 调用的时候,即使全局没有domgross_2013,只要bechdel里有这个列就能用 get_column(bechdel, domgross_2013)
2. 为什么ggplot里可以直接写domgross_2013而不是字符串?
核心原因就是:ggplot的aes()函数用了非标准求值!
正常情况下,如果你在全局环境里没有domgross_2013这个变量,直接写domgross_2013会立刻报错,但aes()不按常理出牌——它不会立刻去全局环境找这个变量的值,而是把你写的domgross_2013当成一个“列名标签”存起来。等到ggplot实际要画图的时候,它会自动去你指定的data = bechdel数据框里,找和这个标签同名的列来用。
打个生活化的比方:你告诉ggplot“我要把x轴对应到叫domgross_2013的列”,但你不用特意说“叫‘domgross_2013’的列”(字符串形式),直接说“domgross_2013”就行——aes()就像个贴心的翻译,能听懂你说的列名,自动去数据框里找对应的内容。
如果换成标准求值的方式,你就得这么写(现在更推荐用.data代词):
ggplot(data = bechdel, aes(x = .data[["domgross_2013"]])) + geom_histogram(bins = 10, color="purple", fill="white") + labs(title = "Domestic Growth of Movies", x = " Domestic Growth")
这里你明确用字符串告诉它要找哪个列,就是标准求值的逻辑了。而aes()的非标准求值就是让你写代码更简洁,不用加引号和额外的语法,直接写列名就行。
内容的提问来源于stack exchange,提问作者joshpetit

