Media de una ventana deslizante en R

19

Tengo un vector de valores que me gustaría informar el promedio en ventanas a lo largo de una diapositiva más pequeña.

Por ejemplo, para un vector de los siguientes valores:

4, 5, 7, 3, 9, 8

Un tamaño de ventana de 3 y una diapositiva de 2 harían lo siguiente:

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

Y devuelve un vector de estos valores:

5.33, 6.33, 5.67

¿Hay una función simple que haga esto por mí? Si también devuelve los índices de inicio de la ventana, eso sería una ventaja adicional. En este ejemplo eso sería 1,3,5

Quemaduras en T
fuente
44
¿Has visto esto ?
JM no es un estadístico
¿Puedes darnos algunos antecedentes sobre esta idea de "diapositiva"?
Shane
@JM - ¡No lo había hecho! ¡Gracias! Estoy a punto de ver cómo funciona.
T-Burns
@Shane - ¡Sí! Lo siento, eso no estaba claro. La diapositiva es el número de posiciones / índices que mueve para comenzar a calcular la siguiente ventana de promedios. Por lo tanto, en lugar de la siguiente ventana que comienza después del final de la última, hay una superposición cuando la diapositiva es más pequeña que el tamaño de la ventana. La idea es suavizar un poco los puntos de datos.
T-Burns
Gracias, tuve la misma pregunta. Ahora, me pareció útil la función "rollapply".
angelous

Respuestas:

24

La función rollapplyen el paquete zoo te acerca:

> 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

Simplemente no calculará el último valor para usted, ya que no contiene 3 observaciones. Tal vez esto será suficiente para su verdadero problema? Además, tenga en cuenta que el objeto devuelto tiene los índices que desea como del namesvector devuelto.

Su ejemplo es suponer que hay un 0 no observado en la última ventana. Puede ser más útil o realista rellenar con un NApara representar la información que falta y decirle meanque maneje los valores que faltan. En este caso tendremos (8 + 9) / 2 como nuestro valor final de ventana.

> 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
Restablece a Mónica - G. Simpson
fuente
Por cierto, una vez escribí sobre el uso de esta función para implementar la noción de " loil
Tal Galili
Puede agregar un 0 al final de x ( x<-c(x,0)) para obtener el último elemento de respuesta.
1
@mbq; eso supone una fuerte suposición de que la observación es 0. Yo había estado reflexionando sobre este punto y T-Burns está haciendo la misma suposición (un 0 no observado). Preferiría quizás rellenar con NA y pasar el na.rm = TRUEargumento a mean. La respuesta no será la misma que solicitó el OP, pero parece más útil. Editaré mi respuesta para incluir esto.
Restablecer Monica - G. Simpson
@ucfagls Sin embargo, esto es fácil de cambiar y, como dijiste, esta suposición fue hecha por el OP. Por otro lado, sería aún más restrictivo y eliminaría el último promedio.
¡Gracias! Especialmente por señalar el último valor como suposición cero, no lo había considerado. ¡Definitivamente me importa esa última ventana!
T-Burns
12

Rollapply funciona muy bien con un pequeño conjunto de datos. Sin embargo, si está trabajando con varios millones de filas (genómica), es bastante lento.

La siguiente función es súper 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

revolucionista
fuente
Bastante util. Pero tenga en cuenta que esa ventana = 3 devolverá el promedio de 4 (!) Valores, a menos que agregue a -1(al rango) y a +1(al bucle).
BurninLeo
5

Esta simple línea de código hace lo siguiente:

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

si xes el vector en cuestión.

usuario1414
fuente
Esto no devuelve lo que el autor de la pregunta quería, sino 5.33 5.00 6.33. Sin embargo, parece bastante interesante. ¿Puedes explicar tu idea, porque no la entiendo?
Henrik
1
@Henric Uso este truco con frecuencia, pero el código del usuario 1414 devuelve este rollo con la diapositiva 1, no con la 2, según lo previsto por OP. Echa un vistazo (c(0,0,x)+c(0,x,0)+c(x,0,0))/3para ver a qué me refiero (y cómo funciona). La fórmula adecuada sería: (c(0,0,x)+c(0,x,0)+c(x,0,0))[1:(length(x)-3)*2+1]/3(debemos cortar el relleno 0 al principio y luego seleccionar los elementos pares.
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)
RockScience
fuente
¿Funciona esto para matrices 2D? ¿Como que? Si el tamaño de la ventana es 3 * 3 como ejemplo
Mona Jalal
es solo una dirección
RockScience
3

La respuesta de shabbychef en 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);
}

EDITAR: los índices que está buscando son solo idx1... esta función se puede modificar fácilmente para devolverlos también, pero es casi igual de rápido recrearlos con otra llamada a seq(1,length(x),by=slide).

Comunidad
fuente
gracias por traducir Pensé que sería un ejercicio fácil, y aprendí algo de R de él
shabbychef
Mi respuesta actualizada es el uso fromo::running_meande la versión de última generación de mi paquete fromo .
shabbychef
3

Puedo hacer esto fácilmente en Matlab y agacharme mientras me bajas el voto:

%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 efecto secundario, idx1es el índice del elemento en la suma. Estoy seguro de que esto se puede traducir fácilmente a R. El idioma first:skip:lasten Matlab le da a la matriz first, first + skip, first + 2skip, ..., first + n skip, donde el último elemento de la matriz no es mayor que last.

editar : había omitido la parte de promedio (dividir por windowsize).

shabbychef
fuente
+1 Not tada, rv / windowsize ;-)
1
Este margen de comentario ... es demasiado estrecho para este código, así que publiqué una nueva respuesta.
1
¡Gracias, pero MATLAB no es gratis!
T-Burns
@ T-Burns: sin embargo, la octava es libre; también R está lo suficientemente cerca de Matlab para que este código pueda traducirse fácilmente. De hecho, @mbq hizo eso ..
shabbychef
1

Esto le dará los medios de la ventana y el índice del primer valor de la ventana:

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

Se aplican varias advertencias: no he probado esto con nada más que sus datos de muestra; Creo que agregar marcos de datos como este puede ser realmente lento si tiene muchos valores (porque copiará el marco de datos cada vez); etc. Pero produce lo que pediste.

Matt Parker
fuente
Por favor, no haga un voto negativo sin proporcionar un comentario. ¿Cómo se supone que sepa lo que está mal?
Matt Parker
No fui yo, pero esto es lento (pero no mucho más lento que rollapply).
2
tampoco fui yo, pero como mencionaste tú mismo, la preasignación del objeto de resultado ayudará con el problema de la velocidad. Un truco, si no sabe, o es tedioso / difícil de determinar, el tamaño del objeto resultante que necesita. Asigne algo razonable, tal vez llenando previamente con NA. Luego complete con su ciclo, pero agregue una marca de verificación que si se está acercando al límite del objeto preasignado, asigne otro gran fragmento y continúe llenando.
Restablece a Monica - G. Simpson el
1
@mbq; La velocidad de los resultados, aunque importante, no es la única consideración. En lugar de tener que reinventar el while y manejar todos los índices, etc. en las soluciones personalizadas, el lineal rollapplyes mucho más fácil de entender y entender la intención. Además, rollapplyes probable que haya tenido muchos más globos oculares revisando su código que algo que podría preparar una tarde. Caballos de carreras.
Restablecer Monica - G. Simpson
1
Cambiar [i:(i+2)]a [i:(i+win.size-1)]haría que el código sea más general, creo.
Jota