Ravindra BagaleCourses & study guides मराठी Track your progress

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

  1. Sort by time ascending.
  2. Split: older months = train, newest months = test.
  3. Naive: repeat train.iloc[-1] for every test month.
  4. Seasonal naive: for each test month, copy the value from 12 months earlier.
  5. 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.