最大的问题和无效的根源是索引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)
}
正如你所看到的,我创建了收集结果的向量。最后,我将它添加到data.frame,我不需要打乱名称。
那么它有多好呢?
我用nrow从1000到10,000 × 1000运行data.frame的每个函数,并用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在他们的答案中所述,向量化是获得更好性能的关键。
从你的代码,你可以移动到循环之外:
调节
结果的初始化(是temp[i,9])
这导致了这段代码
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乘10,000。
调谐调谐
另一个调整是将循环索引temp[i,9]更改为res[i](在第i个循环迭代中完全相同)。
这又是索引向量和索引data。frame的区别。
第二件事:当你查看循环时,你可以看到不需要遍历所有的i,而只对符合条件的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行小于1秒的计算时间。
如果你想更进一步,我认为至少有两件事是可以做到的:
写一个C代码来做条件累加
如果你知道你的数据Max序列不是很大,那么你可以把循环改为向量化
While (any(cond)) {
cond <- c(FALSE, cond[-1] & !cond[-n])
Res [indx] <- Res [indx] + Res [which(indx)-1]
cond[indx] <- FALSE
}
用于模拟和图形的代码可在GitHub上获得。