scikit-learn / scikit-learn/scikit-learn

SelectFromModel's `prefit` fails unless fit is called when set_output(transform="pandas")

Open
#34,880 10 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Documentation Needs Decision
Dominant language
Python
Stars
67.3k
Forks
27.4k
Avg merge
1d 15h
Merged PRs (30d)
58

Description

[!WARNING]
This issue is not yet ready for a PR. If you are interested in contributing to scikit-learn, please have a look at our contributing guidelines, and in particular the sections for new contributors and the "Needs triage" label.

Introduce yourself

My understanding is that if prefitis true, one could, in principle call transform() without calling fit() first.

While this is true if we don't set the output to pandas, it fails when we do so:

Minimal reproduction:

import pandas as pd
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.feature_selection import SelectFromModel

X, y = load_iris(as_frame=True, return_X_y=True)
clf = LogisticRegression(max_iter=1000).fit(X, y)

# prefit=True -- docs say we don't need to call .fit() on sel
sel = SelectFromModel(clf, prefit=True).set_output(transform="pandas")

sel.transform(X)
NotFittedError: This SelectFromModel instance is not fitted yet. Call 'fit' with appropriate arguments before using this estimator.

Without .set_output(transform="pandas"), the identical prefit=True selector transforms X just fine with no .fit() call.

The error only appears once pandas output is requested, because set_output internally calls get_feature_names_out(), which checks whether the wrapper itself has been fitted (via check_is_fitted(self), not check_is_fitted(self.estimator)).

According to Claude, that check was intentionally added in #25308 to standardize get_feature_names_out() behavior across SelectorMixin estimators.

So my question is: is this expected behaviour? or is it an unintended bug?

From a user perspective, if I use fitagain, even though prefit is True, I get the impression that my estimator would be re-fitted, so if this is intended, it might be worth adding a line in the docs.

sel.fit(X, y)     # with prefit=True, does NOT retrain clf -- just
                  # deep-copies it and records feature_names_in_
sel.transform(X)  # now works
Describe the issue linked to the documentation

SelectFromModel's prefit parameter is documented as:

prefit : bool, default=False
Whether a prefit model is expected to be passed into the constructor directly or not. If True, estimator must be a fitted estimator. If False, estimator is fitted and updated by calling fit and partial_fit, respectively.

Maybe it's just me, but I sort of read this as, if the estimator is prefit, I could avoid calling fit and it would be just fine.

Suggest a potential alternative/fix

Add a note to the prefit parameter docstring, e.g.:

Note: even with prefit=True, .fit() must still be called before using get_feature_names_out() or set_output(transform="pandas"), since these check whether the selector itself (not the underlying estimator) has been fitted. Calling .fit() in this case does not refit estimator; it only records bookkeeping metadata (estimator_, feature_names_in_).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with SelectFromModel's prefit behavior and the get_feature_names_out path described in the issue. Run the provided pandas-output reproduction and compare it with the non-pandas transform case. Done means deciding whether prefit should support this usage and aligning the behavior or documentation, with regression coverage if a code change is chosen.

Written by the indexing model from the issue text.

Assessment

Tech stack
pandas, python, scikit-learn
Domain
api, machine-learning
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.