This release is a pre-release and may not be stable for production use.
pyLGM
General-purpose latent Gaussian models for Python — the model class behind INLA.
Deterministic Bayesian inference for structured data. No MCMC, no new dependencies.
Documentation · How it works · Comparison · Examples · Theory
What it does
Declare structure — groups, space, time, frequency, networks — and pyLGM returns a posterior for each component, not just a prediction. Fits run in seconds through Laplace approximations and INLA-style integration, and are deterministic: same data, same answer, no convergence diagnostics.
Partial pooling in one picture: noisy small-area rates (left, near zero) are pulled toward their neighbours, while well-observed areas keep their signal. Marker size is the expected count. From the disease-mapping example.
Install
pip install pylgm
pip install "pylgm[spark]" # optional: Spark data boundary
Requires Python ≥ 3.11.
30-second example
A Poisson model with a per-region random intercept, fit with the Laplace engine:
import pandas as pd
from pylgm import Fixed, IID, LGM, Poisson
frame = pd.DataFrame({
"region": ["north", "north", "north", "south", "south", "south"],
"time": [1, 2, 3, 1, 2, 3],
"x": [0.0, 0.5, 1.0, 0.0, 0.5, 1.0],
"count": [3, 5, 8, 2, 3, 5],
})
model = LGM(
response="count",
likelihood=Poisson(), # canonical log link
predictor=Fixed("1 + x") # fixed effects
+ IID("region", index="region", precision=2.0), # random intercept per region
panel=("region",),
time="time",
)
result = model.fit(frame, engine="laplace")
print("fitted_mean:", result.fitted_mean.round(3).tolist())
# fitted_mean: [3.254, 4.986, 8.15, 2.201, 3.373, 5.513]
The same model can be declared in YAML and loaded with pylgm.config.load_model.
Reproducing a published result
examples/columbus_spatial_econometrics
reproduces the reference result of spatial econometrics — Anselin (1988),
Table 12.1, 49 Columbus OH neighbourhoods:
| model | const | INC | HOVAL | ρ / λ |
|---|---|---|---|---|
| published OLS | 68.619 | −1.5973 | −0.2739 | — |
| OLS, recomputed | 68.619 | −1.5973 | −0.2739 | — |
| published ML spatial error | 60.279 | −0.9573 | −0.3046 | 0.5468 |
pyLGM SAR |
59.543 | −0.9057 | −0.3058 | 0.5946 |
OLS matching the published numbers exactly verifies the data and spec; the
SAR fit then lands next to the published ML spatial-error estimates, and
recovers the finding that ignoring spatial correlation overstates the income
effect by 1.76×.
A network that changes every year
examples/state_income_dynamic_network
fits 48 US states over 1997–2007 with one network per year, then knocks out
20% of the panel and restores it:
| method | RMSE ↓ (log income) |
|---|---|
DynamicSpatialPanel |
0.0246 |
| state mean | 0.1214 |
| year mean | 0.1484 |
~5× closer than the obvious baselines. The same example reports where it loses — a last-value forecast beats it on level forecasts, because the fitted γ ≈ 1 says log income is near a random walk.
Why not just use XGBoost?
Often you should — and the comparison page says so with measured numbers rather than adjectives. Both problems below are simulated, so the true surface is known and scored directly:
| Problem | pyLGM | XGBoost | GLM |
|---|---|---|---|
| 200 areas, 3 counts each, smooth spatial signal (RMSE ↓) | 0.135 | 0.371 | 0.429 |
| 4000 rows, nonlinear covariate interactions (RMSE ↓) | 2.839 | 0.293 | — |
pyLGM wins where the per-unit sample is thin but the units are related, and
returns 95% intervals that cover the truth 99% of the time. Gradient boosting
wins where the signal is interactions among covariates and you have the rows to
learn them. Reproduce both with
examples/method_comparison.
What's in the box
| Area | What you get | Docs |
|---|---|---|
| Likelihoods | Gaussian (exact), Poisson, Bernoulli, Binomial, negative-binomial, zero-inflated counts, Gamma, Beta, Weibull/exponential survival | likelihoods |
| Effects | Fixed, IID, RW1/RW2, AR1 (optionally group-wise), Seasonal, MIDAS, MIDASParametric, SpaceTime |
effects |
| Spatial | Besag (ICAR), ProperCAR, BYM2, weighted graphs |
spatial |
| Networks | directed SAR, dynamic DynamicSpatialPanel (SDPD) with forward forecasting |
spatial |
| Scale | sparse solver past the dense guard, with the full uncertainty surface | internals |
| Hyperparameters | Empirical Bayes (type-II ML), MAP-II with PC priors, bounds | empirical bayes |
| Integration | INLA grid quadrature, simplified/full-Laplace marginals, DIC/WAIC/CPO/PIT | INLA |
| Prediction | fit-row, out-of-sample predict, forecasting via NaN rows, and joint posterior draws via sample |
prediction |
| Aggregates | LinearObservation (noisy, optionally estimated sigma) and exact LinearConstraint data on the predictor grid, for temporal disaggregation and nowcasting |
linear observations |
| Constraints | arbitrary linear constraints A x = e (R-INLA extraconstr) |
effects |
| Data boundary | Pandas, or Spark / Databricks | spark |
Documentation
Full docs: https://ardea00.github.io/pylgm/
- How it works — one
fit()call end to end, then prediction and forecasting - Comparison — against regression, gradient boosting and MCMC, including where pyLGM loses
- Theory — the model class and every structured effect, with references
- Examples — 21 runnable scripts
Roadmap
What's shipped and what's next is on the roadmap; scope and compatibility policy on the internals page.
Contributing
Issues and pull requests welcome — see
docs/development.md for the test setup. main is
protected: PRs need the full CI matrix green before merge.
License
Release files for pylgm 0.7.0rc2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pylgm-0.7.0rc2.tar.gz | 1.1 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pylgm-0.7.0rc2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.3 MB
Release files / pylgm-0.7.0rc2.tar.gz
| Download URL | pylgm-0.7.0rc2.tar.gz |
|---|---|
| Size | 1.1 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dac5674b717a3b0910dec610911e05d9b090a8e4db29b963feb7788fe4168ff2
|
|
BLAKE2b-256 checksum How to use checksums |
3030e2e12fd75a8c52f9d611c76d46c8e6d9d48304077da4a35a73eb166df0ff
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency logRelease files / pylgm-0.7.0rc2-py3-none-any.whl
| Download URL | pylgm-0.7.0rc2-py3-none-any.whl |
|---|---|
| Size | 229.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6f0f5a43fb7b8107f9d52baff27179ec5a8d0b3d7c2709f55d1fff33989e44ee
|
|
BLAKE2b-256 checksum How to use checksums |
6eb9cde79d1a62dde8a6335572c3b4c0656f21068fd260a41902848d3126cd35
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency log