Mittelwert eines Schiebefensters in R

19

Ich habe einen Vektor von Werten, die ich den Durchschnitt in Fenstern entlang einer kleineren Folie angeben möchte.

Zum Beispiel für einen Vektor mit den folgenden Werten:

4, 5, 7, 3, 9, 8

Eine Fenstergröße von 3 und eine Folie von 2 würden Folgendes bewirken:

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

Und geben Sie einen Vektor dieser Werte zurück:

5.33, 6.33, 5.67

Gibt es eine einfache Funktion, die dies für mich erledigt? Wenn auch die Indizes des Fensters zurückgegeben werden, ist dies ein zusätzlicher Bonus. In diesem Beispiel wäre das 1,3,5

T-Burns
quelle
4
Kennen Sie schon das ?
JM ist kein Statistiker
Können Sie Hintergrundinformationen zu dieser "Folie" -Idee geben?
Shane
@JM - hatte ich nicht! Vielen Dank! Ich werde gleich sehen, wie es funktioniert.
T-Burns
@ Shane - Ja! Es tut mir leid, das war nicht klar. Die Folie gibt die Anzahl der Positionen / Indizes an, die Sie verschieben, um mit der Berechnung des nächsten Durchschnittsfensters zu beginnen. Anstelle des nächsten Fensters, das nach dem Ende des letzten Fensters beginnt, gibt es eine gewisse Überlappung, wenn die Folie kleiner als Ihre Fenstergröße ist. Die Idee ist, die Datenpunkte etwas zu glätten.
T-Burns
Danke, ich hatte die gleiche Frage. Nun fand ich es nützlich die Funktion "Rollapply".
Engel

Antworten:

24

Die Funktion rollapplyim Paket zoo bringt Sie näher:

> 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

Es wird einfach nicht der letzte Wert für Sie berechnet, da es keine 3 Beobachtungen enthält. Vielleicht reicht das für Ihr eigentliches Problem aus? Beachten Sie außerdem, dass das zurückgegebene Objekt die gewünschten Indizes namesfür den zurückgegebenen Vektor hat.

In Ihrem Beispiel wird davon ausgegangen, dass im letzten Fenster eine unbeobachtete 0 vorhanden ist. Es kann nützlicher oder realistischer sein, mit einem zu füllen NA, um die fehlenden Informationen darzustellen und zu sagen, meanwie mit fehlenden Werten umzugehen ist. In diesem Fall haben wir (8 + 9) / 2 als endgültigen Fensterwert.

> 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
Setzen Sie Monica - G. Simpson wieder ein
quelle
Übrigens habe ich einmal über die Verwendung dieser Funktion geschrieben, um den Begriff "Quantile Loess" zu implementieren: r-statistics.com/2010/04/…
Tal Galili
Sie können am Ende von x ( x<-c(x,0)) eine 0 einfügen , um das letzte Antwortelement zu erhalten.
1
@mbq; Das ist eine starke Annahme, dass die Beobachtung 0 ist. Ich habe über diesen Punkt nachgedacht, und T-Burns geht von derselben Annahme aus (eine unbeobachtete 0). Ich würde es vorziehen, vielleicht mit NA aufzufüllen und das na.rm = TRUEArgument an weiterzuleiten mean. Die Antwort stimmt nicht mit der des OP überein, scheint jedoch nützlicher zu sein. Ich werde meine Antwort bearbeiten, um dies einzuschließen.
Setzen Sie Monica - G. Simpson
@ucfagls Dies ist jedoch leicht zu ändern, und wie Sie sagten, wurde diese Annahme vom OP getroffen. Andererseits wäre ich noch restriktiver und würde den letzten Durchschnitt streichen.
Vielen Dank! Insbesondere, weil ich den letzten Wert als Null-Annahme notiert hatte, hatte ich das nicht berücksichtigt. Das letzte Fenster interessiert mich auf jeden Fall !!
T-Burns
12

Rollapply funktioniert hervorragend mit einem kleinen Datensatz. Wenn Sie jedoch mit mehreren Millionen Zeilen (Genomics) arbeiten, ist dies recht langsam.

Die folgende Funktion ist super schnell.

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

r_evolutionist
quelle
Sehr hilfreich. Beachten Sie jedoch, dass window = 3 den Durchschnitt von 4 (!) Werten zurückgibt, es sei denn, Sie fügen ein -1(zum Bereich) und ein +1(zur Schleife) hinzu.
BurninLeo
5

Diese einfache Codezeile macht das Ding:

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

Wenn xist der Vektor in Frage.

