Skip to content

Fitted Values and Forecasts

Ivan Svetunkov edited this page Jul 6, 2026 · 19 revisions

Fitted Values and Forecasts

This page documents methods for extracting fitted values and generating forecasts from smooth models.

predict()/forecast()

Generates point forecasts and optionally prediction intervals for h steps ahead.

In R, the standard method is forecast(), although predict() is also available, but with a limited functionality and focusing on the in-sample prediction.

In Python, use predict() method.

R Usage

model <- adam(AirPassengers, "MMM", lags=12)

# Out-of-sample prediction
pred <- forecast(model, h=12, interval="prediction")

# In-sample confidence intervals
pred <- predict(model, interval="confidence")

Python Usage

from smooth import ADAM

# Fit model
model = ADAM(model="ZZZ", lags=12)
model.fit(y)

# Basic point forecast (no intervals by default, matching R)
fc = model.predict(h=12)
fc.mean           # pd.Series of point forecasts
fc.lower          # None (no intervals requested)

# With prediction intervals
fc = model.predict(h=12, interval="prediction", level=0.95)
fc.mean           # pd.Series of point forecasts
fc.lower          # pd.DataFrame, columns=[0.025]
fc.upper          # pd.DataFrame, columns=[0.975]

# Approximate (parametric) intervals
fc = model.predict(h=12, interval="approximate", level=0.95)

# Simulation-based intervals
fc = model.predict(
    h=12, interval="simulated",
    level=0.95, nsim=1000
)

# Semiparametric: empirical multi-step variance + parametric distribution
fc = model.predict(h=12, interval="semiparametric", level=0.95)

# Empirical: direct quantiles of multi-step in-sample forecast errors
fc = model.predict(h=12, interval="empirical", level=0.95)

# Nonparametric: power-law quantile regression (Taylor & Bunn 1999) for h > 1
fc = model.predict(h=12, interval="nonparametric", level=0.95)

# Multiple confidence levels at once
fc = model.predict(h=12, interval="prediction", level=[0.8, 0.95, 0.99])
fc.lower          # pd.DataFrame, columns=[0.1, 0.025, 0.005]
fc.upper          # pd.DataFrame, columns=[0.9, 0.975, 0.995]

# One-sided intervals
fc = model.predict(h=12, interval="prediction", level=0.95, side="upper")
fc.lower          # None
fc.upper          # pd.DataFrame, columns=[0.975]

fc = model.predict(h=12, interval="prediction", level=0.95, side="lower")
fc.lower          # pd.DataFrame, columns=[0.025]
fc.upper          # None

# Convert to flat DataFrame (backward compatibility)
df = fc.to_dataframe()  # columns: "mean", "lower_0.025", "upper_0.975", ...

Parameters

Parameter Type (R) Type (Python) Default (R / Python) Description
object adam ADAM - Fitted model
h integer int 10 / required Forecast horizon
newdata / X matrix/data.frame NDArray NULL / None Exogenous variables for forecast period
occurrence numeric vector NDArray NULL / None Future occurrence probabilities (values in [0,1]) if known
interval character str "none" / "none" Interval type (see table below)
level numeric float or list 0.95 / 0.95 Confidence level(s); see Level parameter below
side character str "both" / "both" Interval side: "both", "upper", or "lower"; see Side parameter below
cumulative logical bool FALSE / False Produce cumulative forecasts (useful for inventory control)
nsim integer int NULL / 10000 Number of simulations for simulation-based intervals
scenarios logical bool FALSE / False Return simulated scenarios (only for interval="simulated")
... - - - Other parameters passed to underlying functions

Interval Types

Type Description Best For R Python
"none" No intervals Point forecasts only Yes Yes
"prediction" Analytical for additive, simulated for others General use (recommended) Yes Yes
"approximate" Analytical formulae for conditional variance Fast, additive models Yes Yes
"simulated" Monte Carlo simulation Multiplicative models Yes Yes
"semiparametric" Based on multi-step forecast errors and assumed distribution When residuals are not i.i.d. Yes Yes
"nonparametric" Quantile regression (Taylor & Bunn, 1999) Distribution-free Yes Yes
"empirical" Empirical quantiles of multi-step forecast errors Distribution and model free Yes Yes
"confidence" Confidence intervals for point forecast via reforecast() Uncertainty in the forecast line Yes Yes
"complete" Accounts for parameter uncertainty via reforecast() Full uncertainty quantification Yes Yes

