Stop fit() mutating constructor parameters in PCA / PLS / OPLS (#505) - #527
Merged
Merged
Conversation
…ing the clone contract PCA, PLS, and OPLS wrote the resolved component count (and PLS the resolved missing-data settings) back onto their constructor parameters inside fit(). sklearn's contract requires __init__ arguments to stay verbatim, because get_params/clone/GridSearchCV treat them as the requested configuration: PLS.cross_validate clones the fitted parent, so every resample silently inherited the clamped component count and the mutated missing-data settings, and PCA(n_components=None) became a concrete int after one fit, freezing the first dataset's clamp. The resolved count is now the fitted attribute n_components_, set only in fit(); the parameter is untouched. Internal post-fit readers (the T2 limit mixin, ellipse_coordinates, spe_limit, the plot pre-checks, PLS prediction intervals) read n_components_, MBPCA/MBPLS expose the same fitted attribute for those shared helpers, and OPLS maps the old attribute name to a rename message. Clamping logic and its SpecificationWarning are unchanged. Fixes #505. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
The typecheck gate is red on main itself: the unpinned mcp extra now resolves to mcp 2.x, where FastMCP was renamed MCPServer, so mypy fails on mcp_server.py on every branch. This ports the migrated server and the mcp>=2.0 floor verbatim from #528; the diff no-ops once #528 merges. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
Owner
Author
|
The Generated by Claude Code |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Codecov flagged the TPLS-parent delegation, the plain-integer fallback, and the unfitted-model raise as uncovered on the patch; pin all four resolution paths directly. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019C3XXbJkuSYH9fMryLqNcU
63 tasks
…e-library-issues-hr7xxk-clone # Conflicts: # CHANGELOG.md # CITATION.cff # pyproject.toml
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.
Summary
fit()no longer writes the resolved component count (or, in PLS, the resolved missing-data settings) back onto constructor parameters. The resolved value is the new fitted attributen_components_;n_componentsstays exactly what the user passed, includingNone, soget_params/clone/PLS.cross_validateresamples fit the requested configuration and refitting one instance on differently shaped data re-derives the clamp each time. Clamping logic and itsSpecificationWarningare unchanged, per the issue's non-goals.n_components_: the shared Hotelling's T2 limit mixin andellipse_coordinatesin_base.py,spe_limitin_limits.py, the plot pre-checks inplots.py(new_fitted_n_componentshelper that also handles the TPLS_parentwiring), PCA'shotellings_t2, and PLSprediction_interval. MBPCA/MBPLS now also setn_components_infit()so those shared helpers read one attribute across all four estimators.n_componentsconstructor parameter) exposes the fitted count only asn_components_and maps the old attribute name to a helpful rename message via its existing_ATTRIBUTE_RENAMESmachinery.All four acceptance criteria from the issue are covered by new tests in
tests/test_sklearn_compat.py:get_params()round-trip after fit (includingNone),clone()reproduces the request, refit on different shapes resolves independently, and a spy onPLS.fitpins that everycross_validatesub-model is constructed with the user's requestedn_components.Version 1.73.0 (MINOR: post-fit meaning of
n_componentschanges; assumes queued PR #524 merges first, trivial rebase otherwise).Test plan
tests/test_sklearn_compat.py(20 passed)uv run pytest tests/test_multivariate.py tests/test_multivariate_opls.py tests/test_sklearn_compat.py tests/test_multivariate_contribution_plots.py tests/test_audit_regressions_multivariate.py --no-cov: 269 passed, 2 pre-existing skipsuv run pytest tests/test_multiblock_reference.py tests/test_multiblock_oracles.py tests/test_multivariate_tpls_display.py tests/test_multivariate_adaptive.py tests/test_multivariate_tpls_feature_importance.py --no-cov: 154 passedruff checkandruff format --checkclean;mypy src/process_improveshows only the pre-existingmcp_server.pyFastMCP error unrelated to this diffChecklist
pyproject.toml(PATCH for fixes/docs/config, MINOR for new features)ruff check .passesCHANGELOG.mdupdatedGenerated by Claude Code