Save and Load

Use save and load when you want to persist a fitted PanelMMM and rebuild it later without redefining the whole model configuration in code.

Version 3.3.2 uses the model identity ammm PanelMMM and removes former identity aliases. Use the release that created an older fitted artefact to load it. New 3.3.2 runs require newly fitted models; changing stored labels or setting check=False is not a supported upgrade path. See the 3.3.2 upgrade guide.

Basic round trip

The standard workflow is:

mmm.fit(
    X,
    y,
    draws=500,
    tune=500,
    chains=2,
    progressbar=False,
    random_seed=42,
)

mmm.save("mmm.nc")

loaded = PanelMMM.load("mmm.nc")

save() writes the model’s InferenceData to NetCDF. load() reads that file, recreates the PanelMMM configuration from stored metadata, restores loaded.idata, and rebuilds the PyMC graph from the saved training data.

What ammm stores

ammm relies on more than the posterior draws for a full round trip.

Stored itemWhy it matters
posterior and other InferenceData groupsPreserve sampled results
fit_dataRebuild the model graph with the original training data
idata.attrsReconstruct PanelMMM init kwargs and validate compatibility

The stored attrs include both the shared model metadata and PanelMMM-specific configuration such as:

  • date_column
  • channel_columns
  • target_column
  • target_type
  • dims
  • control_columns
  • control_impacts
  • adstock and saturation
  • adstock_first
  • yearly_seasonality
  • time_varying_intercept and time_varying_media
  • scaling
  • model_config
  • sampler_config
  • serialised mu_effects

save() behaviour

save(fname, **kwargs) is a thin wrapper over self.idata.to_netcdf(...).

Important constraints:

  • the model must already be fitted
  • self.idata must contain a posterior group
  • any extra kwargs are passed directly to InferenceData.to_netcdf(...)

If you call save() before fitting, ammm raises:

RuntimeError: The model hasn't been fit yet, call .fit() first

load() and compatibility checks

By default, PanelMMM.load(...) validates that the saved file matches the current model class and configuration:

loaded = PanelMMM.load("mmm.nc", check=True)

With check=True, ammm verifies:

  • the saved model type (ammm PanelMMM for PanelMMM)
  • the saved model version
  • the saved model id derived from the serialised configuration

The model-type check runs before reconstructing the model. Version and ID checks run after reconstruction. If any of those checks fail, ammm raises DifferentModelError.

If you need to bypass those checks, you can set check=False:

loaded = PanelMMM.load("mmm.nc", check=False)

Use that only to investigate metadata mismatches within the supported current format. It does not restore support for artefacts from earlier releases.

Load from an in-memory InferenceData

If you already have an InferenceData object, use load_from_idata(...) instead of saving to disk first:

loaded = PanelMMM.load_from_idata(idata, check=True)

This is the same round-trip path that load() uses internally after reading the NetCDF file.

Where build_from_idata() fits

build_from_idata(idata) is the lower-level rebuild step. It:

  1. restores supported serialised mu_effects
  2. reads idata.fit_data
  3. splits that saved training data back into X and y
  4. rebuilds the PyMC graph

You usually do not need to call build_from_idata() yourself because load() and load_from_idata() already do it.

The rebuilt graph keeps the training-data record described in Fitting an existing graph again. Calling fit() on a loaded model is accepted when the supplied X and y equal the saved training data. Different data raise ValueError before sampling; create a new model instance to fit them.

Round-trip limitations

Not every fitted object can be restored fully.

Event payload requirements

Current EventAdditiveEffect serialisation stores the event DataFrame and the effect specification. PanelMMM.load(...) restores both. Older payloads that lack df_events or effect raise ValueError during restoration. Reconstruct those older models from their original inputs before saving them with the current format.

Do not drop fit_data if you want to reload

Because rebuild uses idata.fit_data, do not save a partial file that omits that group if you want to call PanelMMM.load(...) later.

Half-life adstock files retain h

For geometric or delayed half-life adstock, the posterior must retain the sampled {prefix}_halflife variable. ammm derives {prefix}_alpha when it rebuilds or evaluates the graph. A saved alpha alone cannot reconstruct a half-life model and loading, prediction, response curves, scenarios, or permitted optimisation will fail explicitly. Do not edit a saved posterior to replace h with an alpha diagnostic.

For example, this is valid NetCDF output:

mmm.save("posterior_only.nc", groups=["posterior"])

But it is not a full PanelMMM round-trip artefact, because the saved file no longer includes the training data needed for build_from_idata(...).

Practical advice

  • Use the default save() behaviour for round trips.
  • Keep check=True unless you have a specific compatibility reason not to.
  • Prefer PanelMMM.load(...) over loading NetCDF manually.
  • Retain the original event inputs when working with older saved payloads.

Next steps

After loading a model, you can go straight to posterior predictive sampling, diagnostics, decomposition, or optimisation using the restored idata and rebuilt graph.