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

Fra*_*fka 1 loops r

我有一个解决我的问题的工作解决方案,但我将无法使用它因为它太慢(我的计算预测整个模拟将需要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)
Run Code Online (Sandbox Code Playgroud)

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

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

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

Rei*_*son 8

你承诺for()在R 的循环中生长一个对象的主要罪过.不要(我重复不要)这样做.x在开始时分配足够的存储空间,然后在x您开始时填写.

x <- matrix(nrow = N * (2000 * 2), ncol = ??)
Run Code Online (Sandbox Code Playgroud)

然后在内循环中

x[ii, ] <- table(rle(....))
Run Code Online (Sandbox Code Playgroud)

在第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
Run Code Online (Sandbox Code Playgroud)

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

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

  • 不,你误解了.循环**不坏**!你做这些的方式是**坏**.`for()`几乎和`lapply()`和朋友一样快,如果你正确地编写循环并且不在循环中增长对象.为整个对象分配存储,然后填写该对象.当你将rbind()结果放在一起时,R必须通过复制`x`来创建一个新对象,使它更大一行,并将新数据分配给那个新对象并将其全部分配为`x`.所有这些都需要花费很多时间. (3认同)