Lift populace-fit's scikit-learn<1.9 pin via quantile-forest 1.4.2 (#318)#322
Merged
Merged
Conversation
) populace-fit capped scikit-learn below 1.9 because quantile-forest imported sklearn.tree._tree.DTYPE, which sklearn 1.9 removed (and sklearn 1.9 also changed the sample-weight signature of the forest bootstrap helpers). The cap made the package uninstallable alongside any sklearn>=1.9 consumer: installing populace-fit into such an environment downgraded scikit-learn 1.9 -> 1.8, breaking float-pinned reproduction tests built under 1.9 (hit in populace-dynamics). quantile-forest 1.4.2 (2026-06-21) tracks both sklearn-1.9 changes (zillow/quantile-forest#152 restores DTYPE via an np.float32 fallback, #153 fixes the sample-weight bootstrap). Requiring quantile-forest>=1.4.2 lets the sklearn<1.9 cap be dropped (>=1.5), so populace-fit installs and passes its suite under both sklearn 1.8 and 1.9 and can coexist in one environment with an sklearn-1.9 consumer. populace-fit is the only package that imports quantile_forest (verified across the repo). Its QRF forests do their own weighted bootstrap and call .fit() without sample_weight, and the sign gate is a native HistGradientBoostingClassifier, so nothing in this package touches the sklearn-1.9-changed forest bootstrap path directly. Test evidence (populace-fit suite, editable install of populace-frame + populace-fit, quantile-forest 1.4.2 in both): - scikit-learn 1.8.0: 76 passed - scikit-learn 1.9.0: 76 passed Also documents the coexistence guarantee in populace-fit's README. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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 #318.
Root cause
populace-fitpinnedscikit-learn>=1.5,<1.9becausequantile-forestimportedsklearn.tree._tree.DTYPE, a symbol scikit-learn 1.9 removed (sklearn 1.9 also changed the sample-weight signature of the forest bootstrap helpers_generate_sample_indices/_get_n_samples_bootstrap). The<1.9cap madepopulace-fituninstallable alongside anyscikit-learn>=1.9consumer: installing it editable into such an environment (the gate-1 baseline run in populace-dynamics) downgraded scikit-learn 1.9 → 1.8, which shifted C2ST classifier internals enough to break float-pinned noise-floor reproduction tests built under 1.9. The two packages could not coexist in one venv.Fix
Bump
quantile-forest>=1.3→>=1.4.2and drop the sklearn cap (>=1.5,<1.9→>=1.5).Why 1.4.2 is the right target (upstream, evidence-checked):
quantile-forestPR zillow/quantile-forest#152 ("Support scikit-learn 1.9 (DTYPE removed from sklearn.tree._tree)") restoresDTYPEvia atry/exceptfallback tonp.float32(its value on every sklearn version). Merged 2026-06-10.sample_weightbootstrap signature change. Merged after Use 2024 SOI filing-season EITC totals #152.v1.4.1...v1.4.2contains both Use 2024 SOI filing-season EITC totals #152 and Add UK bus-spending imputation plan and DfT calibration targets #153. It is therefore the first release compatible with sklearn 1.9. (1.4.1, the version the lockfile previously resolved, predates both.)quantile-forestitself never pinned an upper bound on scikit-learn — the<1.9cap was purelypopulace-fit's defensive pin, so lifting it is safe once the floor guarantees a compatiblequantile-forest.Why no upper bound on sklearn:
populace-fitis the only package in the repo that importsquantile_forest(verified: onlypackages/populace-fit/pyproject.toml,src/populace/fit/qrf.py,tests/test_qrf.pyreference it). Its own sklearn usage is version-stable — the QRF forests run their own weighted bootstrap and call.fit()withoutsample_weight(so they don't hit the sklearn-1.9-changed bootstrap path directly), and the sign gate is a nativeHistGradientBoostingClassifier. The evidence below confirms the suite is green on both 1.8 and 1.9.This is the "upstream / lift the pin" direction from the issue (option 1), which is preferable to making
quantile-forestoptional (option 2) because the QRF backend is the package's core model.Both-environment test evidence
Two isolated
uvvenvs (Python 3.13.9), each an editable install ofpopulace-frame+populace-fit+pytest, differing only in scikit-learn.quantile-forest==1.4.2in both; all other deps identical (numpy 2.5.1, pandas 3.0.3, scipy 1.18.0, joblib 1.5.3, threadpoolctl 3.6.0).scikit-learn 1.8.0 (
pip install "scikit-learn<1.9"):scikit-learn 1.9.0 (
pip install "scikit-learn>=1.9"):76/76 pass under both. A
scikit-learn>=1.9repo can now installpopulace-fitinto the same environment without a downgrade.Changelog
This repo has no changelog infrastructure — no
changelog.d/, nochangelog.yaml, noCHANGELOG.md, and no towncrier config in anypyproject.toml— so no fragment is added. (Towncrier is a PolicyEngine country-model-repo convention, not used in populace.)Files changed
packages/populace-fit/pyproject.toml— bumpquantile-forestfloor, drop sklearn cap, update the rationale comment.uv.lock—quantile-forest1.4.1 → 1.4.2 (adds cp314 wheels too).packages/populace-fit/README.md— document the sklearn coexistence guarantee under Dependencies.🤖 Generated with Claude Code