Skip to main content

FlagGAM: rule-basis generalized additive models for explainable tabular prediction (Zhao & Welsch, 2026; from-scratch implementation).

Project description

FlagGAM

Apache-2.0

Documentation & guidebook: https://wlazlod.github.io/flaggam/ (available once the repository is public).

FlagGAM is a method for building interpretable generalized additive models from tabular data. It works by first running a univariate screening pass — the Univariate Flagging Algorithm (Sheth et al., 2019) — that identifies threshold and category cuts where a feature's distribution shifts meaningfully relative to the outcome. Each surviving cut becomes a binary basis function ("flag"), and the flags together form a compact, human-readable rule basis.

A linear or logistic head is then fitted on top of the rule basis, producing a model whose predictions are sums of individually interpretable flag contributions. Because every flag corresponds to a concrete data condition (e.g., "age ≥ 55"), the resulting model supports exact rule extraction and feature-level attribution without approximation.

This package is a from-scratch Python implementation of FlagGAM (Zhao & Welsch, arXiv:2605.31189) and the Univariate Flagging Algorithm (Sheth et al., PLOS ONE 2019). It provides sklearn-compatible FlagGAMClassifier and FlagGAMRegressor estimators that integrate directly into standard scikit-learn pipelines.

Installation

# Editable install (development)
pip install -e .

# Or with uv
uv sync --extra dev

Quickstart

Rule discovery requires enough rows per tail (min_support). The example below uses 600 synthetic rows with a planted signal so that export_rules() returns non-trivial rules.

import numpy as np
import pandas as pd
from flaggam import FlagGAMClassifier

rng = np.random.default_rng(0)
n = 600
age = rng.normal(40, 10, n)
purpose = rng.choice(["car", "tv", "edu"], n)
logit = -1.5 + 2.0 * (age <= 30) + 1.5 * (purpose == "edu")
y = (rng.uniform(size=n) < 1 / (1 + np.exp(-logit))).astype(int)
X = pd.DataFrame({"age": age, "purpose": pd.Categorical(purpose)})

clf = FlagGAMClassifier(random_state=0).fit(X, y)

# Inspect the rule basis (5 rules on this seed)
rules = clf.export_rules()
print(rules[["feature", "rule", "weight"]])
#      feature             rule    weight
#          age   age <= 27.4074  1.589593
#          age   age >= 46.7581 -0.387614
#      purpose purpose == 'edu'  0.906901
#      purpose  purpose == 'tv' -0.418348
#      purpose purpose == 'car' -0.486362

# Attribution for a young 'edu' applicant
x_young = pd.DataFrame({"age": [22.0], "purpose": pd.Categorical(["edu"])})
explanation = clf.explain(x_young)
print(explanation)
#    row     feature             rule  value  contribution
#      0         age   age <= 27.4074    1.0      1.589593
#      0     purpose purpose == 'edu'    1.0      0.906901
#      0 <intercept>      <intercept>    1.0     -0.624096

Extensions (beyond the paper)

Three optional modules extend the paper's method; each is an original addition not present in Zhao & Welsch (2026) and lives in its own module.

PD calibration — diagnostics (reliability curve, Brier, ECE, calibration-in-the-large) and recalibration (platt, isotonic, base_rate) fitted on data disjoint from head fitting:

from flaggam import CalibratedFlagGAM, expected_calibration_error

cal = CalibratedFlagGAM(FlagGAMClassifier(random_state=0), method="platt", cv=5)
cal.fit(X, y)
pd_hat = cal.predict_proba(X)[:, 1]

Monotonicity constraints — regulators often require PD monotone in a feature. Because FlagGAM's numerical contributions are step/ramp bases, sign constraints give exact monotonicity:

clf_mono = FlagGAMClassifier(monotonic_constraints={"age": -1}).fit(X, y)  # PD non-increasing in age

Fairness / proxy audit — group metrics for a protected attribute and a rule-level audit that ranks bases by association with it:

from flaggam import ProxyAudit, group_metrics

