我目前在使用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运行此测试。我每次都遇到这个问题。
修改
thx到@ 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上的大小合适。不知道为什么会这样。
答案 0 :(得分:5)
看看
> 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