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

T-Burns
fonte
4
Você viu isso ?
JM não é estatístico
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
Restabelecer Monica - G. Simpson
fonte
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

revolucionário
fonte
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.

user1414
fonte
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)
RockScience
fonte
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).

Comunidade
fonte
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).

shabbychef
fonte
+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.

Matt Parker
fonte
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