【问题标题】:Operator "[<-" in RStudio and RRStudio 和 R 中的运算符“[<-”
【发布时间】:2017-09-10 19:09:35
【问题描述】:

偶然我遇到了"[&lt;-" 操作员的奇怪行为。它的行为取决于调用顺序以及我使用的是 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),情况看起来完全一样。 我知道“功能”版本 ("[&lt;-"(x..)) 可能从未使用过,但我很好奇它为什么会发生。谁能解释一下?

===========================

编辑: 好的,所以我从 cmets 得知原因是 x &lt;- 1:10 的类型为“整数”,而在替换 x[5] &lt;- 123 后它是“双”。 但仍然存在疑问,为什么 RStudio 中的行为不同?我重新启动 R 会话,它没有改变任何东西。

【问题讨论】:

  • 这可能值得一读stackoverflow.com/questions/15178507/…——但这不是同一个问题
  • plain old R 是什么意思?
  • 这是一个疯狂的猜测,我不确定如何测试它,但在 mnel 链接到的问题中,指出如果有第二个对替换的对象的引用不会在原地完成,但会产生一个副本(因此不会修改原始变量)。也许 RStudio 作为其 GUI 的一部分,具有对该对象的引用。这是可能的,因为它有一个对象浏览器。或者触发复制机制而不是就地替换行为的其他方面。
  • 我无法在 RStudio 和 RGUI(以及使用 Rterm 的 Eclipse)中重现这种相同的行为(顺序很重要)。
  • @Arun -- 作为马特的问题。也就是说,当您一次粘贴所有命令时,Rstudio 的对象浏览器没有机会“触摸”x,其方式是将其named 字段重置为2,直到发生子分配之后。您(或使用 Rstudio 的其他人)可以通过粘贴 x &lt;- 1:10; .Internal(inspect(x)) 来测试这一点,或者一次全部粘贴,或者一个一个粘贴。在第一种情况下,我希望看到[MARK,NAM(1)] 和第二种[MARK,NAM(2)]。如果是这样,我认为这个谜团已经基本解决了。

标签: r rstudio


【解决方案1】:

Rstudio 的行为

Rstudio 的对象浏览器修改它检查的对象,在修改时强制复制。具体来说,对象浏览器使用至少一个 R 函数,其调用在内部强制评估对象,在此过程中将对象的 named 字段的值从 1 重置为 2。来自R-Internals manual

当一个对象即将被更改时,会查询指定的字段。值 2 表示对象必须在被更改之前被复制。 [...] 值 1 用于 [...] 原则上在计算期间存在两个副本的情况 [...] 但不再存在,因此可以优化一些原始函数在这种情况下避免复制。

要查看对象浏览器修改了 named 字段(下一个代码块中的[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,... 

一旦 named 字段设置为 2,[&lt;-(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 

[

的可变行为

[&lt;- w.r.t. 的行为修改向量X 取决于X 的存储类型以及分配给它的元素的存储类型。这解释了R 的行为,而不是 Rstudio 的行为。

在 R 中,当 [&lt;- 附加到向量 X 或执行要求修改 X 的类型的子赋值时,X 被复制并且返回的值不会覆盖预先存在的变量X。 (为此,您需要执行X &lt;- "[&lt;-(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 确实允许[&lt;- 函数通过引用直接修改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

【讨论】:

  • 我已经复制了你的最后一个例子,结果是一样的,但是在替换 "[&lt;-"(X, 2, 20L) 之前我运行命令 typeof(X),然后替换不起作用(在 RGui 中)。奇怪。
  • @JoshO'Brien:供参考层次结构使用:?Comparison
  • 命名字段用于引用计数,表示内存中有多少变量指向该对象。它可以是 1 或 2,是超过 1 的缩写。这是一种性能优化,允许简单的分配和删除,以避免需要垃圾收集器。我怀疑它在 RStudio 中设置为 2,因为有两个对该对象的引用:一个在控制台中,一个在对象浏览器中。
  • 我在 R-Devel 上给出了一个稍微完整的答案,但你不需要知道 C 来了解 class()typeof() 之间的区别的要点——只需在以下位置输入它们R 提示并注意打印内容的差异。
  • @JoshO'Brien 您知道 RStudio 页面上有关此“功能”的任何相关文档/问题吗?我曾计划解决Confused about NAMED 的答案,但已经落到问题 的第二行:y = 1:10 "NAM(1) as expected"。不,不是在 Rstudio 中...感谢您的出色回答,挽救了我的一天。
猜你喜欢
  • 2014-03-23
  • 2018-11-10
  • 1970-01-01
  • 2012-07-20
相关资源
最近更新 更多