Rのスライディングウィンドウの平均


19

小さいスライドに沿ってウィンドウの平均を報告したい値のベクトルがあります。

たとえば、次の値のベクトルの場合:

4, 5, 7, 3, 9, 8

ウィンドウサイズが3でスライドが2の場合、次のようになります。

(4+5+7)/3 = 5.33
(7+3+9)/3 = 6.33
(9+8)/3 = 5.67

そして、これらの値のベクトルを返します:

5.33, 6.33, 5.67

私のためにこれを行う簡単な関数はありますか?また、ウィンドウスタートのインデックスも返された場合は、ボーナスが追加されます。この例では、1,3,5


4
これを見たことがありますか?
JMは

この「スライド」アイデアの背景を教えてください。
シェーン

@JM-ありませんでした!ありがとうございました!私はそれがどのように機能するのか見ようとしています。
Tバーンズ

@シェーン-はい!すみません、はっきりしませんでした。スライドは、平均の次のウィンドウの計算を開始するために移動する位置/インデックスの数です。そのため、最後のウィンドウの終了後に開始する次のウィンドウではなく、スライドがウィンドウサイズよりも小さい場合、オーバーラップが発生します。アイデアは、データポイントを少し滑らかにすることです。
Tバーンズ

おかげで、同じ質問がありました。さて、「rollapply」機能が便利だとわかりました。
天使のような14

回答:


24

rollapplyパッケージzooの関数を使用すると、次のことができます。

> require(zoo)
> TS <- zoo(c(4, 5, 7, 3, 9, 8))
> rollapply(TS, width = 3, by = 2, FUN = mean, align = "left")
       1        3 
5.333333 6.333333

3つの観測値が含まれていないため、最後の値は計算されません。たぶんこれはあなたの本当の問題に十分でしょうか?また、返されたオブジェクトにはnames、返されたベクトルのインデックスとして必要なインデックスがあることに注意してください。

あなたの例では、最後のウィンドウに観測されていない0があると仮定しています。で埋めNAて欠損情報を表し、mean欠損値を処理するように指示する方が便利または現実的です。この場合、最終的なウィンドウ値として(8 + 9)/ 2になります。

> TS <- zoo(c(4, 5, 7, 3, 9, 8, NA))
> rollapply(TS, width = 3, by = 2, FUN = mean, na.rm = TRUE, align = "left")
       1        3        5 
5.333333 6.333333 8.500000

ところで、私はかつて、「クォン黄土」の概念を実装するために、この機能の使用方法について書いた:r-statistics.com/2010/04/...
タルGalili

x(x<-c(x,0))の最後に0を追加して、答えの最後の要素を取得できます。

1
@mbq; これは、観測値が0であるという強い仮定を立てています。この点を検討していたので、T-Burnsは同じ仮定を立てています(観測されていない0)。おそらくNAでパディングし、na.rm = TRUE引数をに渡すことを好みますmean。答えは、OPが要求したものと同じではありませんが、より便利なようです。これを含めるように回答を編集します。
モニカの復活-G.シンプソン

@ucfaglsしかし、これは簡単に変更でき、あなたが言ったように、この仮定はOPによってなされました。その一方で、私はさらに制限され、最後の平均を削除します。

ありがとう!特に、最後の値をゼロと仮定するために、私はそれを考慮していませんでした。私は間違いなくその最後のウィンドウを気にします!!
Tバーンズ

12

Rollapplyは、小さなデータセットでうまく機能します。ただし、数百万行(ゲノミクス)で作業している場合は非常に遅くなります。

次の機能は超高速です。

data <- c(runif(100000, min=0, max=.1),runif(100000, min=.05, max=.1),runif(10000, min=.05, max=1), runif(100000, min=0, max=.2))

slideFunct <- function(data, window, step){
  total <- length(data)
  spots <- seq(from=1, to=(total-window), by=step)
  result <- vector(length = length(spots))
  for(i in 1:length(spots)){
    result[i] <- mean(data[spots[i]:(spots[i]+window)])
  }
  return(result)
}

http://coleoguy.blogspot.com/2014/04/sliding-window-analysis.html


とても助かります。ただし、window = 3は、-1(範囲に)および+1(ループに)を追加しない限り、4(!)の平均値を返すことに注意してください。
BurninLeo

5

この単純なコード行は、次のことを行います。

((c(x,0,0) + c(0,x,0) + c(0,0,x))/3)[3:(length(x)-1)]

if xは問題のベクトルです。


これは、質問者が望んだものを返しませんが、5.33 5.00 6.33。ただし、非常に興味深いようです。あなたの考えを説明してもらえますか?
ヘンリック

