この質問に対する回答は投稿されていないので、この種の問題を解決するためのさらに良い方法があることを主張するために1つ挙げると思いました。これは、数千回も発生する可能性があります。より速く。(これが役に立たない場合は、私に知らせてください、しかし私はここで何もないよりはましだと思いました)
「移動平均」または「スライディングウィンドウ」を聞くと、FFT畳み込みがすぐに頭に浮かびます。これは、この種の問題を非常に効率的に処理できるためです。すべての「スライディング」は舞台裏で行われているので、これまでにない構文上の美しさもすべて備えていると思います。
(次のコードは、https://gist.github.com/1320175で1つのファイルで入手できます)
まず、いくつかのデータをシミュレートします(ここでは簡単にするために整数を使用していますが、もちろん必要ありません)。
require(plyr)
set.seed(12345)
n = 10
n.sum = 2
a = sample.int(10, n, replace=T)
df = data.frame(n=1:n, a)
> df
n a
1 1 8
2 2 9
3 3 8
4 4 9
5 5 5
6 6 2
7 7 4
8 8 6
9 9 8
10 10 10
ここで、n-a
すべてを一度に事前計算します。
n.minus.a = with(df, n - a)
次に、入力と畳み込まれたときに、データに対して合計(または平均化/平滑化/その他)を行うカーネルを定義します。 k
n.minus.a
k = rep(0, n)
k[1:n.sum] = 1
すべての設定が完了したら、を介して周波数領域でこの畳み込みを効率的に行う関数を定義できますfft()
。
myConv <- function(x, k){
Fx = fft(x)
Fk = fft(k)
Fxk = Fx * Fk
xk = fft(Fxk, inverse=T)
(Re(xk) / n)[-(1:(n.sum-1))]
}
これを実行するための構文は素晴らしく、単純です。
> myConv(n.minus.a, k)
[1] -14 -12 -10 -5 4 7 5 3 1
convolve()
これはすべて、Rのコンビニエンス関数を使用するときにも内部で発生します。
> convolve(n.minus.a, k)[1:(length(n.minus.a)-n.sum+1)]
[1] -14 -12 -10 -5 4 7 5 3 1
これを手動の方法と比較して、結果がすべて同等であることを示します。
> sliding(df, 2, function(df) with(df, data.frame(n = n[1], a = a[1], b = sum(n - a))))
n a b
1 1 8 -14
2 2 9 -12
3 3 8 -10
4 4 9 -5
5 5 5 4
6 6 2 7
7 7 4 5
8 8 6 3
9 9 8 1
最後に、n=10^4
これらすべてのメソッドを作成してテストし、速度を確認します。
> system.time(myConv(n.minus.a, k))
user system elapsed
0.002 0.000 0.002
> system.time(convolve(n.minus.a, k, type='circ')[1:(length(n.minus.a)-n.sum+1)])
user system elapsed
0.002 0.000 0.002
> system.time(sliding(df, 2, function(df) with(df, data.frame(n = n[1], a = a[1], b = sum(n - a)))))
user system elapsed
7.944 0.018 7.962
FFT法はほぼ瞬時に戻り、この大まかなタイミングでも、手動法よりもほぼ4000倍高速です。
もちろん、あらゆる種類のスライディング問題をこのパラダイムにハト穴を開けることができるわけではありませんが、このような数値問題sum()
(および加重平均など)を使用すると、完全に機能します。いずれにせよ、通常、少なくとも少しグーグルして、特定のプローブに対してトリックを実行するフィルターカーネルが利用可能かどうかを確認することは十分に価値があります。幸運を!