Média de uma janela deslizante em R


19

Eu tenho um vetor de valores que gostaria de relatar a média nas janelas ao longo de um slide menor.

Por exemplo, para um vetor dos seguintes valores:

4, 5, 7, 3, 9, 8

Um tamanho de janela de 3 e um slide de 2 faria o seguinte:

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

E retorne um vetor desses valores:

5.33, 6.33, 5.67

Existe uma função simples que fará isso por mim? Se também retornasse os índices da janela, isso seria um bônus adicional. Neste exemplo, isso seria 1,3,5



Você pode dar uma ideia dessa idéia de "slide"?
Shane

@JM - eu não tinha! Obrigado! Estou prestes a ver como isso funciona.
T-Burns #

@ Shane - Sim! Me desculpe, isso não estava claro. O slide é o número de posições / índices que você move para começar a calcular a próxima janela de médias. Portanto, em vez de iniciar a próxima janela após o final da última, há alguma sobreposição quando o slide é menor que o tamanho da janela. A idéia é suavizar um pouco os pontos de dados.
T-Burns,

Obrigado, eu tive a mesma pergunta. Agora, achei útil a função "rollapply".
angelical 6/08/14

Respostas:


24

A função rollapplyno pacote zoo aproxima você:

> 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

Ele simplesmente não computará o último valor para você, pois não contém 3 observações. Talvez isso seja suficiente para o seu problema real? Além disso, observe que o objeto retornado possui os índices desejados como o namesvetor retornado.

Seu exemplo está assumindo que há um 0 não observado na última janela. Pode ser mais útil ou realista preencher com um NApara representar as informações ausentes e dizer meanpara manipular os valores ausentes. Nesse caso, teremos (8 + 9) / 2 como nosso valor final de janela.

> 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

BTW, uma vez eu escrevi sobre o uso dessa função para implementar a noção de "quantile loess": r-statistics.com/2010/04/…
Tal Galili

Você pode adicionar um 0 no final de x ( x<-c(x,0)) para obter o último elemento de resposta.

1
@mbq; isso é uma forte suposição de que a observação é 0. Eu estava considerando esse ponto e T-Burns está fazendo a mesma suposição (um 0 não observado). Talvez eu prefira trabalhar com NA e passar a na.rm = TRUEdiscussão para mean. A resposta não será a mesma que o OP solicitou, mas parece mais útil. Vou editar minha resposta para incluir isso.
Reponha Monica - G. Simpson

@ucfagls No entanto, isso é fácil de mudar e, como você disse, essa suposição foi feita pelo OP. Por outro lado, eu seria ainda mais restritivo e removeria a última média.

Obrigado! Especialmente por observar o último valor como suposição zero, eu não tinha considerado isso. Eu definitivamente me preocupo com essa última janela !!
T-Burns

12

Rollapply funciona muito bem com um pequeno conjunto de dados. No entanto, se você estiver trabalhando com vários milhões de linhas (genômica), é bastante lento.

A seguinte função é super rápida.

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


Bastante útil. Mas lembre-se de que window = 3 retornará a média de 4 (!) Valores, a menos que você adicione a -1(ao intervalo) e a +1(ao loop).
BurninLeo 11/09

5

Esta simples linha de código faz o seguinte:

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

se xé o vetor em questão.


Isso não retorna o que o solicitante queria, mas 5.33 5.00 6.33. No entanto, parece bastante interessante. Você pode explicar sua ideia, porque eu não entendo.
Henrik

1
@Henric Eu uso esse truque frequentemente, mas o código do user1414 retorna esse rolo com o slide 1, e não 2, conforme pretendido pelo OP. Confira o (c(0,0,x)+c(0,x,0)+c(x,0,0))/3que quero dizer (e como isso funciona). A fórmula apropriada seria: (c(0,0,x)+c(0,x,0)+c(x,0,0))[1:(length(x)-3)*2+1]/3(devemos cortar o preenchimento de 0 no início e selecionar os elementos pares então.

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

ou

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

Isso funciona para matrizes 2D? Tipo, como? Se o tamanho da janela é de 3 * 3 como um exemplo
Mona Jalal

é apenas uma direção
RockScience 15/05

3

resposta de shabbychef em 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: Os índices que você está procurando são apenas idx1... essa função pode ser facilmente modificada para retorná-los também, mas é quase igualmente rápido recriá-los com outra chamada para seq(1,length(x),by=slide).


obrigado por traduzir. Achei que seria um exercício fácil, e eu aprendi algumas R partir dele
shabbychef

Minha resposta atualizada é o uso fromo::running_meanda versão mais recente do meu pacote fromo .
precisa

3

Eu posso fazer isso facilmente no Matlab e me esquivar enquanto você me rebate:

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

como efeito colateral, idx1é o índice do elemento na soma. Estou certo de que isso pode ser facilmente traduzido em R. O idioma first:skip:lastdo Matlab fornece ao array primeiro, primeiro + pula, primeiro + 2 pula, ..., primeiro + n pula, onde o último elemento da matriz não é maior que last.

editar : eu tinha omitido a parte da média (dividir por windowsize).


+1 Não tada, rv / WindowSize ;-)

1
Esta caixa de comentário marg ... é muito estreita para este código, por isso publiquei uma nova resposta.

1
Obrigado, mas o MATLAB não é gratuito !!
T-Burns,

@ T-Burns: oitava é livre, no entanto; também R está perto o suficiente do Matlab para que este código possa ser facilmente traduzido. Na verdade, @mbq fez isso ..
shabbychef

1

Isso fornecerá os meios da janela e o índice do primeiro valor da janela:

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

Várias advertências se aplicam: não testei isso contra nada além de dados de amostra; Acredito que anexar quadros de dados como esse pode ficar muito lento se você tiver muitos valores (porque ele copiará o data.frame toda vez); etc. Mas produz o que você pediu.


Por favor, não faça voto negativo sem fornecer um comentário. Como vou saber o que há de errado?
Matt Parker

Não fui eu, mas isso é lento (mas não muito mais lento que rollapply).

2
Também não fui eu, mas, como mencionado por você, a pré-alocação do objeto de resultado ajudará no problema de velocidade. Um truque, se você não souber, ou é tedioso / difícil de determinar, o tamanho do objeto de resultado que você precisa. Aloque algo razoável, talvez pré-preenchendo com NA. Em seguida, preencha com seu loop, mas inclua uma verificação de que, se estiver chegando ao limite do objeto pré-alocado, aloque outro grande pedaço e continue preenchendo.
Reinstate Monica - G. Simpson

1
@mbq; A velocidade dos resultados, embora importante, não é a única consideração. Em vez de ter que reinventar o tempo e manipular todos os índices etc. nas soluções personalizadas, o linear rollapplyé muito mais fácil de entender e cumprir a intenção. Além disso, rollapplyé provável que tenha havido muitos mais olhos verificando seu código do que algo que eu possa preparar uma tarde. Cavalos para cursos.
Reinstate Monica - G. Simpson

1
Mudar [i:(i+2)]para [i:(i+win.size-1)]tornaria o código mais geral, eu acho.
Jota
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.