我目前在使用 R 保存列表和“子列表”时遇到一个奇怪的问题。标题可能不明确,但这是困扰我的问题:
给定一些数据(这里的数据完全是人为的,但问题不在于模型的相关性):
set.seed(1)
a0 = rnorm(10000,10,2)
b1 = rnorm(10000,10,2)
b2 = rnorm(10000,10,2)
b3 = rnorm(10000,10,2)
data = data.frame(a0,b1,b2,b3)
还有一个返回复杂对象列表的函数(假设
lm()
对象):test = function(k){
tt = vector('list',k)
for(i in 1:k) tt[[i]] = lm(a0~b1+b2+b3,data = data)
tt
}
我们的测试函数返回一个列表
lm()
对象。让我们看看这个对象的大小:ok = test(2)
object.size(ok)
> object.size(ok)
4019336 bytes
让我们创建
ok2
,一个完全相似的对象,但不在函数内:ok2 = vector('list',2)
ok2[[1]] = lm(a0~b1+b2+b3,data = data)
ok2[[2]] = lm(a0~b1+b2+b3,data = data)
...并检查他的尺寸:
> object.size(ok2)
4019336 bytes
我们在这里,
ok
和 ok2
完全一样,所以告诉我们 R。问题,如果我们将这些对象保存在硬盘驱动器上作为 R 对象(使用
save()
或 saveRDS()
):save(ok,file='ok.RData')
save(ok2,file='ok2.RData')
它们在硬盘上的大小分别为:
3 366 005 bytes
和 1 678 851 bytes
.ok
比 ok2
大 2 倍虽然它们完全相似!更奇怪的是,如果你保存我们对象的“子列表”,比如
ok[[1]]
和 ok2[[1]]
(对象再次完全相同):a = ok[[1]]
a2 = ok2[[1]]
save(a,file='console/a.RData')
save(a2,file='console/a2.RData')
它们在硬盘上的大小分别为:
2 523 284 bytes
和 838 977 bytes
.两件事情 :
为什么
a
的大小与a2
的大小不同在硬盘上?为什么ok
的大小与ok2
的大小不同在硬盘上?为什么
a
正好是 ok
的一半尺寸 2 523 284 bytes
而 ok
尺寸在 3 366 005 bytes
在高清?。我错过了什么吗?
ps:我在 Windows 7 32 位下使用 R 2.15.1、2.15.2、2.15.3、3.0.0 以及 debian 和 R 2.15.1、R 2.15.2 运行了这个测试。我每次都遇到这个问题。
编辑
感谢@ user1609452,这里有一个似乎有效的小技巧:
test2 = function(k){
tt = vector('list',k)
for(i in 1:k){
tt[[i]] = lm(a0~b1+b2+b3,data = data)
attr(tt[[i]]$terms,".Environment") = .GlobalEnv
attr(attr(tt[[i]]$model,"terms"),".Environment") = .GlobalEnv
}
tt
}
公式对象带有自己的环境和很多东西。把它放在
NULL
或到 .GlobalEnv 并且它似乎正在工作。像 predict.lm() 这样的函数仍然有效,我们保存的对象在 HD 上有正确的大小。不知道为什么。
最佳答案
看着
> attr(ok[[1]]$terms,".Environment")
<environment: 0x9bcf3f8>
> attr(ok2[[1]]$terms,".Environment")
<environment: R_GlobalEnv>
还
> ls(envir = attr(ok[[1]]$terms,".Environment"))
[1] "i" "k" "tt"
所以
ok
用它在函数的环境中拖动。另请阅读
?object.size
The calculation is of the size of the object, and excludes the
space needed to store its name in the symbol table.
Associated space (e.g. the environment of a function and what the
pointer in a ‘EXTPTRSXP’ points to) is not included in the
calculation.
例如定义一个
test2
和一个 ok3
test2 = function(k){
tt = vector('list',k)
for(i in 1:k) tt[[i]] = lm(a0~b1+b2+b3,data = data)
rr = tt
tt
}
ok3 <- test2(2)
save(ok3, 'ok3.RdData')
> file.info('ok3.RData')$size
[1] 5043933
> file.info('ok.RData')$size
[1] 3366005
> file.info('ok2.RData')$size
[1] 1678851
> ls(envir = attr(ok3[[1]]$terms,".Environment"))
[1] "i" "k" "rr" "tt"
所以
ok
大约是 ok2
的两倍因为它有额外的 tt
和 ok3
是原来的三倍tt
和 rr
> c(object.size(ok),object.size(ok2),object.size(ok3))
[1] 4019336 4019336 4019336
有相关讨论here
关于R:从函数输出中使用 save() 保存 list() 时的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16295507/