始める無料で始める

ローリング平均(C++)

ベクトル化したローリング平均関数 rollmean3() は性能は良かったものの、可読性がとても低いものでした。このコードがローリング平均を計算していると判断するのは難しく、結果としてデバッグや保守が大変になります。

2 つ目のバージョン rollmean2() は遅い代わりに読みやすくなりました。これを C++ に翻訳できれば、読みやすさと高速性の両方を期待できます。

rollmean2() はワークスペース内で定義されています。どのように動くか思い出すために、定義を表示して確認してもかまいません。これから rollmean2() を C++ に翻訳し、rollmean4() として実装します。

この演習はコースの一部です

Rcpp で R コードを最適化する

コースを見る

演習の手順

  • res を、長さが n で、値は NumericVectorget_na() メソッドで与えられる NumericVector として設定します。
  • total を、x の最初の window 個の値として計算します。
  • window - 1 の位置での平均を、合計をウィンドウ幅で割って計算します。
  • 2 つ目のループでは、xi - window 番目の要素を引き、i 番目の要素を足して、合計を更新します。

実践的なインタラクティブ演習

このサンプルコードを完成させて、この演習に挑戦してみましょう。

#include 
using namespace Rcpp;

// [[Rcpp::export]]
NumericVector rollmean4(NumericVector x, int window) {
  int n = x.size();
  
  // Set res as a NumericVector of NAs with length n
  NumericVector res(___, ___::___());
  
  // Sum the first window worth of values of x
  double total = 0.0;
  for(int i = 0; i < window; i++) {
    total += ___;
  }
  
  // Treat the first case seperately
  res[window - 1] = ___ / window;
  
  // Iteratively update the total and recalculate the mean 
  for(int i = window; i < n; i++) {
    // Remove the (i - window)th case, and add the ith case
    total += - ___ + ___;
    // Calculate the mean at the ith position
    res[i] = total / window;
  }
  
  return res;  
}

/*** R
   # Compare rollmean2, rollmean3 and rollmean4   
   set.seed(42)
   x <- rnorm(1e4)
   microbenchmark( 
    rollmean2(x, 4), 
    rollmean3(x, 4), 
    rollmean4(x, 4), 
    times = 5
   )   
*/
コードを編集して実行