Promedio móvil en R

Por el equipo de promedio.net · Actualizado el

Sin instalar paquetes, el promedio móvil en R se calcula con stats::filter(x, rep(1/3, 3), sides = 1), que promedia cada valor con los dos anteriores. Con el paquete zoo, rollmean(x, k = 3, fill = NA, align = "right") es más legible, y con data.table, frollmean(x, 3) es el más rápido para series largas. En los tres casos, las primeras k − 1 posiciones quedan en NA porque aún no hay suficientes datos.

Sintaxis

# R base: escribe siempre stats:: por si dplyr está cargado
stats::filter(x, rep(1 / k, k), sides = 1)   # últimos k valores
stats::filter(x, rep(1 / k, k), sides = 2)   # centrado (opción por omisión)

# zoo
zoo::rollmean(x, k, fill = NA, align = "right")

# data.table
data.table::frollmean(x, k)                  # alineado a la derecha
AlineaciónCada valor promediaUso típico
Derecha (sides = 1, align = "right")El dato actual y los k − 1 anterioresSeguimiento, pronóstico, finanzas
Centrada (sides = 2, align = "center")Datos antes y después del actualSuavizar una gráfica histórica

Paso a paso

  1. Ordena la serie por fecha, de la más antigua a la más reciente.
  2. Elige el tamaño k de la ventana: 3 o 4 para suavizar poco, 12 para quitar la estacionalidad de datos mensuales.
  3. Decide la alineación: derecha si el promedio solo debe usar el pasado.
  4. Calcula con la función que prefieras y conviértelo a número con as.numeric() si usaste stats::filter, que devuelve una serie de tiempo (ts).
  5. Agrega el resultado como columna nueva y grafícalo junto con los datos originales.

Ejemplos resueltos

Ejemplo 1: ventas mensuales con R base

Ventas de ocho meses, en miles de pesos:

ventas <- c(48, 52, 50, 61, 58, 66, 70, 64)
movil <- stats::filter(ventas, rep(1 / 3, 3), sides = 1)
round(as.numeric(movil), 2)
[1]    NA    NA 50.00 54.33 56.33 61.67 64.67 66.67

El tercer mes promedia 48, 52 y 50 (150 / 3 = 50). El cuarto deja fuera el 48 y entra el 61: (52 + 50 + 61) / 3 = 54.33. El último valor, 66.67, muestra que la tendencia sigue subiendo aunque el octavo mes (64) haya bajado respecto del séptimo.

Ejemplo 2: zoo, con y sin relleno

library(zoo)
round(rollmean(ventas, k = 3, fill = NA, align = "right"), 2)
round(rollmean(ventas, k = 3), 2)
[1]    NA    NA 50.00 54.33 56.33 61.67 64.67 66.67
[1] 50.00 54.33 56.33 61.67 64.67 66.67

Con fill = NA, el resultado tiene el mismo largo que la serie y se puede pegar como columna. Sin fill, devuelve solo las 6 ventanas completas (8 − 3 + 1). Sin align, rollmean centra la ventana: el primer promedio quedaría en el segundo mes, no en el tercero.

Ejemplo 3: como columna de un data frame, por tienda

library(dplyr)

df <- data.frame(
  tienda = rep(c("A", "B"), each = 4),
  mes    = rep(1:4, times = 2),
  venta  = c(10, 12, 14, 16, 100, 90, 80, 70)
)
df |>
  group_by(tienda) |>
  arrange(mes, .by_group = TRUE) |>
  mutate(movil2 = zoo::rollmean(venta, k = 2, fill = NA, align = "right")) |>
  ungroup()

La columna movil2 queda en NA, 11, 13, 15 para la tienda A y en NA, 95, 85, 75 para la B. Sin group_by, el primer mes de la tienda B se promediaría con el último de la A (16 y 100) y daría 58, un número que no corresponde a ninguna tienda. arrange(..., .by_group = TRUE) garantiza el orden por mes dentro de cada tienda.

Errores comunes

Comprueba un cálculo corto con la calculadora de promedio móvil. Las variantes ponderada y exponencial, y su uso en finanzas, están en la sección de promedio móvil.

Fuentes

  1. R Core Team, documentación de filter (paquete stats). Argumentos filter, method y sides. Consultado el 11 de noviembre de 2026.
  2. zoo, rollmean. Argumentos k, fill y align. Consultado el 11 de noviembre de 2026.
  3. data.table, frollmean. Argumentos n, fill y align. Consultado el 11 de noviembre de 2026.