这些字符串或变量是?

时间:2017-11-24 22:36:36

标签: r ggplot2

来自C / Python / Java背景,我无法理解一些R语法,其中文字看起来像变量,但似乎表现得像字符串。例如:

library(ggplot2)
library("ggplot2")

两条线的行为相当。但是,我希望第一行的意思是“加载名称存储在ggplot2变量中的库”并给出类似object 'ggplot2' not found的错误。

说到ggplot2:

ggplot(data, aes(factor(arrivalRate), responseTime, fill=factor(mode))) +
  geom_violin(trim=FALSE, position=dodge)

变量arrivalRateresponseTimemode不存在,但不知何故R知道在data数据框内查找它们。我假设aes实际上接收字符串,然后使用类似eval的内容进行处理。

R如何解析最终将某些文字解释为字符串的代码?

4 个答案:

答案 0 :(得分:28)

当一个参数传递给一个函数时,它不会作为传递,而是作为 promise 传递,其中包含

  • 调用者用作实际参数的表达式或代码
  • 要评估该表达式的环境,即:来电者的环境。
  • 在promise的环境中计算表达式时表达式所表示的值 - 在实际计算promise之前,不会填充此槽。如果函数永远不会访问它,它将永远不会被填充。

pryr包可以在承诺中显示信息:

library(pryr)

g <- function(x) promise_info(x)
g(ggplot2)

,并提供:

$code
ggplot2  <-- the promise x represents the expression ggplot2

$env
<environment: R_GlobalEnv>  <-- if evaluated it will be done in this environment

$evaled
[1] FALSE  <-- it has not been evaluated

$value
NULL  <-- not filled in because promise has not been evaluated

pryr输出中的上述插槽中唯一一个可以在R级别访问而无需编写C函数(或使用诸如访问此类C代码的pryr之类的包)的代码插槽。这可以使用R函数substitute(x)(或其他方法)来完成。就应用于promise的pryr输出substitute而言,返回代码槽而不评估promise。也就是说,不修改值槽。如果我们以普通的方式访问x,即不通过substitute,那么代码将在promise的环境中进行评估,存储在值槽中,然后传递给访问函数中的表达式它。

因此,下列任何一个都会产生一个字符串,表示作为表达式传递的内容,即代码槽的字符表示形式,而不是其值。

f <- function(x) as.character(substitute(x))
f("ggplot2")
## [1] "ggplot2"
f(ggplot2)
## [1] "ggplot2"

文库

事实上,library使用这个成语,即as.character(substitute(x))来处理它的第一个参数。

AES

aes函数使用match.call将整个调用作为表达式进行处理,因此在某种意义上是substitute的替代方法。例如:

h <- function(x) match.call()
h(pi + 3)
## h(x = pi + 3)

注意

如果不查看函数的文档或代码如何处理其参数,就无法分辨。

答案 1 :(得分:20)

R语言的一个有趣的怪癖是它评估表达式的方式。在大多数情况下,R的行为与您期望的一样。引号中的表达式被视为字符串,其他任何内容都被视为变量,函数或其他标记。但是一些函数允许“非标准评估”,其中或多或少地评估不带引号的表达式,就好像它是引用变量一样。最常见的例子是R的加载库的方式(允许不带引号或引用的库名称)及其简洁的公式接口。其他包可以利用NSE。 Hadley Wickham在他非常受欢迎的 tidyverse 包中广泛使用它。除了为用户保存几个字符的输入外,NSE还有许多用于动态编程的有用属性。

如另一个答案所述,Wickham有an excellent tutorial on how it all works。 RPubs用户lionel也有一个great working paper on the topic

答案 2 :(得分:7)

这个概念被称为&#34;非标准评估&#34;,并且有许多不同的方式可以在不同的R函数中使用它。有关简介,请参阅this book chapter

这种语言功能可能令人困惑,library()函数可能不需要它,但是当你需要在数据帧上指定计算时,它允许非常强大的代码,如ggplot2或dplyr中的情况,例如。

答案 3 :(得分:5)

library(ggplot2)
library("ggplot2")

不等同。在第一行中,ggplot2是一个符号,可以 或者可能不受某种价值的约束。在第二行中,"ggplot2"是一个 长度为一的字符向量。

然而,函数可以操纵它所获得的参数 评估它们,并且可以决定同等地处理这两种情况,这显然是library所做的。

以下是如何操作未评估表达式的示例:

> f <- function(x) match.call()  # return unevaluated function call
> x <- f(foo)
> x
f(x = foo)
> mode(x)
[1] "call"
> x[[1]]
f
> x[[2]]
foo
> mode(x[[2]])
[1] "name"
> as.character(x[[2]])
[1] "foo"
> x <- f("foo")
> mode(x[[2]])
[1] "character"