Para calcular un promedio móvil en Python con pandas, usa serie.rolling(n).mean(): cada valor del resultado es el promedio de los últimos n datos. Las primeras n − 1 posiciones quedan en NaN porque aún no hay suficientes datos; con min_periods=1 se calculan con los disponibles. Sin pandas, np.convolve(x, np.ones(n) / n, mode="valid") da el mismo resultado.
Sintaxis
serie.rolling(window=3).mean() # últimos 3 datos
serie.rolling(3, min_periods=1).mean() # sin NaN al inicio
serie.rolling(3, center=True).mean() # ventana centrada
serie.rolling("7D").mean() # últimos 7 días de calendario
serie.ewm(span=3, adjust=False).mean() # exponencial
import numpy as np
np.convolve(x, np.ones(3) / 3, mode="valid") # solo ventanas completas
Paso a paso
- Ordena los datos por fecha, de la más antigua a la más reciente.
rollingtoma los datos en el orden en que están. - Elige el tamaño de la ventana: 7 para datos diarios con ciclo semanal, 12 para mensuales con ciclo anual, 3 para suavizar poco.
- Calcula con
rolling(n).mean()y decide qué hacer con el inicio: dejarNaN, usarmin_periodso recortar. - Si faltan fechas, usa una ventana por tiempo (
"7D") en lugar de por cantidad de filas.
Ejemplos resueltos
Ejemplo 1: ventas diarias con ventana de 3 días
import pandas as pd
ventas = pd.Series([120, 135, 128, 150, 162, 158, 171],
index=pd.date_range("2026-03-01", periods=7, freq="D"))
print(ventas.rolling(3).mean())
2026-03-01 NaN
2026-03-02 NaN
2026-03-03 127.666667
2026-03-04 137.666667
2026-03-05 146.666667
2026-03-06 156.666667
2026-03-07 163.666667
Freq: D, dtype: float64
El 3 de marzo promedia 120, 135 y 128 (383 / 3 = 127.67); el 4 de marzo deja fuera el 120 y entra el 150. Con min_periods=1, el 1 de marzo valdría 120 y el 2, 127.5. Con center=True, cada valor promedia el día anterior, el mismo y el siguiente, útil para gráficas pero no para pronosticar, porque usa datos del futuro.
Ejemplo 2: fechas con huecos y ventana por tiempo
Si faltan días, una ventana de 3 filas mezcla datos de fechas lejanas. Una ventana de "3D" toma solo los días de calendario dentro del rango:
s = pd.Series([10, 20, 30, 40],
index=pd.to_datetime(["2026-01-01", "2026-01-02",
"2026-01-05", "2026-01-06"]))
print(s.rolling("3D").mean())
print(s.rolling(3).mean())
2026-01-01 10.0
2026-01-02 15.0
2026-01-05 30.0
2026-01-06 35.0
dtype: float64
2026-01-01 NaN
2026-01-02 NaN
2026-01-05 20.0
2026-01-06 30.0
dtype: float64
El 5 de enero, la ventana de 3 días (3, 4 y 5) solo contiene el 30, así que el promedio es 30. La ventana de 3 filas, en cambio, mezcla el 1, el 2 y el 5 de enero y da 20. Las ventanas por tiempo requieren un índice de fechas ordenado y por omisión aceptan ventanas incompletas.
Ejemplo 3: promedio móvil por tienda
Con varias series en la misma tabla, calcula la ventana dentro de cada grupo para no mezclar tiendas:
d = pd.DataFrame({"tienda": ["A"] * 4 + ["B"] * 4,
"venta": [10, 12, 14, 16, 100, 90, 80, 70]})
d["movil2"] = d.groupby("tienda")["venta"].transform(lambda s: s.rolling(2).mean())
print(d)
tienda venta movil2
0 A 10 NaN
1 A 12 11.0
2 A 14 13.0
3 A 16 15.0
4 B 100 NaN
5 B 90 95.0
6 B 80 85.0
7 B 70 75.0
Sin el groupby, la fila 4 promediaría 16 (tienda A) con 100 (tienda B) y daría 58, un valor sin sentido.
Sin pandas: NumPy y Python puro
import numpy as np
x = np.array([120, 135, 128, 150, 162, 158, 171])
print(np.convolve(x, np.ones(3) / 3, mode="valid"))
[127.66666667 137.66666667 146.66666667 156.66666667 163.66666667]
mode="valid" devuelve solo las ventanas completas: 7 datos con ventana de 3 dan 5 promedios. En Python puro: [sum(v[i - k + 1:i + 1]) / k for i in range(k - 1, len(v))].
Promedio móvil exponencial
ventas.ewm(span=3, adjust=False).mean() da más peso a los datos recientes. Con span=3 el factor de suavizado es α = 2 / (3 + 1) = 0.5: cada valor es la mitad del dato nuevo más la mitad del promedio anterior. Para la serie del ejemplo 1, el 3 de marzo vale 0.5 × 128 + 0.5 × 127.5 = 127.75. La diferencia con el simple y sus usos en finanzas se explican en la sección de promedio móvil.
Errores comunes
- Datos desordenados.
rollingno ordena: si las fechas vienen al revés, el promedio «de los últimos 3» toma los siguientes. Usasort_index()osort_values("fecha"). ValueError: window must be an integer 0 or greater. Pasaste una ventana como texto o negativa con un índice que no es de fechas. Las ventanas como"7D"exigen unDatetimeIndex(o el parámetroon=con una columna de fechas).- Esperar números desde la primera fila. Las primeras
n − 1filas sonNaNa propósito; no las rellenes con 0. - Usar
center=Trueen un pronóstico. Incluye datos posteriores a la fecha y adelanta artificialmente los cambios.
Para comprobar un cálculo pequeño sin código, usa la calculadora de promedio móvil.
Fuentes
- pandas, Series.rolling. window, min_periods, center, ventanas por tiempo. Consultado el 11 de noviembre de 2026.
- pandas, Series.ewm. span y adjust. Consultado el 11 de noviembre de 2026.