为什么不存在的data.frame列中的项目分配有效?

Nic*_*bbe 7 r

灵感来自Q6437164:有人可以向我解释为什么以下工作:

iriscopy<-iris #or whatever other data.frame
iriscopy$someNonExistantColumn[1]<-15
Run Code Online (Sandbox Code Playgroud)

对我而言,似乎并不明白R如何将此语句解释为:someNonExistantColumn在data.frame中创建一个名为new的新列,并将第一个值(实际上是所有值,如图所示)设置为值15.

Rei*_*son 10

R语言定义手册为我们提供了一个指针,指向R如何计算表单的表达式:

x$foo[1] <- 15
Run Code Online (Sandbox Code Playgroud)

就好像我们打电话一样

`*tmp*` <- x
x <- "$<-.data.frame"(`*tmp*`, name = "foo", 
                      value = "[<-.data.frame"("$.data.frame"(`*tmp*`, "foo"), 
                                               1, value = 15))
rm(`*tmp*`)
Run Code Online (Sandbox Code Playgroud)

如果我们为了说明的目的而放弃使用的实际方法,那么中间位可能更容易解决:

x <- "$<-"(`*tmp*`, name = "foo", 
           value = "[<-"("$"(`*tmp*`, "foo"), 1, value = 15))
Run Code Online (Sandbox Code Playgroud)

回到你的例子iris,我们有类似的东西

iris$foo[1] <- 15
Run Code Online (Sandbox Code Playgroud)

这里,递归地评估函数.第一提取功能"$"被用于访问部件"foo"iris,其是NULL:

> "$"(iris, "foo")
NULL
Run Code Online (Sandbox Code Playgroud)

然后,"[<-"用于替换上面返回的对象的第一个元素(the NULL)与值15,即调用:

> "[<-"(NULL, 1, value = 15)
[1] 15
Run Code Online (Sandbox Code Playgroud)

现在,这是在value我们调用的最外层部分中用作参数的对象,即使用"$<-"以下命令进行赋值:

> head("$<-"(iris, "foo", value = 15))
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species foo
1          5.1         3.5          1.4         0.2  setosa  15
2          4.9         3.0          1.4         0.2  setosa  15
3          4.7         3.2          1.3         0.2  setosa  15
4          4.6         3.1          1.5         0.2  setosa  15
5          5.0         3.6          1.4         0.2  setosa  15
6          5.4         3.9          1.7         0.4  setosa  15
Run Code Online (Sandbox Code Playgroud)

(此处包含head()以限制显示的行数.)

这有希望解释函数如何调用进度.要处理的最后一个问题是为什么整个向量foo设置为15?答案就在下面的详细信息部分中给出?"$<-.data.frame":

Details:

....

         Note that there is no ‘data.frame’ method for ‘$’, so ‘x$name’
     uses the default method which treats ‘x’ as a list.  There is a
     replacement method which checks ‘value’ for the correct number of
     rows, and replicates it if necessary.
Run Code Online (Sandbox Code Playgroud)

关键位是最后一句.在上面的示例中,使用了最外面的分配value = 15.但是在这一点上,我们想要更换整个组件"foo",这个组件很长nrow(iris).因此,value = rep(15, nrow(iris))在最外面的赋值/函数调用中实际使用的是.

这个例子更复杂,因为你必须从方便符号转换

x$foo[1] <- 15
Run Code Online (Sandbox Code Playgroud)

到适当的函数调用使用"$<-"(),"[<-"()"$"()." R语言定义" 第3.4.4节中的示例使用了这个更简单的示例:

names(x)[3] <- "Three"
Run Code Online (Sandbox Code Playgroud)

评估为

`*tmp*` <- x
x <- "names<-"(`*tmp*`, value="[<-"(names(`*tmp*`), 3, value="Three"))
rm(`*tmp*`)
Run Code Online (Sandbox Code Playgroud)

因为names()看起来像通常的函数调用,所以稍微容易理解.