Oznacza przesuwane okno w R.

19

Mam wektor wartości, które chciałbym zgłosić średnią w oknach wzdłuż mniejszego slajdu.

Na przykład dla wektora następujących wartości:

4, 5, 7, 3, 9, 8

Okno o rozmiarze 3 i slajd 2 wykonałyby następujące czynności:

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

I zwróć wektor tych wartości:

5.33, 6.33, 5.67

Czy istnieje prosta funkcja, która zrobi to za mnie? Jeśli zwróci również indeksy okna startowego, byłby to dodatkowy bonus. W tym przykładzie byłoby to 1,3,5

T-Burns
źródło
4
Widziałeś to ?
JM nie jest statystykiem
Czy możesz podać jakieś podstawy tego pomysłu na „slajd”?
Shane
@JM - Nie miałem! Dziękuję Ci! Zaraz zobaczę, jak to działa.
T-Burns,
@Shane - Tak! Przepraszam, że nie było jasne. Slajd to liczba pozycji / indeksów, które przesuwasz, aby rozpocząć obliczanie następnego okna średnich. Więc zamiast następnego okna rozpoczynającego się po zakończeniu ostatniego, zachodzi pewne nakładanie się, gdy slajd jest mniejszy niż rozmiar okna. Chodzi o to, aby nieco wygładzić punkty danych.
T-Burns,
Dzięki, miałem to samo pytanie. Teraz uznałem za przydatną funkcję „rollapply”.
anielski

Odpowiedzi:

24

Funkcja rollapplyw pakiecie zoo zbliża:

> 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

Po prostu nie obliczy dla ciebie ostatniej wartości, ponieważ nie zawiera 3 obserwacji. Może to wystarczy dla twojego prawdziwego problemu? Zwróć również uwagę, że zwracany obiekt ma indeksy, które chcesz jako nameszwróconego wektora.

Twój przykład zakłada, że ​​w ostatnim oknie jest nieobserwowane 0. Bardziej użyteczne lub realistyczne może być wypełnienie za pomocą przycisku, NAaby przedstawić brakujące informacje i nakazać meanobsługę brakujących wartości. W tym przypadku będziemy mieli (8 + 9) / 2 jako naszą ostateczną wartość okna.

> 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
Przywróć Monikę - G. Simpson
źródło
BTW, kiedyś napisałem o użyciu tej funkcji do wdrożenia pojęcia „less kwantylowy
Tal Galili
Możesz dodać 0 na końcu x ( x<-c(x,0)), aby uzyskać ostatni element odpowiedzi.
1
@mbq; to mocno zakłada, że ​​obserwacja wynosi 0. Zastanawiałem się nad tym punktem, a T-Burns przyjmuje to samo założenie (niezauważone 0). Wolałbym być może z NA i przekazać na.rm = TRUEargument mean. Odpowiedź nie będzie taka sama, jak wymagana przez PO, ale wydaje się bardziej przydatna. Zmodyfikuję swoją odpowiedź, aby to uwzględnić.
Przywróć Monikę - G. Simpson
@ucfagls Jednak łatwo to zmienić i, jak powiedziałeś, założenia tego dokonał OP. Z drugiej strony byłbym jeszcze bardziej restrykcyjny i usunąłbym ostatnią średnią.
Dzięki! Zwłaszcza biorąc pod uwagę, że ostatnia wartość jest zerowa, nie wziąłem tego pod uwagę. Zdecydowanie dbam o to ostatnie okno !!
T-Burns,
12

Rollapply działa świetnie z małym zestawem danych. Jeśli jednak pracujesz z kilkoma milionami wierszy (genomika), jest to dość powolne.

Następująca funkcja jest bardzo szybka.

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

rewolucjonista
źródło
Całkiem pomocny. Pamiętaj jednak, że okno = 3 zwróci średnią z 4 (!) Wartości, chyba że dodasz -1(do zakresu) i a +1(do pętli).
BurninLeo
5

Ta prosta linia kodu ma tę funkcję:

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

jeśli xjest to wektor.