"complete" and "confidence" dispatch to reforecast() in both languages — see Refitting-and-Reforecasting for the per-replicate kernel mechanics, the default nsim=100, and the ARIMA / xreg caveats on the Python side.

Note: "semiparametric", "nonparametric" and "empirical" use the rmultistep() method to extract multistep in-sample forecast errors. See more in Residuals-and-Errors.

Level parameter

The level parameter specifies the confidence level(s) for prediction intervals. It can be a single value or (in both R and Python) a vector/list of values for producing multiple interval bands simultaneously.

Values above 1 are treated as percentages and automatically divided by 100 (e.g. level=95 becomes level=0.95).

Single level (scalar):

Language Code Output
R forecast(model, h=12, level=0.95) $lower and $upper (single-column matrices)
Python model.predict(h=12, interval="prediction", level=0.95) fc.lower DataFrame with column 0.025, fc.upper with column 0.975

Multiple levels (vector/list):

Language Code Output
R forecast(model, h=12, level=c(0.8, 0.95, 0.99)) $lower and $upper (3-column matrices)
Python model.predict(h=12, interval="prediction", level=[0.8, 0.95, 0.99]) fc.lower DataFrame with columns [0.1, 0.025, 0.005], fc.upper with columns [0.9, 0.975, 0.995]

In Python, lower and upper are separate DataFrames whose column names are the quantile values (floats). For side="both" and level=X, the lower column is (1-X)/2 and the upper column is (1+X)/2.

Side parameter

The side parameter controls which bounds of the prediction interval are returned.

Value Description Python output (level=0.9)
"both" Both lower and upper bounds (default) fc.lower columns=[0.05], fc.upper columns=[0.95]
"upper" Upper bound only fc.lower is None, fc.upper columns=[0.9]
"lower" Lower bound only fc.lower columns=[0.1], fc.upper is None

When side="upper", the upper quantile equals the level directly (e.g. 90th percentile for level=0.9). When side="lower", the lower quantile equals 1 - level (e.g. 10th percentile for level=0.9). Both side options work with single or multiple levels.

Output

R: Returns an object of class "adam.forecast" / "smooth.forecast".

Python: predict() returns a ForecastResult object with structured access to forecasts and intervals. The result also supports DataFrame-style access (result["mean"], result.shape, result.columns) for backward compatibility.

Attribute Type (R) Type (Python) Description
mean numeric vector pd.Series Point forecasts (conditional mean)
lower matrix (h × n_levels) pd.DataFrame or None Lower prediction bounds; columns are quantile values. None when interval="none" or side="upper"
upper matrix (h × n_levels) pd.DataFrame or None Upper prediction bounds; columns are quantile values. None when interval="none" or side="lower"
level numeric float or list Confidence level(s) used
side character str Which side of intervals was requested
interval logical str Resolved interval type ("none", "approximate", "simulated", "semiparametric", "empirical", "nonparametric")
model adam object - The estimated model object (R only)
scenarios matrix (h × nsim) stored in model._general["_scenarios_matrix"] Simulated scenarios

Accessing interval columns (with multiple levels):

Language By name By position
R fc$upper[, "Upper bound (95%)"] fc$upper[, 1:2]
Python fc.upper[0.95] fc.upper.iloc[:, 0:1]
fc = model.predict(h=12, interval="prediction", level=[0.8, 0.95, 0.99])

# By quantile name (float)
fc.upper[0.975]          # 97.5th percentile (from level=0.95)
fc.lower[0.025]          # 2.5th percentile  (from level=0.95)

# By position (like R's [,1:2])
fc.upper.iloc[:, 0]      # first upper column
fc.upper.iloc[:, 0:2]    # first two upper columns
fc.lower.iloc[:, -1]     # last lower column

# List available quantiles
fc.upper.columns          # Float64Index([0.9, 0.975, 0.995])

