Promedio móvil en Python

Por el equipo de promedio.net · Actualizado el

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

  1. Ordena los datos por fecha, de la más antigua a la más reciente. rolling toma los datos en el orden en que están.
  2. Elige el tamaño de la ventana: 7 para datos diarios con ciclo semanal, 12 para mensuales con ciclo anual, 3 para suavizar poco.
  3. Calcula con rolling(n).mean() y decide qué hacer con el inicio: dejar NaN, usar min_periods o recortar.
  4. 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

Para comprobar un cálculo pequeño sin código, usa la calculadora de promedio móvil.

Fuentes

  1. pandas, Series.rolling. window, min_periods, center, ventanas por tiempo. Consultado el 11 de noviembre de 2026.
  2. pandas, Series.ewm. span y adjust. Consultado el 11 de noviembre de 2026.