가장 큰 문제와 비효율의 뿌리는 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에서 1,000 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
조건 값의 백분율 . 시뮬레이션 된 데이터의 경우 1 초 미만의 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에서 사용할 수 있습니다 .