magli (Modelo Aditivo Generalizado Lineal): Modern Pythonic Generalized Additive Models (GAMs) based on classical statistical literature. It supports both single-term smooths (GAM / LinGAM) and multi-term formula-based models (GAMCore) with automatic hyperparameter tuning.
Full documentation: https://dacts23.github.io/magli/
magli provides two complementary statistical engines under a unified API:
| Feature / Goal |
backend="wood" (Default) |
backend="eilers" |
|---|---|---|
| Smoothing parameter ( |
Continuous REML or GCV optimization (automatic during .fit(), no grid search needed) |
Discrete GCV grid search over candidate |
| Basis function suite | Thin plate (tp, ts), Cubic (cr, cs), Cyclic (cc), P-splines (ps, cp), B-splines (bs), Random effects (re) |
Uniform B-splines (bs) with linear extrapolation |
| Statistical summaries | Full summary tables with approximate F-tests and p-values (Wood 2013) | Basic statistics (EDF, GCV, deviance explained) |
| Shape constraints | Periodic boundaries via cyclic bases (cc, cp) |
Soft constraints: mono_inc, mono_dec, convex, concave, periodic
|
| Observation weights | Weighted penalized least-squares (weights=...) |
Weighted penalized least-squares (weights=...) |
- Use
woodfor general regression, automatic parameter tuning, hypothesis testing, and maximum flexibility in basis types (equivalent to R'smgcv). - Use
eilerswhen you have physical domain constraints (e.g. monotonicity or convexity) or want explicit B-spline grid sweeps.
- R's
mgcvparity in pure Python:magliimplements Simon Wood's continuous REML smoothing parameter selection, Wood 2013 approximate F-tests and p-values, thin plate splines, and cyclic cubic bases without requiring an R runtime or rpy2. - Shape constraints: Soft shape constraints (monotonic increasing, monotonic decreasing, convex, concave) via the Eilers-Marx B-spline engine.
- Fast and numerically stable: SVD data augmentation and cached QR with Cholesky factorization avoid squaring condition numbers.
- Interpretable machine learning: Every term produces clean component decomposition plots and Bayesian confidence intervals.
- Dual backend engines: choose between
wood(Wood 2011) andeilers(Eilers & Marx 1996) - Automatic hyperparameter tuning: continuous REML/GCV optimization or cached QR+Cholesky GCV grid search
- Rich basis suite: thin plate splines, cubic regression splines, cyclic cubic splines, P-splines, B-splines, random effects
- Tensor-product interactions: multidimensional smooths (
te) with Kronecker sum penalties - Shape constraints: monotonic increasing/decreasing, convex, concave, and periodic
- Observation weights: prior precision or frequency weights (
weights=...) infit()andgridsearch() - Uncertainty quantification: Bayesian posterior covariance and frequentist confidence/prediction intervals
- Summary tables: parametric coefficients, EDF, approximate F-statistics, and p-values (Wood 2013)
pip install magliOr install from source for development:
git clone https://github.com/dacts23/magli.git
cd magli
pip install -e .In the Wood engine, smoothing parameters are estimated continuously during fit via REML (no manual grid search required):
import numpy as np
from magli import GAM, GAMCore
np.random.seed(42)
x = np.linspace(0, 1, 200)
y = np.sin(2 * np.pi * x) + np.random.normal(0, 0.2, len(x))
# Single-term model with cubic regression splines
model = GAM(k=10, bs="cr", backend="wood")
model.fit(x, y)
print(model.summary())
y_pred = model.predict(x)
ci = model.confidence_intervals(x, width=0.95)Multi-term formula with tensor-product interactions and linear terms:
# Multi-term dataset: 2 interactive variables + 1 linear variable
X = np.random.uniform(0, 10, (200, 3))
y_multi = np.sin(X[:, 0]) + 0.5 * X[:, 1] + 1.2 * X[:, 2] + np.random.normal(0, 0.2, 200)
gam = GAMCore("te(0, 1, bs='cr', k=4) + l(2)", backend="wood")
gam.fit(X, y_multi)
print(gam.summary())The Eilers-Marx engine provides discrete GCV grid searches and shape constraints:
import numpy as np
from magli import GAM
# Reusing synthetic data x, y or generating new series
x = np.linspace(0, 1, 200)
y = np.sin(2 * np.pi * x) + np.random.normal(0, 0.2, len(x))
# Fast B-spline grid search over candidate lambda and spline counts
model = GAM(backend="eilers")
model.gridsearch(x, y)
y_pred = model.predict(x)
ci = model.confidence_intervals(x, width=0.95)
model.plot_decomposition(x, y)Enforcing soft shape constraints (e.g. monotonic increasing dose-response):
# Enforce monotonic increasing trend
mono_model = GAM(n_splines=12, constraint="mono_inc", backend="eilers")
mono_model.fit(x, y)Fitting with observation weights (e.g. inverse variance or down-weighted outliers):
# Weighted penalized least-squares
weighted_model = GAM(n_splines=12, backend="eilers")
weighted_model.fit(x, y, weights=w)GAMCore uses an intuitive additive formula specification:
| Term Syntax | Meaning | Example |
|---|---|---|
s(col, ...) |
Univariate smooth spline | s(0, k=10, bs='cr') or s(0, n_splines=12, constraint='mono_inc') |
te(c1, c2, ...) |
Multidimensional tensor product | te(0, 1, k=5, bs='cr') |
f(col, ...) |
Categorical factor | f(2, coding='dummy') or f(2, coding='one-hot') |
l(col, ...) |
Parametric linear effect | l(3) |
Note: Predictor variables are identified by 0-indexed column numbers in input arrays.
Full documentation, mathematical foundations, and end-to-end tutorials are available at:
- Quick Start: installation and basic workflows
- Mathematical Foundations: theory behind both engines:
- Shape Constraints: monotonic, convex, concave, and periodic splines
- Smoothing Optimization: continuous REML and discrete GCV grid search
- Examples & Case Studies: worked examples across diverse problems
- API Reference: full class and method documentation
- Changelog: release history and version notes
Step through the interactive Jupyter notebooks in examples/:
| Notebook | What it covers |
|---|---|
gam_tutorial.ipynb |
Hands-on GAM tour exploring underfitting vs. overfitting, EDF interpretation, 2-D tensor interactions, and shape constraints |
wood_backend_math_tutorial.ipynb |
The Wood backend from the inside, covering the basis zoo, S.scale and sum-to-zero absorption, continuous REML/GCV optimisation, Wood (2013) approximate F-tests, and an end-to-end workflow |
eilers_backend_math_tutorial.ipynb |
The Eilers-Marx backend from the inside, covering De Boor B-splines, difference penalties, the SVD data-augmentation solver, GCV grid search, shape constraints, and an end-to-end workflow |
Every formula in the two backend notebooks is followed by code that asserts it
numerically, and each closes with a pass/fail audit of its identities.
(Running notebooks requires the Jupyter stack via pip install -e .[notebooks].)
Or run any of the self-contained demo scripts:
python examples/01_basic_lingam.py
python examples/10_engineering_case_study.py
python examples/11_wood_backend.py
python examples/12_concrete_demo.py
python examples/13_eilers_vs_wood_comparison.py
python examples/14_wood_basis_decomposition_plots.py
python examples/15_eilers_basis_decomposition_plots.pyGNU General Public License v3.0 (GPL-3.0-or-later) © 2026 David Ávila Cortés.
See LICENSE for full terms and third-party attributions (Simon N. Wood / mgcv and Daniel Serven / pygam).