4

我目前在使用 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()or 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正好是HDok尺寸2 523 284 bytes的一半?ok3 366 005 bytes

我错过了什么吗?

ps:我在 Windows 7 32bits 下使用 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 上具有正确的大小。不知道为什么。

4

1 回答 1

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因为它有额外的ttok3是它的三倍大,tt并且rr

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

这里有相关的讨论

于 2013-04-30T09:38:58.547 回答