更快地解决循环分组RLE计算问题

时间:2012-10-18 11:40:39

标签: r loops

我的问题有working solution,但我无法使用它,因为它太慢了(我的计算预测整个模拟需要2 - 3年!)。因此,我正在寻找更好(更快)的解决方案。这(实质上)是我正在使用的代码:

N=4
x <-NULL
for (i in 1:N) { #first loop
  v <-sample(0:1, 1000000, 1/2) #generate data
  v <-as.data.frame(v) #convert to dataframe
  v$t <-rep(1:2, each=250) #group
  v$p <-rep(1:2000, each=500) #p.number
  # second loop
  for (j in 1:2000) { #second loop
    #count rle for group 1 for each pnumber
    x <- rbind(x, table(rle(v$v[v$t==1&v$p==j])))
    #count rle for group 2 for each pnumber
    x <- rbind(x, table(rle(v$v[v$t==2&v$p==j])))
  } #end second loop
} #end first loop
#total rle counts for both group 1 & 2
y <-aggregate(x, list(as.numeric(rownames(x))), sum)

单词:代码生成一个硬币翻转模拟(v)。生成组因子(1&amp; 2)。生成p.number因子(1:2000)。对于组1和组1,每个p.number(1:2000)记录运行长度。第2组(每个p.number都在两组中运行)。在N循环(第一个循环)之后,总运行长度表示为一个表(聚合)(即每个组的运行长度,对于每个p.number,超过N循环总计)。

我需要第一个循环,因为我正在使用的数据来自单个文件(因此我正在加载文件,计算各种统计信息等,然后加载下一个文件并执行相同操作)。我对第二个循环的依赖性要小得多,但无法弄清楚如何用更快的东西替换它。

第二个循环可以做些什么(希望,很多)更快?

2 个答案:

答案 0 :(得分:8)

你承诺在R中for()循环内生长一个物体的主要罪行。不要(我重复不)这样做。在开始时为x分配足够的存储空间,然后在出发时填写x

x <- matrix(nrow = N * (2000 * 2), ncol = ??)

然后在内循环

x[ii, ] <- table(rle(....))

其中ii是一个循环计数器,在第一个循环之前初始化为1并在第二个循环中递增:

x <- matrix(nrow = N * (2000 * 2), ncol = ??)
ii <- 1
for(i in 1:N) {
    .... # stuff here
    for(j in 1:2000) {
        .... # stuff here
        x[ii, ] <- table(rle(....))
        ## increment ii
        ii <- ii + 1
        x[ii, ] <- table(rle(....))
        ## increment ii
        ii <- ii + 1
    } ##  end inner loop
} ## end outer loop

另请注意,您正在重复使用()i i loops which will not work. for(is just a normal R object and so both j`的机器人中的索引loops will be overwriting it as the progress. USe作为第二个循环,如上所述。

首先尝试这种简单的优化,看看是否允许真实模拟在可接受的时间内完成。如果没有,请返回显示最新代码的新Q,我们可以考虑其他优化。上面的优化很简单,优化table()rle()可能需要做更多的工作。注意到,您可能会查看tabulate()函数,该函数在table()中执行繁重工作,这可能是优化该特定步骤的一种途径。

答案 1 :(得分:2)

如果您只想分别为rletable的每个值组合运行v$tv$p,则无需第二个循环。它以这种方式更快:

values <- v$v + v$t * 10 + v$p * 100
runlength <- rle(values)
runlength$values <- runlength$values %% 2
x <- table(runlength)


y <- aggregate(unclass(x), list(as.numeric(rownames(x))), sum)

整个代码看起来像这样。如果N低至4,则不断增长的对象x将不会成为严重问题。但一般来说,我同意@GavinSimpson,它不是一个好的编程技术。

N=4
x <-NULL
for (i in 1:N) { #first loop
  v <-sample(0:1, 1000000, 1/2) #generate data
  v <-as.data.frame(v) #convert to dataframe
  v$t <-rep(1:2, each=250) #group
  v$p <-rep(1:2000, each=500) #p.number

  values <- v$v + N * 10 + v$t * 100 + v$p * 1000
  runlength <- rle(values)
  runlength$values <- runlength$values %% 2
  x <- rbind(x, table(runlength))

} #end first loop
y <-aggregate(x, list(as.numeric(rownames(x))), sum) #tota