关于这个答案: R中的复制修改语义到底是什么,以及规范来源在哪里?
我们可以看到,在第一次改变'[<-'矢量时,即使只修改一个条目,R也会复制整个矢量.然而,在第二次,矢量"就地"改变.如果我们测量创建和修改大向量的时间,则在不检查对象的地址的情况下这是显而易见的:
> system.time(a <- rep(1L, 10^8))
user system elapsed
0.15 0.17 0.31
> system.time(a[222L] <- 111L)
user system elapsed
0.26 0.08 0.34
> system.time(a[333L] <- 111L)
user system elapsed
0 0 0
Run Code Online (Sandbox Code Playgroud)
请注意,类型/ storage.mode没有变化.
所以问题是:为什么不能优化第一个括号分配呢?在什么情况下实际需要这种行为(第一次修改时的完整拷贝)?
编辑:(剧透!)正如下面接受的答案中所解释的,这只不过是在system.time函数调用中包含第一个赋值的工件.这导致R将绑定的内存空间标记a为可能引用多个符号,因此在更改时需要重复.如果我们删除封闭调用,则会从第一个括号分配中修改向量.
感谢Martin提供深入的解决方案!
在修改数据框中的一个条目时,R似乎复制整个数据帧.我想知道是否有办法让R只复制相应的数据列(例如下面的特定INTSXP而不是VECSXP)来维护复制变更策略?还有办法对数据帧进行现场修改吗?
> x<-data.frame(x=1:1000000,y=1:1000000)
> .Internal(inspect(x))
@62cd2b0 19 VECSXP g0c2 [OBJ,MARK,NAM(2),ATT] (len=2, tl=0)
@f80d0e0 13 INTSXP g0c7 [MARK] (len=1000000, tl=0) 1,2,3,4,5,...
@8ed6970 13 INTSXP g0c7 [] (len=1000000, tl=0) 1,2,3,4,5,...
ATTRIB:
@68f6b40 02 LISTSXP g0c0 []
TAG: @4e58868 01 SYMSXP g1c0 [MARK,LCK,gp=0x4000] "names" (has value)
@613efd0 16 STRSXP g0c2 [] (len=2, tl=0)
@4e93038 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "x"
@4fe8bd8 09 CHARSXP g1c1 [MARK,gp=0x61] [ASCII] [cached] "y"
TAG: @4e62650 01 SYMSXP g1c0 [MARK,LCK,gp=0x4000] "row.names" (has value)
@113bb328 13 INTSXP g0c1 [] …Run Code Online (Sandbox Code Playgroud)