Repository navigation
Conversation
RepresentationSearchCV.fit took only (X, y) and called cv.split without groups, so a group splitter (GroupKFold, LeaveOneGroupOut, GroupShuffleSplit, StratifiedGroupKFold) always raised "The 'groups' parameter should not be None" and fit(X, y, groups=g) raised a TypeError. Grouped data such as several rows per patient could not be searched with a leakage-safe group split, and there was no way to pass sample_weight or other fit parameters. fit now takes a keyword-only groups, forwarded to cv.split, and **fit_params, forwarded to the estimator's fit on every fold (per-sample values restricted to the fold's training rows, as in scikit-learn's searches) and on the final refit. The Preprocessor and the scorer do not receive them. Splits without groups are unchanged. Fixes #91
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 #91.
RepresentationSearchCVcould not use group splitters such asGroupKFold.fitcalled the splitter without groups and had nogroupsargument, and there was no way to passsample_weightor other fit parameters to the estimator. Grouped data (patients, sessions, sites) could not be searched with a split that keeps each group on one side.Root cause
RepresentationSearchCV.fit(X, y)took no other arguments. It calledcv.split(np.zeros(n_samples), y_arr)without groups and fitted the estimator on each fold and at the refit withfit(x, y)only.Fix
RepresentationSearchCV.fitis nowfit(X, y=None, *, groups=None, **fit_params), as in scikit-learn's searches:groupsis passed tocv.split.fit_paramsare made indexable once with scikit-learn's_check_method_params. Each fold's estimator gets them restricted to the fold's training rows, and the final refit ofbest_estimator_gets them whole.Preprocessors and the scorer do not receive them, so target-aware placement and validation scores stay unweighted.Behaviour changes
fitacceptsgroupsand arbitrary keyword fit parameters. Calls without them behave as before.groupswith a splitter that does not use them shows scikit-learn's usualThe groups parameter is ignored by ...warning.Documentation
RepresentationSearchCV.fitdocstring: new Parameters and Returns sections, includinggroupsand**fit_paramsand who receives them.cvparameter docstring: a group splitter such asGroupKFoldneedsgroupsatfit.docs/core_concepts/target_awareness.md("Searching over representations"): aGroupKFoldexample withgroups=patient_id, and a paragraph explaining that fit parameters such assample_weightreach the estimator on every fold and at the refit, but not thePreprocessoror the scorer.Tests
test_group_splitter_receives_groups[group_kfold],[leave_one_group_out],[group_shuffle_split]: withgroupsand a per-row fit parameter, each fold's estimator sees exactly the splitter's training rows, and no group is on both sides of a split. Fails onmain(TypeError), passes here.test_groups_leave_non_group_splits_unchanged: with a splitter that ignores groups, passinggroupsleavescv_results_unchanged. Fails onmain(TypeError), passes here.test_fit_params_are_split_per_fold_and_passed_to_the_refit: a per-row fit parameter is restricted to each fold's training rows and passed whole to the refit. Fails onmain(TypeError), passes here.test_sample_weight_reaches_the_estimator:best_estimator_has the coefficients of a weightedRidgefit on the best representation, and the fold scores change with the weights. Fails onmain(TypeError), passes here.Reproduction
Output of the script from #91 on this branch:
The first and third calls give
GroupKFoldno groups, so they now fail in the splitter, exactly asGridSearchCVdoes with the same arguments. The third no longer fails with aTypeErrorforsample_weight. Passinggroups=groups, sample_weight=np.ones(300)together fits.Checks
just test: 1444 passed, 59 skipped, 7 xfailed; coverage 93.65% (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/compose/search.py, keep_check_method_paramsin thesklearn.utils.validationimport next to RepresentationSearchCV lacks predict_proba, classes_ and classifier tags, so nested roc_auc CV returns NaN #92'sget_tagsandavailable_ifimports. At the refit, keepfit(x_all, y_arr, **fit_params)followed by RepresentationSearchCV lacks predict_proba, classes_ and classifier tags, so nested roc_auc CV returns NaN #92'sn_features_in_andfeature_names_in_lines. Indocs/core_concepts/target_awareness.md, both add paragraphs after the search example: keep both, this PR's first. Intests/compose/test_search.py, merge the imports and keep both test blocks. Resolved this way, the full suite passes (1450 passed, 59 skipped, 7 xfailed).RepresentationSearchCV.fit. Keep this PR's signature and parameter sections and add Preprocessor rejects polars DataFrames, so pipelines with set_output(transform="polars") crash #94's paragraph on polars input. Preprocessor rejects polars DataFrames, so pipelines with set_output(transform="polars") crash #94's one-time polars conversion then runs before_check_method_params. Resolved this way, the full suite passes (1460 passed, 59 skipped, 7 xfailed).pretab/compose/search.py.tests/compose/test_search.pyhas an append/append conflict: keep both blocks.This change was previously part of #97, which is closed in favour of one pull request per issue.