R:使用函数输出中的save()保存list()时出现奇怪的行为

时间:2013-04-30 08:35:31

标签: r

我目前在使用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

我们在这里,okok2完全相同,因此告诉我们R. 问题,如果我们将这些对象作为R对象保存在硬盘驱动器上(使用save()saveRDS()):

save(ok,file='ok.RData')
save(ok2,file='ok2.RData')

硬盘上的尺寸分别为:3 366 005 bytes1 678 851 bytesokok2大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 bytes838 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上的大小合适。不知道为什么会这样。

1 个答案:

答案 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.

例如,定义test2ok3

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的两倍,因为它有额外的ttok3tt的三倍大rr

> c(object.size(ok),object.size(ok2),object.size(ok3))
[1] 4019336 4019336 4019336

有相关讨论here