użytkownik1414
źródło
To nie zwraca tego, czego chciał pytający, ale 5,33 5,00 6,33. Wygląda jednak dość interesująco. Czy możesz wyjaśnić swój pomysł, ponieważ go nie rozumiem.
Henrik
1
@Henric Często używam tej sztuczki, ale kod użytkownika 1414 zwraca tę rolkę ze slajdem 1, a nie 2, zgodnie z zamierzeniami OP. Sprawdź, (c(0,0,x)+c(0,x,0)+c(x,0,0))/3co mam na myśli (i jak to działa). Właściwą formułą byłoby: (c(0,0,x)+c(0,x,0)+c(x,0,0))[1:(length(x)-3)*2+1]/3(musimy wyciąć 0-padding na początku i wtedy wybrać parzyste elementy.
4
library(zoo)
x=c(4, 5, 7, 3, 9, 8)
rollmean(x,3)

lub

library(TTR)
x=c(4, 5, 7, 3, 9, 8)
SMA(x,3)
RockScience
źródło
Czy to działa w przypadku matryc 2D? Jak jak Jeśli rozmiar okna to 3 * 3 jako przykład
Mona Jalal
jest tylko jeden kierunek
RockScience
3

odpowiedź shabbychef w 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);
}

EDYCJA: Wskaźniki, których szukasz, są po prostu idx1... tę funkcję można łatwo zmodyfikować, aby je również zwrócić, ale odtworzenie ich przy użyciu innego wywołania jest prawie równie szybkie seq(1,length(x),by=slide).

Społeczność
źródło
dzięki za tłumaczenie. Uznałem, że będzie to łatwe ćwiczenie i nauczyłem się z niego trochę R
shabbychef
Moja zaktualizowana odpowiedź to użycie fromo::running_meannajnowszej wersji mojego pakietu fromo .
shabbychef
3

Mogę to łatwo zrobić w Matlabie i uchylić się, gdy głosujesz na mnie:

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

jako efekt uboczny idx1jest indeks elementu w sumie. Jestem pewien, że można to łatwo przetłumaczyć na R. Idiom first:skip:lastw Matlabie daje tablicę pierwszy, pierwszy + pomiń, pierwszy + 2skip, ..., pierwszy + n pomiń, gdzie ostatni element w tablicy nie jest większy niż last.

edycja : Pominąłem część uśredniającą (podziel przez windowsize).

shabbychef
źródło
+1 Not tada, rv / windowsize ;-)
1
To pole komentarza marg ... jest zbyt wąskie dla tego kodu, więc opublikowałem nową odpowiedź.
1
Dzięki, ale MATLAB nie jest darmowy !!
T-Burns,
@ T-Burns: oktawa jest jednak darmowa; także R jest na tyle blisko Matlaba, że ​​ten kod można łatwo przetłumaczyć. W rzeczywistości @mbq zrobił to ...
shabbychef
1

Spowoduje to wyświetlenie okna i indeksu pierwszej wartości okna:

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

Obowiązują różne zastrzeżenia: nie przetestowałem tego na niczym innym, jak na przykładowych danych; Uważam, że dołączanie do takich ramek danych może być bardzo wolne, jeśli masz wiele wartości (ponieważ spowoduje to skopiowanie data.frame za każdym razem); itd. Ale produkuje to, o co prosiłeś.

Matt Parker
źródło
Proszę nie głosować bez komentarza. Skąd mam wiedzieć, co jest nie tak?
Matt Parker,
To nie byłem ja, ale to jest powolne (ale niewiele wolniejsze niż rollapply).
2
ja też nie byłem, ale jak sam wspomniałem, wstępna alokacja obiektu wynikowego pomoże w problemie z prędkością. Jedna sztuczka, jeśli nie wiesz lub jest nudna / trudna do ustalenia, rozmiar potrzebnego obiektu wynikowego. Przydziel coś rozsądnego, być może wstępnie wypełniając NA. Następnie wypełnij swoją pętlę, ale dodaj zaznaczenie, że jeśli zbliżasz się do limitu wstępnie przydzielonego obiektu, przydziel kolejną dużą porcję i kontynuuj wypełnianie.
Przywróć Monikę - G. Simpson
1
@mbq; Szybkość wyników, choć ważna, nie jest jedynym czynnikiem. Zamiast na nowo wymyślać chwilę i obsługiwać wszystkie indeksy itp. W niestandardowych rozwiązaniach, jedno-liniowy, który rollapplyjest znacznie łatwiejszy do zrozumienia i zaspokajania intencji. Ponadto, rollapplyjest prawdopodobne, aby mieli o wiele więcej gałek ocznych sprawdzenie jego kodu niż coś mogę gotować jedno popołudnie. Konie na kursy.
Przywróć Monikę - G. Simpson
1
Myślę, że zmiana [i:(i+2)]na [i:(i+win.size-1)]uczyniłaby kod bardziej ogólnym.
Jota,