Skip to main content

Representation adequacy and transport-stability auditing in Python

Project description

updatesupport

PyPI Version

Audit whether the categories in your report are stable enough for the estimate you are reporting.

updatesupport quantifies hidden-composition ambiguity: how much an aggregate rate, effect, or risk metric could move if the public buckets in a report stayed fixed but the hidden mix inside those buckets changed.

It is useful when a dashboard, model-review pack, policy table, or causal analysis reports a number by coarse public categories and you need to know:

Are these categories enough to support this reported estimate?

Why It Exists

Many reports publish estimates by coarse buckets:

age band x education band x sex
product x region x FICO band x LTV band
segment x channel

Those buckets may hide subgroups with different target rates or effects. A confidence interval answers sampling uncertainty. A model metric answers model fit. updatesupport answers a different review question:

Holding the reported public mix fixed, how far could the aggregate move under plausible hidden subgroup shifts?

The output is a review-ready Markdown audit with:

  • observed estimate
  • hidden-composition stress interval
  • transport ambiguity, the interval width
  • public adequacy flag
  • public cells driving the ambiguity
  • refinement recommendations
  • sensitivity checks
  • public-representation frontier search for small stable reporting designs

This is not a replacement for causal identification, model validation, or sampling uncertainty. It is an audit layer for the reporting representation.

Quickstart

pip install updatesupport

or, in a uv project:

uv add updatesupport
import updatesupport as us

report = us.public_descent_report(
    rows_or_frame,
    public=["AGE_BAND", "EDU_BAND", "SEX"],
    hidden=["AGE_BAND", "EDU_BAND", "SEX", "OCC_MAJOR", "WKHP_BAND", "RAC1P"],
    target="income_over_threshold",
    weight="sample_weight",
    candidate_refinements=["OCC_MAJOR", "WKHP_BAND", "RAC1P"],
    min_cell_weight=25,
    q="saturated",
    title="Income-Threshold Representation Audit",
)

print(report.to_markdown())

The report asks:

If we only report by AGE_BAND x EDU_BAND x SEX, how much could the aggregate income-threshold rate move if occupation, work hours, and race composition changed inside those public cells?

The stress interval is not a confidence interval. It is a partial-identification / sensitivity interval for hidden composition.

A Concrete Result

In the Folktables ACSIncome demo, the observed target rate is 12.37%. When the public mix by age band, education band, and sex is held fixed, hidden subgroup composition can move the target rate from:

11.79% to 13.44%

The transport ambiguity is 1.65 percentage points. In plain English:

The coarse public categories almost determine the aggregate income-threshold rate in this sample, but not quite. Hidden occupational and household differences still matter.

See the full analyst interpretation in docs/folktables-acs-income-interpretation.md.

Main Workflows

1. Audit a Public Report

Use public_descent_report(...) when you already know the public buckets, hidden refinements, and target metric.

report = us.public_descent_report(
    rows_or_frame,
    public=["segment"],
    hidden=["segment", "region", "tenure_band"],
    target="outcome_rate",
    candidate_refinements=["region", "tenure_band"],
    q=us.q_bounded_shift(0.5),
)

2. Run Robustness Checks

Use sensitivity_report(...) when the conclusion should be checked across Q presets, sparse-cell thresholds, or alternate hidden-state definitions.

sensitivity = us.sensitivity_report(
    rows_or_frame,
    public=["AGE_BAND", "SEX"],
    hidden=["AGE_BAND", "SEX", "OCC_MAJOR", "WKHP_BAND"],
    target="income_over_threshold",
    min_cell_weights=[1, 10, 25],
    q_presets=["saturated", us.q_bounded_shift(0.5), "observed"],
)

See docs/transport-presets.md for guidance on Q presets and docs/representation-adequacy.md for interpretation rules.

3. Choose a Stable Public Segmentation

Use public_representation_frontier(...) when you want the smallest public bucket design that keeps ambiguity below a review threshold.

frontier = us.public_representation_frontier(
    rows_or_frame,
    base_public=["AGE_BAND", "EDU_BAND"],
    hidden=["AGE_BAND", "EDU_BAND", "SEX", "OCC_MAJOR", "WKHP_BAND"],
    target="income_over_threshold",
    candidate_refinements=["SEX", "OCC_MAJOR", "WKHP_BAND"],
    q_presets=["saturated", us.q_bounded_shift(0.5), "observed"],
    min_cell_weights=[1, 10, 25],
    ambiguity_limit=0.01,
    bucket_budget=40,
    search="beam",
)