Notes:

  • In R, access elements via $ (e.g., fc$mean, fc$lower)
  • In Python, access via attributes (e.g., fc.mean, fc.lower, fc.upper) or DataFrame-style (fc["mean"])
  • Use fc.to_dataframe() to convert to a flat pd.DataFrame with prefixed column names ("mean", "lower_0.025", "upper_0.975", ...)
  • In both R and Python, scenarios is only populated when interval="simulated" and scenarios=TRUE/True

fitted()

Extracts fitted (in-sample predicted) values from the model.

R Usage

model <- adam(AirPassengers, "MMM", lags=12)

# Get fitted values
fitted(model)

Python Usage

from smooth import ADAM

model = ADAM(model="MMM", lags=12)
model.fit(y)

# Get fitted values
fitted_values = model.fitted

Output

R: Returns a time series with fitted values for each in-sample observation.

Python: Returns an NDArray with fitted values for each in-sample observation.

actuals()

Extracts the actual (observed) values used in model estimation.

R Usage

model <- adam(AirPassengers, "MMM", lags=12, h=12, holdout=TRUE)

# Get actuals
y <- actuals(model)

Python Usage

from smooth import ADAM

model = ADAM(model="MMM", lags=12)
model.fit(y)

# Get actuals (the data used for fitting)
actuals = model.actuals

Output

R: Returns a time series with the actual in-sample observations.

Python: Returns an NDArray with the actual in-sample observations.

Holdout Validation

When h > 0 is supplied to the model constructor, point forecasts are produced automatically at the end of fit() — no separate call to predict() is needed. If holdout=True is also set, the last h observations are withheld from fitting and used for out-of-sample accuracy evaluation.

R Usage

model <- adam(y$x, model="ZXZ", lags=c(1, 12),
              initial="backcasting", h=18, holdout=TRUE)

# Accuracy measures are available directly on the model
print(model)   # shows "Forecast errors:" section automatically

Python Usage

from smooth import ADAM

model = ADAM(model="ZXZ", lags=[1, 12], initial="backcasting",
             h=18, holdout=True)
model.fit(y)

# Point forecasts produced automatically
model._auto_forecast.mean   # pd.Series of h-step-ahead forecasts

# Accuracy measures (only when holdout=True)
model.accuracy              # dict with ME, MAE, RMSE, sCE, ...

# Both appear automatically in print() and plot(which=7)
print(model)
model.plot(which=7)

Accuracy Measures

When holdout=True, the following metrics are stored in model.accuracy (Python) or printed automatically (R). All metrics compare the withheld h observations against the point forecasts.

Metric Description
ME Mean Error (bias)
MAE Mean Absolute Error
RMSE Root Mean Squared Error
sCE Scaled Cumulative Error: sum(errors) / mean(abs(y_train))
Asymmetry Asymmetry coefficient via half-moment (−1 = over-forecast, +1 = under-forecast)
sMAE MAE scaled by mean of in-sample actuals
sMSE MSE scaled by mean² of in-sample actuals
MASE MAE / mean(abs(diff(y_train))) — scaled by lag-1 naive error
RMSSE RMSE / sqrt(mean(diff(y_train)²))
rMAE MAE relative to naive (random-walk) benchmark
rRMSE RMSE relative to naive benchmark

Computed by greybox.point_measures.measures() (Python) / greybox::measures() (R), ensuring identical values across both implementations.

Output

print(model) appends a "Forecast errors:" block after the information criteria:

Information criteria:
     AIC     AICc      BIC     BICc
1808.303 1809.340 1827.578 1830.043

Forecast errors:
ME: -581.25; MAE: 604.23; RMSE: 710.74
sCE: -150%; Asymmetry: -95.4%; sMAE: 8.663%; sMSE: 1.038%
MASE: 0.265; RMSSE: 0.245; rMAE: 0.256; rRMSE: 0.216

plot(model, which=7) shows the point forecast as a blue line extending beyond the training period (red vertical separator).

References

  • Svetunkov, I. (2023). Forecasting and Analytics with the Augmented Dynamic Adaptive Model (ADAM). Chapman and Hall/CRC. Online: https://openforecast.org/adam/.

See Also

Clone this wiki locally