ローリング平均
ローリング平均(移動平均とも呼ばれます)は、時系列解析でノイズをならすために使われます。各時点の値を、その近傍の時点(window)の平均値に置き換えます。
この関数を自然に書くと次のようになります。
rollmean1 <- function(x, window = 3) {
n <- length(x)
res <- rep(NA, n)
for(i in seq(window, n)) {
res[i] <- mean(x[seq(i - window + 1, i)])
}
res
}
これは mean() を何度も呼び出すため、非効率です。1つの解決策は total という変数を使い、各ループの反復で不要になった要素を引き、新しい要素を足す方法です。
rollmean2 <- function(x, window = 3){
n <- length(x)
res <- rep(NA, n)
total <- sum(head(x, window))
res[window] <- total / window
for(i in seq(window + 1, n)) {
total <- total + x[i] - x[i - window]
res[i] <- total / window
}
res
}
いずれにせよ、ベクトル化よりもループで書くほうが自然ですが、その分パフォーマンスが下がることがあります。上の2つの実装はいずれもそれぞれのやり方で非効率です。次の演習でC++版に進む前に、ここではベクトル化を使った版を書いてみましょう。rollmean1()、rollmean2()、そして乱数ベクトル x はワークスペースに用意されています。これから rollmean3() の関数定義を完成させ、これらの関数のパフォーマンスをベンチマークします。
この演習はコースの一部です
Rcpp で R コードを最適化する
実践的なインタラクティブ演習
このサンプルコードを完成させて、この演習に挑戦してみましょう。
# Complete the definition of rollmean3()
rollmean3 <- function(x, window = 3) {
# Add the first window elements of x
initial_total <- ___(head(x, window))
# The elements to add at each iteration
lasts <- tail(x, - window)
# The elements to remove
firsts <- head(x, - window)
# Take the initial total and add the
# cumulative sum of lasts minus firsts
other_totals <- ___ + ___(___ - firsts)
# Build the output vector
c(
rep(NA, window - 1), # leading NA
initial_total / ___, # initial mean
other_totals / ___ # other means
)
}