explanation = frontier.explain_minimal_stable()
if explanation is not None:
    print(explanation.to_markdown())

The frontier compares public-cell count, added public columns, and ambiguity across the stress grid. See docs/public-representation-frontier.md.

4. Audit Causal or Uplift Reports

Use a causal inference library such as EconML, DoWhy, DoubleML, or CausalML to estimate effects first. Then pass row-level or subgroup-level effects into updatesupport.

suite = us.causal_reporting_stability(
    df,
    public=["AGE_BAND", "SEX"],
    hidden=["AGE_BAND", "SEX", "OCC_MAJOR", "WKHP_BAND", "RAC1P"],
    effect="tau_hat",
    weight="sample_weight",
    candidate_refinements=["OCC_MAJOR", "WKHP_BAND", "RAC1P"],
    q=us.q_bounded_shift(0.5),
    statistical_estimate=ate_hat,
    statistical_interval=(ci_low, ci_high),
    statistical_method="causal estimator bootstrap",
)

This keeps four things separate: causal estimate, statistical uncertainty, hidden-composition ambiguity, and public refinement recommendations.

See docs/causal-library-integration.md.

5. Financial Model-Risk Plugin

Financial model-risk use cases live in the separate plugin package:

pip install "updatesupport[finance]"
# or
uv add "updatesupport[finance]"

It adds finance-oriented metrics such as expected loss and default rate without cluttering the core package.

See packages/updatesupport-finance/README.md.

Install Extras

pip install "updatesupport[cvxpy]"      # TV, chi-square, KL, Wasserstein, custom CVXPY Q
pip install "updatesupport[examples]"   # Folktables, pandas, plotting examples
pip install "updatesupport[causal]"     # causal-effect examples
pip install "updatesupport[dowhy]"      # CausalRefutation conversion
pip install "updatesupport[finance]"    # financial model-risk plugin package

The same extras work with uv add:

uv add "updatesupport[cvxpy]"
uv add "updatesupport[examples]"
uv add "updatesupport[causal]"
uv add "updatesupport[dowhy]"
uv add "updatesupport[finance]"

The causal docs cover EconML, DoWhy, DoubleML, and CausalML handoffs.

For all examples and optional integrations:

pip install "updatesupport[examples,causal,dowhy,cvxpy,finance]"
# or
uv add "updatesupport[examples,causal,dowhy,cvxpy,finance]"

Examples

Run the no-download Folktables smoke demo from a source checkout:

uv run python examples/folktables_acs.py --synthetic

Run the real Folktables ACSIncome example:

uv run --extra examples python examples/folktables_acs.py \
  --task income \
  --states CA \
  --year 2018 \
  --sample 50000 \
  --min-cell-weight 25

Generate the benchmark gallery:

uv run --extra examples --extra causal python examples/benchmark_gallery.py

Run the finance plugin example:

uv run --package updatesupport-finance python \
  packages/updatesupport-finance/examples/model_risk_portfolio.py

See docs/benchmark-gallery.md for reproducible case studies.

Source Development

git clone https://github.com/nahuaque/updatesupport.git
cd updatesupport
uv sync --all-packages --group dev --extra cvxpy --extra examples
uv run pytest

Documentation

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

updatesupport-0.1.1.tar.gz (309.9 kB view details)

Uploaded Source

Built Distribution

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

updatesupport-0.1.1-py3-none-any.whl (66.1 kB view details)

Uploaded Python 3

File details

Details for the file updatesupport-0.1.1.tar.gz.

File metadata

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

File hashes

Hashes for updatesupport-0.1.1.tar.gz
Algorithm Hash digest
SHA256 9f59d741f50dc6502a7fde5604eb1aa00a4aa991fbda26f26a16eda5c2bc2831
MD5 6c9d674a24ab33d0514dadc68b901e56
BLAKE2b-256 be92fd5c203a03a62a5eef151c44a21ca355d6303febc82c9f40ec0a7f60ce62

See more details on using hashes here.

File details

Details for the file updatesupport-0.1.1-py3-none-any.whl.

File metadata

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

File hashes

Hashes for updatesupport-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 3292114faf6466b5ce2538023f76504bda8bd6f4b00b01300c05a99b7c0a7a01
MD5 7d08bf5e2f7c5b5bb3b0f48c1b0c6fdb
BLAKE2b-256 a8b736d3d892df6f5f84120cee95072bedcdeb9a07a8c4bc8620e01cad38c054

See more details on using hashes here.

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