假设我在R中创建了一个列表并按如下方式附加到它:
x = list(10)
x[[2]] = 20
Run Code Online (Sandbox Code Playgroud)
这相当于
x = list(10)
x = list(10, 20)
Run Code Online (Sandbox Code Playgroud)
?我对R如何处理内存中的列表的具体细节不太熟悉,但我的理解有限,它往往是复制快乐; 对我来说最理想的是第一个选项并不涉及在内存中创建另一个列表,而只是在内存中为附加值留出一个新位置.基本上,如果我有一个大的列表,我不希望R再制作它的另一个副本,如果我只想附加一些东西.
如果我想要的行为不是这里给出的,那么还有其他方法可以达到预期的效果吗?
flo*_*del 16
我很自信答案是"不".我使用以下代码仔细检查:
Rprof(tmp <- tempfile(), memory.profiling = TRUE)
x <- list()
for (i in 1:100) x[[i]] <- runif(10000)
Rprof()
summaryRprof(tmp, memory = "stats")
unlink(tmp)
Run Code Online (Sandbox Code Playgroud)
输出:
# index: runif
# vsize.small max.vsize.small vsize.large max.vsize.large
# 76411 381781 424523 1504387
# nodes max.nodes duplications tot.duplications
# 2725878 13583136 0 0
# samples
# 5
Run Code Online (Sandbox Code Playgroud)
相关部分是duplications = 0
.
mne*_*nel 12
马修Dowle的答案在这里和后面的内存效率的理由是停止幕后的众多复制的<-
,[<-
,[[<-
和其他基本R
操作(names
等)
[[<-
将复制整个x
.请参阅下面的示例
x <- list(20)
tracemem(x)
#[1] "<0x2b0e2790>"
x[[2]] <- 20
# tracemem[0x2b0e2790 -> 0x2adb7798]:
Run Code Online (Sandbox Code Playgroud)
你的第二个案子
x <- list(10,20)
Run Code Online (Sandbox Code Playgroud)
并不是真正附加原始文件,x
而是替换x
为恰好是x
具有附加值的原始对象.
为了帮助我弄清楚修改列表是做深拷贝还是浅拷贝,我设置了一个小实验.如果修改列表会生成深层副本,那么当您修改包含大对象的列表与包含小对象的列表时,它应该更慢:
z1 <- list(runif(1e7))
z2 <- list(1:10)
system.time({
for(i in 1:1e4) z1[1 + i] <- 1L
})
# user system elapsed
# 0.283 0.034 0.317
system.time({
for(i in 1:1e4) z2[1 + i] <- 1L
})
# user system elapsed
# 0.284 0.034 0.319
Run Code Online (Sandbox Code Playgroud)
我的计算机上的计时基本相同,这表明复制列表会产生浅拷贝,复制指向现有数据结构的指针.
接受了 flodel 的回答,但 Chase 的提示很好,所以我使用他的建议使用tracemem()
. 这是第一个示例,我们只是将其附加到列表中:
x = list(10)
tracemem(x[[1]])
# [1] "<0x2d03fa8>" #(likely different on each machine)
x[[2]] = 20
tracemem(x[[1]])
# [1] "<0x2d03fa8>"
Run Code Online (Sandbox Code Playgroud)
这是第二个示例的结果,我们在其中创建了两个列表:
x = list(10)
tracemem(x[[1]])
# [1] "<0x2d03c78>"
x = list(10, 20)
tracemem(x[[1]])
# [1] "<0x2d07ff8>"
Run Code Online (Sandbox Code Playgroud)
因此,第一种方法似乎提供了所需的行为。
归档时间: |
|
查看次数: |
2078 次 |
最近记录: |