Search⌘ K
AI Features

ARIMA: AR, I, and MA Components

Explore the ARIMA model's components—autoregression, integration, and moving average—and how they forecast monthly pharmacy flu-test demand. Learn to avoid time leakage by keeping test data unseen and use RMSE to compare ARIMA forecasts with naive baselines. Understand how model orders affect predictions and prepare for selecting optimal parameters using ACF, PACF, and information criteria.

Monthly pharmacy flu-test demand determines how many kits to stock before the next month begins. Stocking fewer kits than demand creates costly stockouts, while stocking too many ties up inventory. For the 36 monthly counts in this example, we forecast the months after the training window and score the forecasts on the final six months.

The current rule uses the last observed demand as every future forecast in the six-month test period. This naive forecast gives us a minimum comparison point. A model only earns its extra complexity when it improves on that rule for the held-out months.

The first 30 months form the training window. The final six months remain unseen until scoring. Using sales from those six future months to choose model settings or estimate model parameters would be time leakage, because the forecast would draw on information unavailable at its prediction date.

The following pipeline creates the monthly series, applies the last-value baseline, and reports root mean squared error (RMSE) on the six held-out months.

Python
import numpy as np
import pandas as pd
def rmse(y_true: pd.Series, y_pred: pd.Series) -> float:
errors = y_true - y_pred
return float(np.sqrt(np.mean(np.square(errors))))
def main() -> None:
# 36 monthly observations with an evenly spaced monthly DatetimeIndex
dates = pd.date_range(start="2021-01-01", periods=36, freq="MS")
demand_values = np.array(
[
120,
128,
133,
129,
125,
122,
118,
121,
127,
135,
142,
150,
148,
144,
139,
136,
132,
129,
126,
130,
137,
145,
152,
160,
158,
153,
147,
141,
136,
140,
146,
151,
155,
149,
143,
138,
],
dtype=float,
)
demand = pd.Series(demand_values, index=dates, name="flu_test_demand")
train = demand.iloc[:30]
test = demand.iloc[30:]
baseline_forecast_value = float(train.iloc[-1])
baseline_forecast = pd.Series(
baseline_forecast_value,
index=test.index,
name="naive_last_value_forecast",
)
baseline_rmse = rmse(test, baseline_forecast)
print(f"Naive forecast value (month 30 demand): {baseline_forecast_value:.1f}")
print(f"Baseline RMSE on 6-month test set: {baseline_rmse:.4f}")
if __name__ == "__main__":
main()
  • Lines 12 and 56: The demand is a single ordered pandas Series indexed by a monthly DatetimeIndex (freq="MS"), matching the course’s earlier “time order matters” setup for time-series splits.

  • Lines 58–66: The chronological split keeps the final six months fully held out (avoiding time leakage), and the naive baseline is a constant forecast equal to the last training value (month 30).

  • Lines 5–7 and 68: RMSE is computed directly from the six test-month errors as E[(y− ...