1. 学ぶ
  2. /
  3. コース
  4. /
  5. Rcpp で R コードを最適化する

Connected

演習

ローリング平均

ローリング平均(移動平均とも呼ばれます)は、時系列解析でノイズをならすために使われます。各時点の値を、その近傍の時点(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() の関数定義を完成させ、これらの関数のパフォーマンスをベンチマークします。

指示1 / 2

undefined XP
    1
    2
  • x の最初の window 個の要素の合計を計算します。
  • other_totals を、initial_total に lasts から firsts を引いたものの累積和(cumsum())を加えたものとして計算します。
  • 出力ベクトルを、最初の合計を window で割ったものと、その他の合計を window で割ったもので完成させます。