偶然我遇到了"[<-"
运营商的奇怪行为。它的行为会有所不同,具体取决于调用的顺序以及我是使用RStudio还是普通的RGui。我将通过一个例子说清楚。
x <- 1:10
"[<-"(x, 1, 111)
x[5] <- 123
据我所知,第一个分配不应该改变x
(或者我错了?),而第二个应该这样做。事实上,上述操作的结果是
x
[1] 1 2 3 4 123 6 7 8 9 10
但是,当我们以不同的顺序执行这些操作时,结果会有所不同,并且x
已更改!意味深长:
x <- 1:10
x[5] <- 123
"[<-"(x, 1, 111)
x
[1] 111 2 3 4 123 6 7 8 9 10
但它只会在我使用普通R时发生!在RStudio中,两个选项的行为都是相同的。我在两台机器上检查过它(一台用Fedora,一台用Win7),情况看起来完全一样。
我知道'功能'版本("[<-"(x..)
)可能从未使用过,但我很好奇它为什么会发生。谁能解释一下呢?
==========================
编辑:
好的,所以从评论我得到的原因是x <- 1:10
类型为'整数',并且在替换x[5] <- 123
之后它是'double'。
但仍然存在为什么RStudio的行为不同的问题?我重新启动R会话,它不会改变任何东西。
答案 0 :(得分:36)
Rstudio的对象浏览器以一种强制修改时复制的方式修改它检查的对象。具体来说,对象浏览器使用至少一个R函数,其调用内部强制对象的评估,在此过程中将对象的命名字段的值从1重置为2.来自R-Internals manual :
当要更改对象时,将查询指定的字段。值为2表示在更改之前必须复制对象。 [...]值1用于情况,其中原则上在计算的持续时间内存在两个副本[...]但不再存在,因此可以优化一些原始函数在这种情况下避免复制。
要查看对象浏览器修改命名字段(下一个代码块中的[NAM()]
),请比较运行以下行的结果。在第一个中,两个“行”一起运行,因此Rstudio在查询其结构之前没有时间“触摸”X
。在第二行中,每行都是单独粘贴的,因此在检查之前会修改X
。
## Pasted in together
x <- 1:10; .Internal(inspect(x))
# @46b47b8 13 INTSXP g0c4 [NAM(1)] (len=10, tl=0) 1,2,3,4,5,...
## Pasted in with some delay between lines
x <- 1:10
.Internal(inspect(x))
# @42111b8 13 INTSXP g0c4 [NAM(2)] (len=10, tl=0) 1,2,3,4,5,...
将命名的字段设置为2后,[<-(X, ...)
将不会修改原始对象。将以下内容一次性粘贴到Rstudio中会修改X
,而逐行粘贴它不会:
x <- 1:10
"[<-"(x, 1, 111)
所有这一切的另一个后果是Rstudio的对象浏览器实际上使一些操作比它们原本要慢。再次,比较首先粘贴在一起的相同两个命令,然后一次一个:
## Pasted in together
x <- 1:5e7
system.time(x[1] <- 9L)
# user system elapsed
# 0 0 0
## Pasted in one at a time
x <- 1:5e7
system.time(x[1] <- 9L)
# user system elapsed
# 0.11 0.04 0.16
[<-
w.r.t的行为修改向量X
取决于X
的存储类型以及分配给它的元素。这解释了R
的行为,但没有解释Rstudio的行为。
在R中,当[<-
附加到向量X
或执行需要修改X
类型的子分配时,会复制X
并且返回的值不会覆盖预先存在的变量X
。 (为此,您需要执行X <- "[<-(X, 2, 100)
。
所以,以下都没有修改X
X <- 1:2 ## Note: typeof(X) --> "integer"
## Subassignment that requires that X be coerced to "numeric" type
"[<-"(X, 2, 100) ## Note: typeof(100) --> "numeric"
X
# [1] 1 2
## Appending to X
"[<-"(X, 3, 100L)
X
# [1] 1 2
尽管如此,R确实允许[<-
函数通过引用直接修改X
(即不进行复制)。这里的“可能”包括子作业不要求修改X
类型的情况。
所以以下所有修改X
X <- c(0i, 0i, 0i, 0i)
"[<-"(X, 1, TRUE)
"[<-"(X, 2, 20L)
"[<-"(X, 3, 3.14)
"[<-"(X, 4, 5+5i)
X
# [1] 1.00+0i 20.00+0i 3.14+0i 5.00+5i