65. How to Forecast Sales with Time Series in Python (pandas and sklearn)
65.3 Naive Last-Value and Seasonal Naive Forecasts
Why. Before sklearn, show two honest baselines. If your fancy model loses to “last month” or “same month last year”, you are not done.
What.
- Naive last-value — next value = last observed value.
- Seasonal naive — next value = value from the same season last cycle (month − 12 for monthly data).
How.
Build both baselines
- Sort by time ascending.
- Split: older months = train, newest months = test.
- Naive: repeat
train.iloc[-1]for every test month. - Seasonal naive: for each test month, copy the value from 12 months earlier.
- Keep both for the scoreboard in 65.7.
Worked example A — Tiny naive (easiest).
import pandas as pd
tiny = pd.DataFrame({
"month": ["2026-05", "2026-06", "2026-07", "2026-08"],
"sales_inr": [510000, 495000, 502000, 540000],
})
print(tiny)
print("Naive forecast for 2026-09:", int(tiny["sales_inr"].iloc[-1]))
Output you should see.
month sales_inr
0 2026-05 510000
1 2026-06 495000
2 2026-07 502000
3 2026-08 540000
Naive forecast for 2026-09: 540000
What it means. September guess = August actual. Simple. Often surprisingly hard to beat on short horizons.
Worked example B — Mauli train/test naive + seasonal naive.
We hold out May–Oct 2026 (6 months). Train ends Apr 2026. Last train sales = ₹631,700.
import pandas as pd
import numpy as np
df = pd.read_csv("mauli_monthly_sales.csv", parse_dates=["month"]).sort_values("month")
train = df.iloc[:30]
test = df.iloc[30:]
naive = np.full(len(test), int(train["sales_inr"].iloc[-1]))
seasonal = [int(df["sales_inr"].iloc[30 + i - 12]) for i in range(len(test))]
out = pd.DataFrame({
"month": test["month"].dt.strftime("%Y-%m"),
"actual": test["sales_inr"].values,
"naive_pred": naive,
"seasonal_naive": seasonal,
})
print(out.to_string(index=False))
Output you should see.
month actual naive_pred seasonal_naive
2026-05 674800 631700 565000
2026-06 620700 631700 532500
2026-07 602500 631700 517600
2026-08 694700 631700 595200
2026-09 799900 631700 693500
2026-10 878700 631700 744300
What it means. Naive is a flat line. Seasonal naive follows last year’s shape but sits low when the trend has grown.
Worked example C — Logistics weekly boxes (Bhiwandi).
Dataset note: fictional RapidBox hub weekly shipments. 8 rows. Columns: week_start, boxes_shipped. Currency context: ops KPI (count), not money.
import pandas as pd
logi = pd.DataFrame({
"week_start": pd.date_range("2026-08-03", periods=8, freq="W-MON"),
"boxes_shipped": [5200, 5400, 5100, 5800, 6000, 5900, 6100, 6300],
})
print(logi)
print("Naive next week:", int(logi["boxes_shipped"].iloc[-1]))
Output you should see.
week_start boxes_shipped
0 2026-08-03 5200
...
7 2026-09-21 6300
Naive next week: 6300
Ravindra Bagale's Tip
Keep both baselines. In interviews, “I beat seasonal naive on MAPE” is a strong line.
Ravindra Bagale's Tip – मराठी
दोन्ही baselines सोडू नका. Interview मध्ये “I beat seasonal naive on MAPE” ही मजबूत line आहे.
Ravindra Bagale's Tip – हिंदी
दोनों baselines रखो। Interview में “I beat seasonal naive on MAPE” मजबूत लाइन है।