A = X["purpose"].astype(str)  # protected attribute (illustrative)
metrics = group_metrics(y, clf.predict_proba(X)[:, 1], A)
report = ProxyAudit(clf).report(X, A)          # ranked candidate proxies
clean_clf, trade = ProxyAudit(clf).drop_proxies(X, y, A, threshold=0.3)

Benchmarks

Reproducing the paper's tables requires the benchmarks optional dependency group:

uv sync --extra benchmarks

Each runner produces one paper table as a tidy results CSV:

python -m benchmarks.run_classification   # Table 3 (classification AUROC)
python -m benchmarks.run_regression       # Table 4 (regression RMSE/R2)
python -m benchmarks.run_robustness       # Table 5 (missingness/noise robustness)
python -m benchmarks.run_ablation         # Table 7 (FlagGAM ablations)
python -m benchmarks.run_sensitivity      # Table 8 (hyperparameter sensitivity)

All runners default to --n-splits 1000, matching the paper, which takes hours per table. Pass --n-splits 25 for a quick pass while developing or sanity-checking a change.

Rows are always APPENDED to --out if it already exists (this supports chunked --seed-start resumption); delete the file first if you want a fresh run.

python -m benchmarks.render_tables benchmarks/results/classification.csv --table 3

render_tables.py compares a results CSV against the paper's reported values (Zhao & Welsch, arXiv:2605.31189, benchmarks/paper_targets.py) and flags deltas beyond tolerance. Results CSVs are written under benchmarks/results/ and are gitignored — they are run artifacts, not tracked outputs.

Citation

If you use this package in research, please cite the papers it implements:

FlagGAM method:

Zhao, Z. & Welsch, R. E. (2026).
FlagGAM: Rule-Basis Generalized Additive Models for Explainable Tabular Prediction.
arXiv:2605.31189.

Univariate Flagging Algorithm:

Sheth, M., Gerovitch, A., Welsch, R. E., Markuzon, N. (2019).
The Univariate Flagging Algorithm (UFA): An interpretable approach for predictive modeling.
PLOS ONE 14(10): e0223161.
https://doi.org/10.1371/journal.pone.0223161

A machine-readable citation file is available at CITATION.cff.

Development

uv sync --extra dev
uv run pytest -q
uv run ruff check .
uv run mypy
uv run mkdocs serve  # Preview documentation locally

Status

Feature-complete at 0.1.0: core estimators pass check_estimator with no exclusions; the benchmark suite reproduces the paper's protocol (a 25-split German Credit smoke run reproduces the paper's 0.775 AUROC to within 0.002 (gate tolerance ±0.02)); calibration, monotonicity, fairness, and visualization extensions are implemented and documented. See CHANGELOG.md.

License

Apache 2.0 — see LICENSE. See docs/LICENSING.md for notes on paper copyrights and dataset licences.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

flaggam-0.1.0.tar.gz (590.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

flaggam-0.1.0-py3-none-any.whl (39.1 kB view details)

Uploaded Python 3

File details

Details for the file flaggam-0.1.0.tar.gz.

File metadata

  • Download URL: flaggam-0.1.0.tar.gz
  • Upload date:
  • Size: 590.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for flaggam-0.1.0.tar.gz
Algorithm Hash digest
SHA256 96c84c8d4e73a1a90f38fe820d3819be32871c078d9b4ee143207b0e58d48179
MD5 0cdff02af410210ade1c1e9e9bf51419
BLAKE2b-256 782d5de7a128e6b9af45a809804e99a883c7411fe856962c272a238bedfa2330

See more details on using hashes here.

Provenance

The following attestation bundles were made for flaggam-0.1.0.tar.gz:

Publisher: publish.yml on wlazlod/flaggam

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file flaggam-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: flaggam-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 39.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for flaggam-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a736e7167e6ec0e9f2f21be3fc78332b0c7ada007e28156b6654f4d112391aa5
MD5 89d3b90470a84a8068cec1c979728f6d
BLAKE2b-256 4c4dd0632d8a2c96fd9054103e6d8389b3f585f1f19f1036be1d5918d7faa0b0

See more details on using hashes here.

Provenance

The following attestation bundles were made for flaggam-0.1.0-py3-none-any.whl:

Publisher: publish.yml on wlazlod/flaggam

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page