Repository navigation
Conversation
CARTLocationSelector returned its split candidates in ascending location order, and the minimum-spacing filter keeps the first of two candidates that are closer than min_location_spacing. A weak split just below the dominant one therefore evicted it, and the importance-based trim then usually removed the weak neighbour as well, leaving no location where the target changes. Candidates are now ordered by weighted impurity decrease (as the LightGBM selector already does with gains), so the spacing filter keeps the stronger of two close splits, and the same ranking drives the over-max trim. The returned locations are still sorted by location. Fixes #70
This was referenced Oct 16, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #70.
CARTLocationSelectorcould drop the most informative split when a weak split lay just below it, so the defaultPreprocessor()(target-aware PLE) and every other CART-placed representation could lose the bin edge, center or knot where the target changes, on continuous, untied data.Root cause
CARTLocationSelectorreturned its split candidates in ascending location order (sorted(set(...))), andBaseLocationSelector._enforce_spacingkeeps the first of two candidates that are closer thanmin_location_spacing. A weak split just below the root split therefore evicted it, and the importance-based trim then usually removed the weak neighbour as well.Fix
CARTLocationSelector._split_importancemaps every in-range split threshold of the fitted tree to its weighted impurity decrease. It replaces_extract_split_pointsand_select_top_locations.CARTLocationSelector._ordered_candidatesreturns the candidates ranked by decreasing impurity decrease (ties by location,_rank), as the LightGBM selector already does with gains, so the spacing filter keeps the stronger of two close splits. The trimming context is now the importance map instead of the fitted tree.CARTLocationSelector._trim_over_maxuses the same ranking and returns the kept locations sorted.selectstill returns locations in ascending order.Behaviour changes
min_location_spacing(1% of the range by default): the more informative one now survives. On the issue's simulation (200 single-step datasets),PLETransformer(output_dim=7)now misses the root split in 0 of 200 datasets, down from 25.Documentation
CARTLocationSelectorclass docstring now says the impurity ranking decides both the spacing and the trim. The privateBaseLocationSelector._ordered_candidatesand_enforce_spacingdocstrings describe the importance-descending order both selectors produce and which of two close candidates is kept.docs/core_concepts/resolution_and_placement.mddescribes CART placement as "split points from a per-feature decision tree fit againsty", which still holds. The class docstring already promised that "the most informative splits are kept", and the code now does that.Tests
test_cart_spacing_keeps_the_dominant_split_over_a_weak_neighbour: on the issue's seed-34 dataset the root split of a depth-1 tree is among the 6 selected locations. Fails onmain, passes here.test_cart_keeps_the_root_split_of_a_single_step_target[0-9]: the root split survives on ten single-step datasets. Seeds 2 and 5 fail onmain, all ten pass here; the other eight pass on both and pin the sweep.test_cart_candidates_are_ordered_by_impurity_decrease:_ordered_candidatesreturns candidates in non-increasing impurity-decrease order. Fails onmain, passes here.Reproduction
Output of the script from #70 on this branch, followed by the simulation script from the issue (
LeakageWarnings omitted):Checks
just test: 1450 passed, 59 skipped, 7 xfailed; coverage 93.68% (gate 90%).scripts/quickstart.pypasses.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).Merge notes
main.pretab/core/selectors.py, but in other functions (_supplement, the fallbacks and the LightGBM split extraction; the LightGBM objective), and the code merges cleanly. All three append tests at the end oftests/core/test_location_selectors.py, so whichever lands later gets an append/append conflict there: keep both blocks. With all three branches combined this way, the full test suite passes (1478 passed, 59 skipped, 7 xfailed).CARTLocationSelector._ordered_candidates. Git merges the two without a conflict.This change was previously part of #75, which is closed in favour of one pull request per issue.