Skip to content

fix(placement): return distinct quantile locations on tied data - #119

Open
ChrisW09 wants to merge 1 commit into
fix/56-unique-interior-knotsfrom
fix/82-distinct-quantile-centers
Open

ChrisW09 wants to merge 1 commit into
fix/56-unique-interior-knotsfrom
fix/82-distinct-quantile-centers

Conversation

@ChrisW09

@ChrisW09 ChrisW09 commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #82.

With unsupervised "quantile" placement, which is the default for the standalone feature maps, the RBF, ReLU, sigmoid and tanh expansions repeated centers on tied features (zero-inflated, top-coded or discrete) and produced exactly duplicated output columns. On the issue's zero-inflated feature only 4 of 8 columns were distinct. This also applied through Preprocessor(numerical_method="rbf", target_aware=False, placement_strategy="quantile").

Root cause

QuantilePlacement._place returned the data quantiles verbatim: spanning_knots(x, n, "quantile") with endpoints, or quantile_knots(x, n) without them. On tied data many of these quantiles coincide, and nothing removed the duplicates.

Fix

QuantilePlacement._place (pretab/placement/unsupervised.py) now makes the locations distinct with pretab.core.knots.supplement_interior_knots, the helper that the PR for #56 (#101) adds for the spline knots:

  • With include_endpoints=True, the feature-map path, the minimum and maximum are kept once. The interior is made unique and strictly inside the range, then topped up to n_units - 2 with strictly interior quantile / uniform candidates.
  • With include_endpoints=False, the quantiles are made unique and strictly interior and topped up to n_units in the same way.
  • A zero-range feature has no interior, so it keeps its repeated location and the output width holds. With include_endpoints=True and n_units <= 2, the locations are the same as before.

Behaviour changes

  • Unsupervised "quantile" centers of the RBF, ReLU, sigmoid and tanh expansions move on tied data. They are now distinct, with the range endpoints kept once and the remaining centers strictly interior. On the issue's zero-inflated feature the centers change from [0.0, 0.0, 0.0, 0.0, 0.0, 1.77, 5.33, 35.36] to [0.0, 1.77, 5.05, 5.33, 15.16, 20.21, 30.31, 35.36]. Untied data and zero-range features give the same centers as before, and the golden regression baselines pass unchanged.
  • The public QuantilePlacement(include_endpoints=False) also returns unique, strictly interior locations on tied data.
  • The output width is unchanged.

Documentation

Tests

All tests are in tests/placement/test_placement.py.

Reproduction

Output of the script from #82 on this branch. The script is extended with the two further cases from the issue text, 5 equally likely levels and a top capped at about 30 %, for all four feature maps:

centers: [0.0, 1.77, 5.05, 5.33, 15.16, 20.21, 30.31, 35.36]
distinct output columns: 8 of 8
Preprocessor rbf: distinct output columns: 7 of 7
5 levels
  RBF: distinct output columns: 8 of 8
  ReLU: distinct output columns: 8 of 8
  Sigmoid: distinct output columns: 8 of 8
  Tanh: distinct output columns: 8 of 8
top 30% capped (capped share 0.32)
  RBF: distinct output columns: 8 of 8
  ReLU: distinct output columns: 8 of 8
  Sigmoid: distinct output columns: 8 of 8
  Tanh: distinct output columns: 8 of 8

On main the same script prints 4 of 8, 4 of 7, 5 of 8 for every map, and 6 of 8 for every map.

Checks

  • just test: 1478 passed, 59 skipped, 7 xfailed; coverage 93.55% (gate 90%).
  • Minimum dependencies (CI job: Python 3.10, numpy 1.24.4, pandas 2.0.3, scipy 1.10.1, scikit-learn 1.6.0): 1465 passed, 72 skipped, 7 xfailed; scripts/quickstart.py passes.
  • just docs: strict build succeeds.
  • just check: all pre-commit and pre-push hooks pass (ruff format, ruff lint, prettier, file hygiene, pyright with 0 errors).
  • Import direction between subpackages is unchanged.

Merge notes

This change was previously part of #86, which is closed in favour of one pull request per issue.

QuantilePlacement returned the data quantiles verbatim, so on
zero-inflated, top-coded or discrete features the RBF / ReLU / sigmoid /
tanh feature maps got repeated centers and exactly duplicated output
columns (4 of 8 distinct on a zero-inflated feature).

The locations are now made distinct with the supplement_interior_knots
helper the splines use: the endpoints (when included) are kept once and
the rest is topped up with strictly interior quantile / uniform
candidates. Untied data is unchanged, and a zero-range feature keeps its
repeated location so the width holds. The feature-map docstrings and the
placement guide describe the rule.

Fixes #82

This branch has not been deployed

No deployments
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