最大的问题和无效的根源是索引data.frame,我的意思是所有这些行都在您使用的地方进行temp[,]
。
尽量避免这种情况。我接受了您的功能,更改了索引,然后在这里version_A
dayloop2_A <- function(temp){
res <- numeric(nrow(temp))
for (i in 1:nrow(temp)){
res[i] <- i
if (i > 1) {
if ((temp[i,6] == temp[i-1,6]) & (temp[i,3] == temp[i-1,3])) {
res[i] <- temp[i,9] + res[i-1]
} else {
res[i] <- temp[i,9]
}
} else {
res[i] <- temp[i,9]
}
}
temp$`Kumm.` <- res
return(temp)
}
如您所见,我创建了res
收集结果的向量。最后,我将其添加到其中data.frame
,而无需弄乱名称。那有什么更好的呢?
我data.frame
以nrow
1,000到10,000 x 10,000 运行每个函数,并用system.time
X <- as.data.frame(matrix(sample(1:10, n*9, TRUE), n, 9))
system.time(dayloop2(X))
结果是
您可以看到您的版本与呈指数关系nrow(X)
。修改后的版本具有线性关系,简单的lm
模型预测,对于850,000行,计算将花费6分钟10秒。
向量化的力量
正如Shane和Calimo在他们的答案中所述,矢量化是提高性能的关键。从您的代码中,您可以移出循环:
这导致此代码
dayloop2_B <- function(temp){
cond <- c(FALSE, (temp[-nrow(temp),6] == temp[-1,6]) & (temp[-nrow(temp),3] == temp[-1,3]))
res <- temp[,9]
for (i in 1:nrow(temp)) {
if (cond[i]) res[i] <- temp[i,9] + res[i-1]
}
temp$`Kumm.` <- res
return(temp)
}
比较此功能的结果,这次是nrow
从10,000到100,000 x 10,000。
调优
另一个调整是将循环索引更改temp[i,9]
为res[i]
(在第i个循环迭代中完全相同)。索引向量和索引a还是有区别data.frame
。
第二件事:当您查看循环时,您会发现不需要循环全部i
,而只需要对那些符合条件的循环进行循环。
所以我们开始
dayloop2_D <- function(temp){
cond <- c(FALSE, (temp[-nrow(temp),6] == temp[-1,6]) & (temp[-nrow(temp),3] == temp[-1,3]))
res <- temp[,9]
for (i in (1:nrow(temp))[cond]) {
res[i] <- res[i] + res[i-1]
}
temp$`Kumm.` <- res
return(temp)
}
您获得的性能很大程度上取决于数据结构。精确地-根据TRUE
条件值的百分比。对于我的模拟数据,一秒钟以下需要花费850,000行的计算时间。
我希望您可以走得更远,我认为至少可以做两件事:
- 编写
C
代码来做条件累加
如果您知道最大数据序列中的序列不大,则可以将循环更改为矢量化,例如
while (any(cond)) {
indx <- c(FALSE, cond[-1] & !cond[-n])
res[indx] <- res[indx] + res[which(indx)-1]
cond[indx] <- FALSE
}
GitHub上提供了用于仿真和图形的代码。