2017-02-13 1 views
0

R에 "for"루프가 전혀 필요 없다고 들었습니다.루프를 없애는 방법

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 
    } 
+2

'R'에서 인접한 엘레멘트의 차이점을 얻으려면'diff' 함수가 있습니다. 또한'dplyr'에서'lead'와'lag' 함수를 확인하십시오. – akrun

+7

누가 잘못 했습니까? 일부 작업에는 루프가 필요합니다. –

+0

'for 루프'가 선호되는 방법이 있습니다. 'for 루프 '를 구현하는시기에 대한 자세한 설명은 [this] (http://stackoverflow.com/a/6466415/4408538)의 글을 참고하십시오. 이러한 게시물을 확인하여 R의 루핑 구문을 더 잘 이해할 수 있습니다. [post1] (http://stackoverflow.com/a/2276001/4408538) 및 [post2] (http://stackoverflow.com/q/28983292/4408538). –

답변

1

내 경험에 의하면, 루프에는 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 

을 제공합니다 : 약간의 변화는 모든 방법 벡터 속도로 그것을 얻을 루프까지 약간의 속도를 높일 수는 없지만 벡터화 된 솔루션보다 여전히 느린 방법입니다.

+0

와우! 환상적입니다. 통찰력에 감사드립니다. – whirlaway

+0

@whirlaway - 그 질문에 대한 답변을 했습니까? –

+0

예, 그랬습니다. 그리고 더. 고맙습니다. – whirlaway

0
yrdf <- data.frame(Adj.Close = rnorm(100)) 
numrows <- length(yrdf$Adj.Close) 
diff.vec <- c((yrdf$Adj.Close[1:(numrows-1)]/yrdf$Adj.Close[2:numrows] - 1) * 100, NA) 
0

당신은 또한 결과를 얻기 위해 dplyr 패키지에서 lead 기능을 사용할 수 있습니다 : 그래서, 나는 내가 내 R 코드에서 "for"루프이 파이썬 등으로 제거하는 방법을보고 싶어 당신이 원하는 그.

library(dplyr) 
yrdf <- data.frame(Adj.Close = rnorm(100)) 
(yrdf$Adj.Close/lead(yrdf$Adj.Close)-1)*100 

계산은 (a-b)/b에서 a/b-1로 단순화되었습니다. for 루프 대신 벡터화 된 연산입니다.

관련 문제