Skip to content

[FEATURE] Migrate statistical distribution expectations to the V1 API#11962

Draft
joshua-stauffer wants to merge 5 commits into
developfrom
m/migrate-stat-expectations-v1
Draft

[FEATURE] Migrate statistical distribution expectations to the V1 API#11962
joshua-stauffer wants to merge 5 commits into
developfrom
m/migrate-stat-expectations-v1

Conversation

@joshua-stauffer

Copy link
Copy Markdown
Collaborator

Summary

Four statistical distribution Expectations existed only as stubs that raised
NotImplementedError and were excluded from the public API (tagged "needs
migration to modular expectations api"). This PR completes their migration to the
modular Expectations API and exports them so they are usable and registered:

  • ExpectColumnChisquareTestPValueToBeGreaterThan
  • ExpectColumnBootstrappedKsTestPValueToBeGreaterThan
  • ExpectColumnParameterizedDistributionKsTestPValueToBeGreaterThan
  • ExpectColumnPairCramersPhiValueToBeLessThan

These are the same Expectations that #11764 proposed removing as dead code; they
are dead only because they were never migrated. Rather than delete them, this PR
implements them.

What changed

  • Chi-square (ExpectColumnChisquareTestPValueToBeGreaterThan): computes the
    goodness-of-fit p-value in _validate from column.value_counts and
    column_values.nonnull.count (same approach as the categorical branch of
    ExpectColumnKLDivergenceToBeLessThan). Success when the p-value exceeds p.
  • Parameterized-distribution KS
    (ExpectColumnParameterizedDistributionKsTestPValueToBeGreaterThan): wires up
    the existing column.parameterized_distribution_ks_test_p_value metric. Success
    when the KS p-value is at least p_value.
  • Bootstrapped KS (ExpectColumnBootstrappedKsTestPValueToBeGreaterThan):
    registers the existing (but previously unimported) column.bootstrapped_ks_test_p_value
    metric and fixes its value_keys so bootstrap_samples is actually passed
    through. Success when the bootstrapped statistic exceeds p.
  • Cramér's phi (ExpectColumnPairCramersPhiValueToBeLessThan): a batch-level
    measure of association between two columns. Builds the contingency table
    (binning numeric columns) and computes Cramér's V from the Chi-square statistic.
    Success when V is at most threshold.
  • SciPy compatibility fix: the parameterized-distribution KS metric called
    scipy.stats.kstest(column, distribution, args=...), which current SciPy no
    longer supports for parameterless CDFs (e.g. norm). It now freezes the
    requested distribution and tests against its .cdf, which is equivalent and
    works across SciPy versions.

Backends

The underlying computations (SciPy KS tests, bootstrapping, contingency-table
Cramér's V) are implemented for Pandas only, matching where these statistics were
historically available. Each Expectation declares Pandas as its only supported
data source. Extending to SQL/Spark would be follow-up work.

Tests & artifacts

  • Integration tests under tests/integration/data_sources_and_expectations/expectations/
    for each Expectation (success, failure, and suite-parameter cases), following the
    existing per-Expectation Pandas patterns. Because the bootstrapped-KS statistic is
    randomized, its tests assert on success/failure rather than the exact value.
  • Generated JSON schemas for each new Expectation (invoke schemas --sync) and added
    them to the supported-expectations list.

Verification performed

  • All four Expectations register and validate on a Pandas batch (pass and fail cases).
  • New integration tests pass (-m unit).
  • test_core_model_schemas.py passes (serializable, schemas updated, valid spec).
  • Lint/format clean (ruff check, ruff format).
  • Type-checking clean on the changed modules (local environment lacks some
    third-party stubs; CI mypy is authoritative).

…ions API

Implement and export four previously-stubbed statistical Expectations that
raised NotImplementedError and were excluded from the public API:

- ExpectColumnChisquareTestPValueToBeGreaterThan
- ExpectColumnBootstrappedKsTestPValueToBeGreaterThan
- ExpectColumnParameterizedDistributionKsTestPValueToBeGreaterThan
- ExpectColumnPairCramersPhiValueToBeLessThan

Chi-square computes its statistic in _validate from column value counts and
non-null count; the KS Expectations wire up their existing Pandas metric
providers (registering the bootstrapped-KS provider and fixing its value_keys);
Cramér's phi is a batch-level association measure over two columns computed from
the full frame. Also fixes the parameterized-distribution KS metric to freeze
the requested distribution and test against its CDF, which is required by
current SciPy. Each Expectation is Pandas-only, matching the backends its
underlying computation supports.

Adds integration tests under data_sources_and_expectations and generated JSON
schemas for each new Expectation.
@netlify

netlify Bot commented Jul 9, 2026

Copy link
Copy Markdown

Deploy Preview for niobium-lead-7998 canceled.

Name Link
🔨 Latest commit 026ced5
🔍 Latest deploy log https://app.netlify.com/projects/niobium-lead-7998/deploys/6a4feeac9d9cc500080a60b3

…-test timeout

The default 1000 bootstrap rounds pushed each validation to ~1.9s, exceeding the
2s per-test timeout in CI. Use 100 rounds, which keeps each test well under the
limit while the matching/skewed partitions still give a stable pass/fail.
Double-indexing to_json_dict()["result"]["observed_value"] is not type-safe
(the value is a union that includes list). Compare the whole result dict with
pytest.approx inside, matching the pattern used by the other expectation tests.
- Fix inverted precision in numeric interval binning: small bin widths
  (< ~0.01) rounded to duplicate interval labels and crashed
  Categorical.from_codes. Precision now grows as bin width shrinks.
- Detect all numeric dtypes (int32/float32, nullable Int64/Float64) via
  is_numeric_dtype instead of a hardcoded list that silently routed them
  to the categorical branch; keep booleans on the categorical branch.
- Introduce the "(missing)"/"(other)" sentinels without raising on
  already-categorical columns (cast to object first).
- Forward the bootstrapped-KS metric details verbatim so observed/expected
  partitions and CDFs reach the result.
- Document the inclusive boundary comparisons (<= / >=) that mirror legacy
  behavior for Cramér's phi and parameterized-distribution KS.
- Fix the self-contradictory Cramér's phi failing docstring example to use
  perfectly-associated data.
- Add integration tests: numeric binning (incl. small-magnitude), explicit
  bins/n_bins, nulls, category dtype, and chi-square tail_weight_holdout.
Chained subscripts into to_json_dict()["result"] return JSONValues (a
union) and fail mypy's __getitem__ overload check. Access result.result
(a plain dict) behind an is-not-None guard instead, matching the pattern
used elsewhere in the integration tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant