Puedes armar un pronóstico de ventas útil en Python con unas 40 líneas de código: cargas las ventas mensuales con pandas, apartas los últimos 12 meses como prueba, comparas una referencia sencilla de "el mismo mes del año pasado" con un modelo Holt-Winters de statsmodels y pronosticas los próximos seis meses. Este proyecto para principiantes recorre cada paso y explica cómo saber si el pronóstico es lo bastante bueno para usarlo.
Lo que necesitas antes de empezar
- Python 3 con
pandas,statsmodelsymatplotlibinstalados (pip install pandas statsmodels matplotlib). Un notebook de Jupyter es el lugar más cómodo para correrlo. - Un CSV con dos columnas:
month(una fecha como 2025-01-01) ysales(un número). Una fila por mes, sin huecos. - Al menos dos o tres años de historia. Los modelos estacionales necesitan ver cada mes varias veces para aprender el patrón. Con menos datos, quédate con métodos más simples.
Si tus datos están en transacciones diarias, agrúpalos primero por mes. En pandas eso es df.resample("MS", on="order_date")["amount"].sum(), o puedes hacerlo con una tabla dinámica en Excel y exportar el resultado.
Paso 1: Cargar y revisar los datos
import pandas as pd
df = pd.read_csv("monthly_sales.csv", parse_dates=["month"])
df = df.set_index("month").asfreq("MS") # MS = inicio de mes
print(df.shape)
print(df["sales"].isna().sum(), "meses faltantes")
print(df.tail())
asfreq("MS") le dice a pandas que los datos son mensuales. Si falta un mes en tu archivo, aparece como una fila vacía (NaN), y la línea siguiente la cuenta. Corrige los huecos antes de modelar: averigua por qué falta un mes en lugar de inventar un número.
Haz también un gráfico de la serie (df["sales"].plot()). Busca tres cosas: una tendencia general hacia arriba o hacia abajo, un patrón que se repite cada año y picos raros, como un pedido grande que no se repetirá. Esos picos pueden distorsionar el pronóstico, así que anótalos y decide con el negocio si conviene ajustarlos.
Paso 2: Separar los datos y crear una referencia
El hábito más importante en pronósticos es probar con datos que el modelo no ha visto. Escondemos los últimos 12 meses, pronosticamos usando solo los datos anteriores y comparamos con lo que realmente pasó.
test_months = 12
train = df.iloc[:-test_months]
test = df.iloc[-test_months:]
# Ingenuo estacional: "este mes se parecerá al mismo mes del año pasado"
naive_forecast = pd.Series(
train["sales"].iloc[-12:].to_numpy(), index=test.index
)
La referencia ingenua estacional simplemente repite los valores del año anterior. Parece demasiado simple, pero es una comparación justa: si un modelo más sofisticado no la supera, no vale la pena usarlo. El .to_numpy() quita las fechas viejas para que los valores se alineen con los meses de prueba.
Paso 3: Ajustar un modelo Holt-Winters y medir el error
Holt-Winters (también llamado suavizado exponencial triple) estima tres componentes: el nivel actual, la tendencia y el patrón estacional. Los meses recientes pesan más que los antiguos. Es una opción clásica para ventas mensuales con un patrón anual, y pertenece a la misma familia de métodos que usa la función PRONOSTICO.ETS (FORECAST.ETS) de Excel.
from statsmodels.tsa.holtwinters import ExponentialSmoothing
model = ExponentialSmoothing(
train["sales"],
trend="add",
seasonal="add",
seasonal_periods=12,
).fit()
hw_forecast = model.forecast(test_months)
def mape(actual, predicted):
return ((actual - predicted).abs() / actual).mean() * 100
print(f"Seasonal naive MAPE: {mape(test['sales'], naive_forecast):.1f}%")
print(f"Holt-Winters MAPE: {mape(test['sales'], hw_forecast):.1f}%")
El MAPE (error porcentual absoluto medio) es el tamaño promedio del error como porcentaje de las ventas reales. Mientras más bajo, mejor, y es fácil de explicarle a un gerente: "en promedio, el pronóstico falló por alrededor de X %". Tus resultados dependen totalmente de tus datos, así que no los compares con cifras de otros proyectos; compáralos con tu propia referencia.
| Parámetro | Usa "add" cuando… | Usa "mul" cuando… |
|---|---|---|
trend | Las ventas crecen más o menos la misma cantidad cada período | Las ventas crecen más o menos el mismo porcentaje (requiere valores positivos) |
seasonal | La variación estacional se mantiene del mismo tamaño | La variación estacional crece a medida que crecen las ventas (requiere valores positivos) |
Prueba ambas opciones y quédate con la que tenga menor error de prueba. También puedes usar trend=None si no hay una tendencia clara.
Paso 4: Pronosticar el futuro y compartirlo
Cuando estés conforme con los resultados de prueba, vuelve a ajustar el modelo con todos los datos (así aprende de los meses más recientes) y pronostica hacia adelante.
import matplotlib.pyplot as plt
final_model = ExponentialSmoothing(
df["sales"], trend="add", seasonal="add", seasonal_periods=12
).fit()
future = final_model.forecast(6)
ax = df["sales"].plot(label="Real", figsize=(10, 4))
future.plot(ax=ax, label="Pronóstico", linestyle="--")
ax.set_title("Ventas mensuales y pronóstico a 6 meses")
ax.legend()
plt.tight_layout()
plt.show()
future.round(2).rename("forecast").rename_axis("month").to_csv("sales_forecast.csv")
El CSV se puede abrir directo en Excel o Power BI, donde puedes mostrar lo real y lo pronosticado en el mismo gráfico de líneas. Presenta el pronóstico como una estimación para planear, no como una promesa, y actualízalo cada mes cuando lleguen los datos nuevos.
Errores comunes de principiante
- Probar con los datos de entrenamiento. Un modelo siempre se ve excelente con datos que ya conoce. Aparta siempre un período de prueba.
- Ignorar eventos únicos. Las promociones, los quiebres de inventario y las caídas del sistema hay que anotarlos, y a veces ajustarlos, antes de modelar.
- Pronosticar demasiado lejos. La incertidumbre crece con cada mes. De seis a doce meses es un horizonte razonable para este tipo de modelo.
- Saltarse la referencia. Sin un punto de comparación, no puedes saber si el modelo aporta valor.
Paso 5: Pronosticar cada categoría en un solo ciclo
Un pronóstico del total es un buen comienzo, pero la mayoría de los equipos planea por categoría, región o tienda. Cuando el método ya funciona con una serie, puedes repetirlo para cada grupo con un ciclo corto. Este ejemplo supone un archivo con tres columnas: month, category y sales, donde todas las categorías tienen la historia completa.
import pandas as pd
from statsmodels.tsa.holtwinters import ExponentialSmoothing
sales = pd.read_csv("sales_by_category.csv", parse_dates=["month"])
results = []
for category, group in sales.groupby("category"):
series = group.set_index("month")["sales"].asfreq("MS")
fit = ExponentialSmoothing(
series, trend="add", seasonal="add", seasonal_periods=12
).fit()
fc = fit.forecast(6).rename("forecast").rename_axis("month").reset_index()
fc["category"] = category
results.append(fc)
all_forecasts = pd.concat(results, ignore_index=True)
all_forecasts.to_csv("forecast_by_category.csv", index=False)
print(all_forecasts.head())
El resultado es una tabla larga con una fila por categoría y mes, justo la forma que prefieren Power BI y las tablas dinámicas de Excel. Antes de confiar en ella, repite la prueba del Paso 3 para cada categoría. Algunas se pronosticarán bien; otras, sobre todo las pequeñas o nuevas, quizás no superen la referencia ingenua estacional. Para esas es perfectamente válido usar la referencia o un promedio simple. Un proceso que combina métodos según la categoría, elegidos por su error de prueba, es más honesto que forzar un solo modelo para todo.
Pon atención a las categorías con muy pocas ventas o muchos meses en cero. El suavizado exponencial funciona mejor con series de nivel estable, así que la demanda intermitente suele necesitar otros métodos o un nivel de agregación mayor.
Próximos pasos
Corre este proyecto con tus propios datos de ventas y luego intenta pronosticar por región o por categoría de producto. Si Python es nuevo para ti, empieza con Python para análisis de datos y nuestro tutorial de pandas para usuarios de Excel. Para comparar con un método sin código, lee pronósticos en Excel con PRONOSTICO.ETS, y cuando quieras modelos más avanzados, mira machine learning básico para analistas BI.
Mira: lecciones en video

Preguntas frecuentes
¿Cuántos datos necesito para pronosticar ventas en Python?
Para un modelo mensual estacional como Holt-Winters, procura tener al menos dos o tres años completos. Con menos historia, es más seguro usar una tendencia simple o un promedio móvil.
¿Qué es un buen MAPE para un pronóstico de ventas?
No hay una cifra universal; depende de qué tan variables sean tus ventas. La prueba práctica es si tu modelo supera una referencia sencilla, como repetir los valores del año anterior.
¿Holt-Winters es lo mismo que PRONOSTICO.ETS de Excel?
Pertenecen a la misma familia de métodos de suavizado exponencial, así que los resultados suelen parecerse pero no son idénticos. Python te da más control sobre los parámetros y las pruebas.
¿Puedo usar este pronóstico en Power BI?
Sí. Exporta el pronóstico a CSV como se muestra, o corre el script con la integración de Python de Power BI, y combínalo con los datos reales en un gráfico de líneas.
Marca esta lección como completada para seguir tu progreso.