내 경험에 의하면, 루프에는 for
회피를 피하는 세 가지 이유가 있습니다. 첫 번째는 (코드를 공유하는 경우) 다른 사람들이 읽기 어려울 수 있으며, apply
계열의 기능이이를 향상시킬 수 있고 (반환에 대해보다 명확하게 표현할 수 있음) 두 번째는 코드를 병렬로 실행하려는 경우 (특히 대부분의 apply
함수는 당황스럽게 병렬이지만 for
루프는 분리해야하는 작업이 훨씬 더 많음) 일부 상황에서는 속도 이점이 있습니다.
그러나 여기에서는 세 번째 이유가 있습니다. 반복 된 호출을 피하기 때문에 벡터화 된 솔루션이 위의 것보다 우수한 경우가 많습니다 (예 : 루프 끝의 c
, if
수표 등) . 여기서는 하나의 벡터화 된 호출로 모든 것을 수행 할 수 있습니다.
첫째, 일부 샘플 데이터
set.seed(8675309)
yrdf <- data.frame(Adj.Close = rnorm(5))
그런 다음, 우리가 100
에 의해 모든 것을 곱은 Adj.Close
에 인접한 항목의 diff
을 다음과 같은 항목으로 분할하는 벡터화 부문을 사용합니다. 결과가 입력과 동일한 길이가 되려면 NA
으로 패드해야합니다. 벡터의 끝에 NA
을 원하지 않거나 필요로하지 않는다면 훨씬 쉽습니다.
myForLoop <- function(){
numrows = nrow(yrdf)
diff.vec = c() # vector of differences
for (index in 1:nrow(yrdf)) { # yrdf is a data frame
if (index == numrows) {
diff = NA # because there is no entry "below" it
} else {
val_index = yrdf$Adj.Close[index]
val_next = yrdf$Adj.Close[index+1]
diff = val_index - val_next # diff between two adjacent values
diff = diff/yrdf$Adj.Close[index+1] * 100.0
}
diff.vec<-c(diff.vec,diff) # append to vector of differences
}
return(diff.vec)
}
microbenchmark::microbenchmark(
forLoop = myForLoop()
, vector = 100 * c(diff(yrdf$Adj.Close),NA)/c(yrdf$Adj.Close[2:nrow(yrdf)], NA)
)
이 제공 : 다음 vector
접근이 걸릴 것으로
Unit: microseconds
expr min lq mean median uq max neval
forLoop 74.238 78.184 82.06786 81.287 84.3740 104.190 100
vector 20.193 21.718 23.91824 22.716 24.0535 80.754 100
주
100 * c(diff(yrdf$Adj.Close),NA)/c(yrdf$Adj.Close[2:nrow(yrdf)], NA)
반환
[1] 238.06442 216.94975 130.41349 -90.47879 NA
그리고는, 명시 적으로, 여기에
microbenchmark
비교입니다 루프는
for
루프의 약 30 %입니다. - 벡터 버전의 적은 0.1 %를 소요 이러한 규모
대규모 방법의 차이가 있음을
Unit: microseconds
expr min lq mean median uq max neval
forLoop 306883.977 315116.446 351183.7997 325211.743 361479.6835 545383.457 100
vector 176.704 194.948 326.6135 219.512 236.9685 4989.051 100
참고를 제공
set.seed(8675309)
yrdf <- data.frame(Adj.Close = rnorm(10000))
microbenchmark::microbenchmark(
forLoop = myForLoop()
, vector = 100 * c(diff(yrdf$Adj.Close),NA)/c(yrdf$Adj.Close[2:nrow(yrdf)], NA)
)
: 이것은 데이터의 크기가 증가로 더 중요 얻는다 달릴 시간. 여기에 새로운 항목을 추가하기 위해 c
을 호출 할 때 전체 벡터를 다시 읽어야하기 때문에 가능합니다.
myForLoopAlt <- function(){
numrows = nrow(yrdf)
diff.vec = numeric(numrows) # vector of differences
for (index in 1:nrow(yrdf)) { # yrdf is a data frame
if (index == numrows) {
diff = NA # because there is no entry "below" it
} else {
val_index = yrdf$Adj.Close[index]
val_next = yrdf$Adj.Close[index+1]
diff = val_index - val_next # diff between two adjacent values
diff = diff/yrdf$Adj.Close[index+1] * 100.0
}
diff.vec[index] <- diff # append to vector of differences
}
return(diff.vec)
}
microbenchmark::microbenchmark(
forLoop = myForLoop()
, newLoop = myForLoopAlt()
, vector = 100 * c(diff(yrdf$Adj.Close),NA)/c(yrdf$Adj.Close[2:nrow(yrdf)], NA)
)
가 for
루프 방식 오프 시간의 절반을 저장
Unit: microseconds
expr min lq mean median uq max neval
forLoop 304751.250 315433.802 354605.5850 325944.9075 368584.2065 528732.259 100
newLoop 168014.142 179579.984 186882.7679 181843.7465 188654.5325 318431.949 100
vector 169.569 208.193 331.2579 219.9125 233.3115 2956.646 100
을 제공합니다 : 약간의 변화는 모든 방법 벡터 속도로 그것을 얻을 루프까지 약간의 속도를 높일 수는 없지만 벡터화 된 솔루션보다 여전히 느린 방법입니다.
'R'에서 인접한 엘레멘트의 차이점을 얻으려면'diff' 함수가 있습니다. 또한'dplyr'에서'lead'와'lag' 함수를 확인하십시오. – akrun
누가 잘못 했습니까? 일부 작업에는 루프가 필요합니다. –
'for 루프'가 선호되는 방법이 있습니다. 'for 루프 '를 구현하는시기에 대한 자세한 설명은 [this] (http://stackoverflow.com/a/6466415/4408538)의 글을 참고하십시오. 이러한 게시물을 확인하여 R의 루핑 구문을 더 잘 이해할 수 있습니다. [post1] (http://stackoverflow.com/a/2276001/4408538) 및 [post2] (http://stackoverflow.com/q/28983292/4408538). –