第二轮回 增长的对象

我们到了第二站,这里居住着贪婪的人.

让我们看看创建一个有序系列的三种方法.

 

方法一是增长这个对象:

vec <- numeric(0)
for(i in 1:n) vec <- c(vec, i)

方法二是首先创建一个固定长度的对象,然后通过下表改变其中的值:

vec <- numeric(n)
for(i in 1:n) vec[i] <- i

方法三直接创建最终的对象:

vec <- 1:n


表2.1展示了在固定的n的情况下,用一个普通的计算机运行三种方法的秒数.

N的增长基本在重对数尺度上是线性的,但是运行时间却明显不同.

你或许会好奇为什么对象增长如此得慢.是因为郊区城市化需要计算开销.当一个新的大小被需要时,对象所存储的地方没有足够的空间,然后这个对象需要被移动到一个更大的空间.然后当这个空间又不能满足对象的增长的时候,这个对象就又会被移动到一个更大的地方去.移动对象花去了非常多的时间.就像现实中的郊区城市化,增长的对象掠夺了一切有用的空间.最终你的存储介质中全是碎片化的可以用空间,没有大的存储块.这被称为破裂内存.

 

一个非常普遍---或许也是非常危险的方法是用函数rbind():

my.df <- data.frame(a=character(0), b=numeric(0))
for(i in 1:n) 
{
   my.df <- rbind(my.df, data.frame(a=sample(letters, 1),
   b=runif(1)))
}

或许rbind()如此通用的主要原因是:每一次迭代都可能会有一个不同的数量的结果.如果这样的话,代码更可能会是这样:

my.df <- data.frame(a=character(0), b=numeric(0))
for(i in 1:n)
{
  this.N <- rpois(1, 10)
  my.df <- rbind(my.df, data.frame(a=sample(letters,
  this.N, replace=TRUE), b=runif(this.N)))
}


通常最终对象的大小的上界是知道的,如果是这样,那就像创建一个上界大小的对象,然后对其赋值.如果最终的大小无法确定,那么你仍旧可以按照上边的做法,但是允许一段时间内对象空间的增长.

<p><span style="color:#000000;">current.N <- 10 * n</span></p><p><span style="color:#000000;">my.df <- data.frame(a=character(current.N),</span></p><p><span style="color:#000000;">b=numeric(current.N))</span></p><p><span style="color:#000000;">count <- 0</span></p><p><span style="color:#000000;">for(i in 1:n) {</span></p><p><span style="color:#000000;">this.N <- rpois(1, 10)</span></p><p><span style="color:#000000;">if(count + this.N > current.N) {</span></p><p><span style="color:#000000;">old.df <- my.df</span></p><p><span style="color:#000000;">current.N <- round(1.5 * (current.N + this.N))</span></p><p><span style="color:#000000;">my.df <- data.frame(a=character(current.N),</span></p><p><span style="color:#000000;">b=numeric(current.N))</span></p><p><span style="color:#000000;">my.df[1:count,] <- old.df[1:count, ]</span></p><p><span style="color:#000000;">}</span></p><p><span style="color:#000000;">my.df[count + 1:this.N,] <- data.frame(a=sample(letters,</span></p><p><span style="color:#000000;">this.N, replace=TRUE), b=runif(this.N))</span></p><p><span style="color:#000000;">count <- count + this.N</span></p><p><span style="color:#000000;">}</span></p><p><span style="color:#000000;">my.df <- my.df[1:count,]</span></p>

通常有一个简单地方法解决整个问题---主动创建一系列的对象块,然后最后将它们整合.

my.list <- vector(’list’, n)
for(i in 1:n) 
{
   this.N <- rpois(1, 10)
   my.list[[i]] <- data.frame(a=sample(letters, this.N
   replace=TRUE), b=runif(this.N))
}
my.df <- do.call(’rbind’, my.list)

下面的例子展示了将动态增长的对象聪明地隐藏掉的方法:每一次,当条件为真,hit就会增长.

hit <- NA
for(i in 1:one.zillion) 
{
   if(runif(1) < 0.3) hit[i] <- TRUE
}

消除增长的变量是提高R运行速度的最简单效果最卓著的方法之一.

 

假如你是用了太多的内存,R将会抱怨.关键因素是R将所有的数据都存在RAM之中.当你需要使用一个巨大的数据集时,这将是一个局限.R的上限是灵活的,特别地,R对于数据的类型从不挑剔.

 

你可以得到一条信息,对于一些筒子太熟悉了,比如:

Error: cannot allocate vector of size 79.8 Mb.

 

这个经常曲解了我有xxx GB 的内存,为何R甚至不能分配80MB的空间的意思这是因为R已经成功分配了大量的内存.这个错误信息是有多少内存R在运行失败点经历的.

 

看到过这种信息的筒筒就会问到:那我该怎么办呢?这里有一些简单地答案:

1.不要变成一个使用脑残程序结构的贪婪人

2.换一个大一点的计算机

3.降低问题大小

 

如果你认同第一天而对第二三条不敢苟同的话,你的替代选择将会很难.一种方法是重新启动R,但将是低效的.另外一个选择是检查你的代码哪里在消耗内存.你可以在代码中插入;

cat(point 1 mem, memory.size(), memory.size(max=TRUE), \n)

这将展示你的R代码时时使用内存情况和当前任务中R使用的最大内存.

 

然而,或许一种更加有效更能提供信息帮助的程序是使用Rprof()输出内存.Rprof()也会输出时间使用情况.另外一种降低内存使用的方法是使用数据库.仅仅提取程序使用的那一部分数据.虽然存取数据会花上一点开销,但是这也是一种常用的方法.

 

一个仅仅使用R数据库解决方案是保存对象在一个独立的文件中,实时使用.你的代码就可能像下边这样:

for(i in 1:n) 
{
   objname <- paste(’obj.’, i, sep=’’)
   load(paste(objname, ’.rda’, sep=’’))
   the obj <- get(objname)
   rm(list=objname)
   # use the obj
}

将来的超级计算机会解决这个问题吗?一些人的回答是:yes---他们的数据规模保持不便而计算机将强大的足够处理这些数据.对于另外一些人,他们认为情况会变得更糟糕哦---更强大的计算机意味着更大的数据集.如果你是第二种人.你或许现在都想使用数据库工作.

 

如果你拥有一台超级计算机,你或许会尝试去创建一些大型的R不能解决的问题.:

?Memory-limits’了解相关信息.

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值