Quantile model: retrain the winner on all rows by default (refit_full) - #180
Merged
Merged
Conversation
…s (the maintainer's pick) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, I075) ChimeraBoostQuantileRegressor gains refit_full=False. When True and the fit used the automatic early-stopping split (no user eval_set, early stopping on, conformalize "auto" or False), the winner is retrained on all rows after the audition finishes: an R/S/N winner's centre becomes the same ChimeraBoostRegressor fitted on all rows without an eval_set (its own carve, identical to the audition's, and its own replay refit); the head booster of an H/B/R winner is retrained from scratch at min(ceil(t_star / 0.8), n_estimators) rounds with the rate pinned. Calibration factors, offsets, residual quantiles and the spread model stay from the held-out fit. refit_ records what was retrained. Off by default: the identity snapshot is 186/186. quantile_suite.py passes each arm the original training rows (split.full) and adds the probe arms ChimeraBoostQuantileRefitCentre and ChimeraBoostQuantileRefitAll; quantile_synth.py passes the rows too. 11 new tests; 1235 passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sters the default Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
refit_full now defaults to True: called without an eval_set, the head makes every choice on its carved fold as before (stopping round, calibration, candidate), then retrains the winner on all rows, as ChimeraBoostRegressor does. The retrained centre gets the head's validation_fraction so its carve always equals the head's. The probe-only _refit_scope switch and its centre-only branch are removed. Nothing changes with a user eval_set, early stopping off or conformalize=True. Benchmark: ChimeraBoostQuantileRefitAll becomes ChimeraBoostQuantileAllRows (the default on split.full, no eval_set); ChimeraBoostQuantileRefitCentre is deleted; the field arm keeps its eval_set. Tests: 7 changed, 1 added, 1 deleted; 1235 passed. Identity snapshot 182/186 (mq3, mq3_w_sub predictions and importances; calibration factors unchanged). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bbstats
added a commit
that referenced
this pull request
Sep 26, 2026
Plan: #180 merged; the quantile queue holds (I076)
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.
The quantile model now learns from all of your training rows. Until now,
fit(X, y)without aneval_setheld back 20% of the rows to choose the stopping round, calibrate the intervals and pick its candidate, and those rows never reached the final model.ChimeraBoostRegressorhas always retrained on all rows at the end; the quantile model now does too.What changes for users
fit(X, y)fit(X, y, eval_set=...)conformalize=Trueorearly_stopping=Falserefit_fullTrueFalseskips it.refit_{"centre": bool, "head": bool, "rounds": int or None}, orNone.Kept from the held-out fit: the chosen candidate, the calibration factors, the fixed and scaled candidates' offsets,
best_iteration_andvalidation_history_. Only the models that make the prediction are retrained. The squared-error centre of the recentred, fixed and scaled candidates goes through the regressor's own retrain. The quantile trees of the head, bins and recentred candidates are refitted from scratch at 1.25 times the rounds early stopping kept, which is the regressor's rule.What it buys
On the 36 Grinsztajn regression datasets (3 seeds each), against today's default called the same way:
A cheaper version that retrains only the squared-error centre was measured in the same run: better on all 19 datasets it changed (median +1.7%) for 7% more time. The full retrain beat it head to head, 20 wins to 1, which was the rule set before the run.
Checks
eval_set, the new default reproduces the benchmark arm exactly on 8 of 8 fits covering the head, bins, recentred and scaled winners. With aneval_set, it reproduces today's numbers exactly.validation_fractionand every case where nothing may be retrained.eval_set; their calibration factors don't move. I'll rebaseline after the merge.docs/quantiles.md(a new "Retraining on all rows" section and a tuning note),docs/parameters.md(therefit_fullrow), CHANGELOG.chimeraboost/,tests/anddocs/, so it's yours to merge.For reviewers
ChimeraBoostRegressor(<the same arguments>, validation_fraction=<the head's>).fit(all rows). It carves exactly the rows the head carved (checked bit for bit), then retrains with its own default refit. That repeats the centre's 80% fit once; calling the regressor's refit directly would save a few percent of the fit.eval_set, so the docs' comparison table still has every model on the same rows and does not include this gain. The docs say so.split.full), and the probe armChimeraBoostQuantileAllRowsmeasures the default the way a user without aneval_setgets it.🤖 Generated with Claude Code