1
@Henric私はこのトリックを頻繁に使用しますが、user1414のコードは、OPが意図したように、2ではなくスライド1でこのロールを返します。(c(0,0,x)+c(0,x,0)+c(x,0,0))/3私が何を意味するか(そしてそれがどのように機能するか)を確認してください。適切な式は次のようになります(c(0,0,x)+c(0,x,0)+c(x,0,0))[1:(length(x)-3)*2+1]/3(最初に0パディングをカットし、偶数要素を選択する必要があります。

4
library(zoo)
x=c(4, 5, 7, 3, 9, 8)
rollmean(x,3)

または

library(TTR)
x=c(4, 5, 7, 3, 9, 8)
SMA(x,3)

これは2Dマトリックスで機能しますか?どう?例としてウィンドウサイズが3 * 3の場合
モナジャラル

それは一方向のみである
RockScience

3

Rのshabbychefの答え

slideMean<-function(x,windowsize=3,slide=2){
 idx1<-seq(1,length(x),by=slide);
 idx1+windowsize->idx2;
 idx2[idx2>(length(x)+1)]<-length(x)+1;
 c(0,cumsum(x))->cx;
 return((cx[idx2]-cx[idx1])/windowsize);
}

編集:探しているインデックスはただidx1...この関数は簡単に変更してそれらを返すこともできますが、別のを呼び出して再作成するのもほぼ同じくらい高速seq(1,length(x),by=slide)です。


翻訳してくれてありがとう。私はそれが簡単な運動だと思い、
それから

私の更新された答えはfromo::running_meanfromoパッケージの最先端バージョンからの使用です。
みすぼらしいシェフ

3

Matlabでこれを簡単に行うことができます。

%given vector x, windowsize, slide 
idx1 = 1:slide:numel(x);
idx2 = min(numel(x) + 1,idx1 + windowsize);  %sic on +1 here and no -1;
cx = [0;cumsum(x(:))];  %pad out a zero, perform a cumulative sum;
rv = (cx(idx2) - cx(idx1)) / windowsize; %tada! the answer!

副作用としてidx1、合計の要素のインデックスです。これは簡単にRに変換できると確信していますfirst:skip:last。Matlab のイディオムは配列first、first + skip、first + 2skip、...、first + n skipを与えます。ここで、配列の最後の要素はを超えませんlast

編集:平均化部分を省略していました(除算windowsize)。


+1 not

1
このmarg ...コメントボックスはこのコードには狭すぎるため、新しい回答を投稿しました。

1
ありがとう、しかしMATLABは無料ではありません!!
Tバーンズ

@ T-Burns:ただし、オクターブは無料です。また、RはMatlabに十分近いため、このコードを簡単に変換できます。実際、@ mbqはそうしました。
shabbychef

1

これにより、ウィンドウの平均値とウィンドウの最初の値のインデックスが取得されます。

#The data
x <- c(4, 5, 7, 3, 9, 8)

#Set window size and slide
win.size <- 3
slide <- 2

#Set up the table of results
results <- data.frame(index = numeric(), win.mean = numeric())

#i indexes the first value of the window (the sill?)
i <- 1
#j indexes the row of the results to be added next
j <- 1
while(i < length(x)) {
    #This mean preserves the denominator of 3
    win.mean <- sum(x[i:(i+2)], na.rm = TRUE)/win.size
    #Insert the results
    results[j, ] <- c(i, win.mean)
    #Increment the indices for the next pass
    i <- i + slide
    j <- j + 1
    }

さまざまな警告が適用されます。これは、サンプルデータ以外ではテストされていません。多くの値がある場合は、このようなデータフレームへの追加が非常に遅くなる可能性があると思います(毎回data.frameをコピーするため)。など。しかし、それはあなたが求めたものを生み出します。


コメントを提供せずに、投票しないでください。何が間違っているのかを知るにはどうすればよいですか?
マットパーカー

それは私ではありませんでしたが、これは遅いです(しかし、それよりも遅くはありませんrollapply)。

2
私もそうではありませんでしたが、自分で述べたように、結果オブジェクトの事前割り当ては速度の問題に役立ちます。必要な結果オブジェクトのサイズがわからない場合、または決定するのが退屈で困難な場合は、1つのトリックが必要です。おそらくNAを事前に入力して、合理的なものを割り当てます。次に、ループを埋めますが、事前に割り当てられたオブジェクトの制限に近づいている場合、別の大きなチャンクを割り当てて、埋め続けることを確認するチェックを追加します。
モニカの復職-G.シンプソン

1
@mbq; 重要なことですが、結果の速度だけが考慮事項ではありません。whileを再発明し、カスタムソリューションのすべてのインデックスなどを処理する代わりに、one-linearのrollapply方が理解しやすく、意図を理解しやすくなっています。また、rollapplyある日の午後に調理するよりも多くの目玉でコードをチェックしていた可能性があります。コース用の馬。
モニカの復活-G.シンプソン

1
に変更[i:(i+2)]する[i:(i+win.size-1)]と、コードがより一般的になると思います。
ジョタ14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.