Media di una finestra scorrevole in R


19

Ho un vettore di valori che vorrei segnalare la media in Windows lungo una diapositiva più piccola.

Ad esempio, per un vettore dei seguenti valori:

4, 5, 7, 3, 9, 8

Una dimensione della finestra di 3 e una diapositiva di 2 farebbe quanto segue:

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

E restituisce un vettore di questi valori:

5.33, 6.33, 5.67

C'è una semplice funzione che farà questo per me? Se restituisse anche gli indici della finestra inizia, sarebbe un bonus in più. In questo esempio sarebbe 1,3,5



Puoi dare qualche idea su questa idea "slide"?
Shane,

@JM - Non l'ho fatto! Grazie! Sto per vedere come funziona.
T-Burns,

@Shane - Sì! Mi dispiace che non fosse chiaro. La diapositiva è il numero di posizioni / indici che sposti per iniziare a calcolare la finestra successiva delle medie. Quindi, piuttosto che la finestra successiva che inizia dopo la fine dell'ultima c'è una sovrapposizione quando la diapositiva è più piccola della dimensione della finestra. L'idea è di appianare un po 'i punti dati.
T-Burns,

Grazie, ho avuto la stessa domanda. Ora, ho trovato utile la funzione "rollapply".
angelico

Risposte:


24

La funzione rollapplynel pacchetto zoo ti avvicina:

> 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

Semplicemente non calcolerà l'ultimo valore per te in quanto non contiene 3 osservazioni. Forse questo sarà sufficiente per il tuo vero problema? Inoltre, si noti che l'oggetto restituito ha gli indici desiderati come namesdel vettore restituito.

Il tuo esempio sta supponendo che ci sia uno 0 non osservato nell'ultima finestra. Potrebbe essere più utile o realistico eseguire il pad con un NAper rappresentare le informazioni mancanti e dire meandi gestire i valori mancanti. In questo caso avremo (8 + 9) / 2 come valore finale a finestra.

> 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

A proposito, una volta ho scritto di un utilizzo di questa funzione per implementare la nozione di " loil
Tal Galili

Puoi aggiungere uno 0 alla fine di x ( x<-c(x,0)) per ottenere l'ultimo elemento di risposta.

1
@mbq; questo è un forte presupposto che l'osservazione sia 0. Ho riflettuto su questo punto e T-Burns sta facendo lo stesso presupposto (uno 0 non osservato). Preferirei forse usare Pad con NA e passare l' na.rm = TRUEargomento a mean. La risposta non sarà la stessa richiesta dall'OP, ma sembra più utile. Modificherò la mia risposta per includerla.
Ripristina Monica - G. Simpson,

@ucfagls Eppure questo è facile da cambiare e come hai detto questo presupposto è stato fatto dall'OP. D'altra parte, sarei ancora più restrittivo e rimuoverei l'ultima media.

Grazie! Soprattutto per aver notato l'ultimo valore come ipotesi zero, non lo avevo considerato. Mi interessa sicuramente quell'ultima finestra !!
T-Burns,

12

Rollapply funziona alla grande con un piccolo set di dati. Tuttavia, se stai lavorando con diversi milioni di righe (genomica) è piuttosto lento.

La seguente funzione è super veloce.

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


Molto utile. Ma attenzione, che window = 3 restituirà la media di 4 (!) Valori, a meno che non si aggiunga a -1(all'intervallo) e a +1(al ciclo).
BurninLeo,

5

Questa semplice riga di codice fa la cosa:

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

se xè il vettore in questione.


Questo non restituisce ciò che voleva il richiedente, ma 5.33 5.00 6.33. Tuttavia, sembra abbastanza interessante. Puoi spiegare la tua idea, perché non la capisco.
Henrik,

1
@Henric Uso questo trucco frequentemente, ma il codice di user1414 restituisce questo rotolo con la diapositiva 1, non 2, come previsto da OP. Guarda (c(0,0,x)+c(0,x,0)+c(x,0,0))/3per capire cosa intendo (e come funziona). La formula corretta sarebbe: (c(0,0,x)+c(0,x,0)+c(x,0,0))[1:(length(x)-3)*2+1]/3(dobbiamo tagliare 0-padding all'inizio e selezionare elementi pari quindi.

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

o

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

Funziona con matrici 2D? Ti piace come? Se la dimensione della finestra è 3 * 3 come esempio
Mona Jalal

è solo una direzione
RockScience

3

la risposta di shabbychef 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);
}

EDIT: gli indici che stai cercando sono solo idx1... questa funzione può essere facilmente modificata per restituirli anche, ma è quasi altrettanto veloce ricrearli con un'altra chiamata a seq(1,length(x),by=slide).


grazie per la traduzione. Ho pensato che sarebbe stato un esercizio facile e ho imparato un po 'di R da esso
shabbychef,

La mia risposta aggiornata è l'uso fromo::running_meandella versione bleeding edge del mio pacchetto fromo .
Shabbychef,

3

Posso farlo facilmente in Matlab e anatra mentre mi sottovaluti:

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

come effetto collaterale, idx1è l'indice dell'elemento nella somma. Sono sicuro che questo può essere facilmente tradotto in R. Il linguaggio first:skip:lastdi Matlab fornisce l'array first, first + skip, first + 2skip, ..., first + n skip, dove l'ultimo elemento dell'array non è maggiore di last.

modifica : avevo omesso la parte media (dividi per windowsize).


+1 Non tada, rv / windowsize ;-)

1
Questa casella di commento marg ... è troppo stretta per questo codice, quindi ho pubblicato una nuova risposta.

1
Grazie, ma MATLAB non è gratuito !!
T-Burns,

@ T-Burns: l'ottava è gratuita; anche R è abbastanza vicino a Matlab che questo codice può essere facilmente tradotto. In effetti, @mbq lo ha fatto ..
shabbychef,

1

Questo ti porterà i mezzi della finestra e l'indice del primo valore della finestra:

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

Si applicano varie avvertenze: non ho testato questo con nient'altro che i tuoi dati campione; Credo che l'aggiunta di frame di dati come questo possa diventare molto lenta se si hanno molti valori (perché copierà data.frame ogni volta); ecc. Ma produce ciò che hai chiesto.


Si prega di non effettuare il downgrade senza fornire un commento. Come posso sapere cosa c'è che non va?
Matt Parker,

Non sono stato io, ma questo è lento (ma non molto più lento di rollapply).

2
neanche io, ma come detto da te, la pre-allocazione dell'oggetto risultato ti aiuterà con il problema della velocità. Un trucco, se non lo sai, o è noioso / difficile da determinare, la dimensione dell'oggetto risultato che ti serve. Assegna qualcosa di ragionevole, forse pre-riempimento con NA. Quindi riempi con il tuo ciclo, ma aggiungi un segno di spunta che se ti stai avvicinando al limite dell'oggetto preallocato, alloca un altro grosso pezzo e continua a riempire.
Ripristina Monica - G. Simpson,

1
@mbq; La velocità dei risultati, sebbene importante, non è l'unica considerazione. Invece di dover reinventare il tempo e gestire tutti gli indici ecc. Nelle soluzioni personalizzate, quello lineare rollapplyè molto più facile da capire e afferrare l'intenzione di. Inoltre, rollapplyè probabile che abbia avuto molti più occhi che controllano il suo codice rispetto a qualcosa che potrei preparare un pomeriggio. Cavalli per i corsi.
Ripristina Monica - G. Simpson,

1
Cambiare [i:(i+2)]in [i:(i+win.size-1)]renderebbe il codice più generale, credo.
Jota,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.