私の経験上、for
ループを避ける3つの理由があります。 1つは、他の人が(コードを共有している場合)読みにくく、apply
ファミリーの機能がそれを改善できること(そして返品についてより明示的になること)です。 2つ目は、コードを並行して実行する場合(特に、ほとんどのapply
関数は恥ずかしそうに並列ですが、for
ループは分割するほうがはるかに多くの作業が必要です)、状況によっては速度の利点があります。
しかし、それはここで役立つ3つ目の理由です:繰り返しの呼び出しを避けるため、ベクトル化されたソリューションは上のいずれの場合よりも優れています(例えば、ループの最後の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
比較でありますループの時間の約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)。 –