user1414
quelle
Dies gibt nicht das zurück, was der Fragesteller wollte, sondern 5,33 5,00 6,33. Es sieht jedoch ziemlich interessant aus. Kannst du deine Idee erklären, weil ich sie nicht verstehe?
Henrik
1
@Henric Ich benutze diesen Trick häufig, aber der Code von user1414 gibt diese Rolle mit Folie 1 und nicht mit 2 zurück, wie von OP beabsichtigt. Schauen Sie sich (c(0,0,x)+c(0,x,0)+c(x,0,0))/3an, was ich meine (und wie es funktioniert). Die richtige Formel wäre: (c(0,0,x)+c(0,x,0)+c(x,0,0))[1:(length(x)-3)*2+1]/3(wir müssen am Anfang 0-Padding ausschneiden und dann gerade Elemente auswählen.
4
library(zoo)
x=c(4, 5, 7, 3, 9, 8)
rollmean(x,3)

oder

library(TTR)
x=c(4, 5, 7, 3, 9, 8)
SMA(x,3)
RockScience
quelle
Funktioniert das für 2D-Matrizen? Wie? Wenn die Fenstergröße als Beispiel 3 * 3 ist
Mona Jalal
Es gibt nur eine Richtung
RockScience
3

shabbychefs antwort in R:

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);
}

BEARBEITEN: Die Indizes, nach denen Sie suchen, sind nur idx1... Diese Funktion kann leicht modifiziert werden, um sie auch zurückzugeben, aber es ist fast genauso schnell, sie mit einem anderen Aufruf von neu zu erstellen seq(1,length(x),by=slide).

Gemeinschaft
quelle
danke fürs übersetzen. Ich dachte, es wäre eine einfache Übung, und ich lernte etwas R daraus
Shabbychef
Meine aktualisierte Antwort stammt fromo::running_meanaus der neuesten Version meines Fromo-Pakets .
Shabbychef
3

Ich kann das leicht in Matlab und duck machen, während du mich abstimmst:

%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!

Als Nebeneffekt idx1ist der Index des Elements in der Summe. Ich bin sicher, dass dies leicht in R übersetzt werden kann. Die Redewendung first:skip:lastin Matlab gibt das Array first, first + skip, first + 2skip, ..., first + n skip an, wobei das letzte Element im Array nicht größer als ist last.

edit : Ich hatte den Mittelwertbildungsteil weggelassen (dividiere durch windowsize).

shabbychef
quelle
+1 Nicht tada, rv /
1
Dieses marg ... Kommentarfeld ist zu eng für diesen Code, daher habe ich eine neue Antwort gepostet.
1
Danke, aber MATLAB ist nicht kostenlos !!
T-Burns
@ T-Burns: Oktave ist jedoch frei; auch R ist Matlab nahe genug, dass dieser Code leicht übersetzt werden kann. Tatsächlich hat @mbq das getan ..
shabbychef
1

Damit erhalten Sie die Fenstermittel und den Index des ersten Wertes des Fensters:

#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
    }

Es gelten verschiedene Einschränkungen: Sie haben dies nur anhand Ihrer Beispieldaten getestet. Ich glaube, dass das Anhängen an Datenrahmen wie diesen sehr langsam werden kann, wenn Sie viele Werte haben (da der data.frame jedes Mal kopiert wird). usw. Aber es produziert, was Sie gefragt haben.

Matt Parker
quelle
Bitte stimmen Sie nicht ab, ohne einen Kommentar abzugeben. Woher soll ich wissen, was los ist?
Matt Parker
Ich war es nicht, aber das ist langsam (aber nicht viel langsamer als rollapply).
2
Ich war es auch nicht, aber wie von Ihnen selbst erwähnt, hilft die Vorbelegung des Ergebnisobjekts bei der Geschwindigkeitsproblematik. Ein Trick, wenn Sie nicht wissen, oder wenn es mühsam / schwierig ist, die Größe des gewünschten Ergebnisobjekts zu bestimmen. Ordnen Sie etwas Vernünftiges zu, vielleicht füllen Sie es vorher mit NA. Füllen Sie dann Ihre Schleife aus, aber fügen Sie eine Prüfung hinzu, die besagt, dass Sie, wenn Sie sich der Grenze des vorab zugewiesenen Objekts nähern, einen weiteren großen Block zuweisen und mit dem Füllen fortfahren.
Setzen Sie Monica - G. Simpson
1
@mbq; Die Geschwindigkeit der Ergebnisse ist zwar wichtig, aber nicht die einzige Überlegung. Anstatt die Zeitspanne neu zu erfinden und alle Indizes usw. in den benutzerdefinierten Lösungen zu behandeln, ist die rollapplyeinlineare Methode viel einfacher zu verstehen und die Absicht von zu begreifen. Auch rollapplyist wahrscheinlich viel mehr Augäpfel Überprüfung seinen Code als etwas zu haben , hatte ich an einem Nachmittag kochen könnte. Pferde für Kurse.
Setzen Sie Monica - G. Simpson
1
Das Ändern [i:(i+2)]von [i:(i+win.size-1)]würde den Code allgemeiner machen, denke ich.
Jota