ローリング平均(C++)
ベクトル化したローリング平均関数 rollmean3() は性能は良かったものの、可読性がとても低いものでした。このコードがローリング平均を計算していると判断するのは難しく、結果としてデバッグや保守が大変になります。
2 つ目のバージョン rollmean2() は遅い代わりに読みやすくなりました。これを C++ に翻訳できれば、読みやすさと高速性の両方を期待できます。
rollmean2() はワークスペース内で定義されています。どのように動くか思い出すために、定義を表示して確認してもかまいません。これから rollmean2() を C++ に翻訳し、rollmean4() として実装します。
この演習はコースの一部です
Rcpp で R コードを最適化する
演習の手順
resを、長さがnで、値はNumericVectorのget_na()メソッドで与えられるNumericVectorとして設定します。totalを、xの最初のwindow個の値として計算します。window - 1の位置での平均を、合計をウィンドウ幅で割って計算します。- 2 つ目のループでは、
xのi - 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
)
*/