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ón | Cada valor promedia | Uso típico |
|---|---|---|
Derecha (sides = 1, align = "right") | El dato actual y los k − 1 anteriores | Seguimiento, pronóstico, finanzas |
Centrada (sides = 2, align = "center") | Datos antes y después del actual | Suavizar una gráfica histórica |
Paso a paso
- Ordena la serie por fecha, de la más antigua a la más reciente.
- Elige el tamaño
kde la ventana: 3 o 4 para suavizar poco, 12 para quitar la estacionalidad de datos mensuales. - Decide la alineación: derecha si el promedio solo debe usar el pasado.
- Calcula con la función que prefieras y conviértelo a número con
as.numeric()si usastestats::filter, que devuelve una serie de tiempo (ts). - 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
- Error al llamar
filter(...)con un vector. Si cargaste dplyr,filterya no es la función de promedios: dplyr la reemplaza por la suya, que filtra filas de un data frame. Escribe siemprestats::filter. - Olvidar
sides = 1.stats::filtercentra la ventana por omisión. El resultado no tieneNAal inicio sino al inicio y al final, y cada promedio usa un dato del futuro. - Pesos que no suman 1.
rep(1, 3)da la suma móvil, no el promedio. Usarep(1 / 3, 3). - Serie desordenada. Ninguna de estas funciones ordena por fecha. Ordena antes con
order()oarrange(). - Meses faltantes. Las ventanas cuentan posiciones, no fechas. Si falta un mes, completa la serie (por ejemplo con
tidyr::complete) antes de calcular.
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
- R Core Team, documentación de filter (paquete stats). Argumentos filter, method y sides. Consultado el 11 de noviembre de 2026.
- zoo, rollmean. Argumentos k, fill y align. Consultado el 11 de noviembre de 2026.
- data.table, frollmean. Argumentos n, fill y align. Consultado el 11 de noviembre de 2026.