2017-02-13 28 views
0

Rに「for」ループをまったく入れる必要はないと言われています。だから、私はこのPythonのような私のRコードのループ「のため」を取り除くことができますどのように見てみたい:このループを取り除く方法

ます。また、結果を得るために dplyrパッケージから lead機能を使用することができます
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ループを避ける3つの理由があります。 1つは、他の人が(コードを共有している場合)読みにくく、applyファミリーの機能がそれを改善できること(そして返品についてより明示的になること)です。 2つ目は、コードを並行して実行する場合(特に、ほとんどのapply関数は恥ずかしそうに並列ですが、forループは分割するほうがはるかに多くの作業が必要です)、状況によっては速度の利点があります。

しかし、それはここで役立つ3つ目の理由です:繰り返しの呼び出しを避けるため、ベクトル化されたソリューションは上のいずれの場合よりも優れています(例えば、ループの最後のcifチェックなど) 。ここでは、ベクトル化された単一の呼び出しですべてを達成できます。

するとまず、いくつかのサンプルデータ

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比較でありますループの時間の約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

あなたがしたいこと。

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ループではなくベクトル化された操作です。

関連する問題