Skip to content

FIX routing to composite methods #30869

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

adrinjalali
Copy link
Member

Fixes #30527
Closes #30529

cc @kschluns

This seems to be the core of the issue we have there,

Here's a minimal reproducer for easier debuging:

from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.decomposition import PCA
import numpy as np
from sklearn.base import BaseEstimator, TransformerMixin
import sklearn

from sklearn.utils._metadata_requests import (
    MetadataRouter,
    MethodMapping,
    process_routing,
)

sklearn.set_config(enable_metadata_routing=True)

class MyTransformer(TransformerMixin, BaseEstimator):
    def fit(self, X, y=None, sample_weight=None):
        return self
    def transform(self, X):
        return X

class MyMetaTransformer(TransformerMixin, BaseEstimator):
    def __init__(self, estimator):
        self.estimator = estimator

    def fit(self, X, y=None, **params):
        routed_params = process_routing(self, "fit", **params)
        self.estimator.fit(X, y, **routed_params.estimator.fit)

    def transform(self, X):
        return self.estimator.transform(X)

    def get_metadata_routing(self):
        router = MetadataRouter(owner=self.__class__.__name__).add(
            estimator=self.estimator,
            method_mapping=MethodMapping().add(caller="fit", callee="fit"),
        )
        return router


class MyPipeline(BaseEstimator):
    def __init__(self, steps):
        self.steps = steps

    def fit(self, X, y=None, **params):
        routed_params = process_routing(self, "fit", **params)
        for name, step in self.steps[:-1]:
            if hasattr(step, "fit_transform"):
                X = step.fit_transform(X, y, **routed_params[name].fit_transform)
            else:
                X = step.fit(X, y, **routed_params[name].fit).transform(X)
        self.steps[-1][1].fit(X, y, **routed_params[self.steps[-1][0]].fit)

    def get_metadata_routing(self):
        router = MetadataRouter(owner=self.__class__.__name__)
        for name, step in self.steps:
            if hasattr(step, "fit_transform"):
                router.add(
                    **{name: step},
                    method_mapping=MethodMapping().add(caller="fit", callee="fit_transform"),
                )
            else:
                router.add(
                    **{name: step},
                    method_mapping=MethodMapping().add(caller="fit", callee="fit"),
                )
        return router


X, y = load_iris(return_X_y=True)
sample_weights = np.ones(len(y))
estimator = MyMetaTransformer(MyTransformer().set_fit_request(sample_weight=True))
pipe = MyPipeline([("trs", estimator), ("estimator", LogisticRegression().set_fit_request(sample_weight=True))])
pipe.fit(X, y, sample_weight=sample_weights)

Needs polishing and fixing tests before merging.

Copy link

✔️ Linting Passed

All linting checks passed. Your pull request is in excellent shape! ☀️

Generated for commit: 0a227a4. Link to the linter CI: here

@adrinjalali adrinjalali added the Metadata Routing all issues related to metadata routing, slep006, sample props label Aug 11, 2025
@adrinjalali adrinjalali moved this to Todo in Metadata routing Aug 11, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Metadata Routing all issues related to metadata routing, slep006, sample props module:utils
Projects
Status: Todo
Development

Successfully merging this pull request may close these issues.

Feature Selectors fail to route metadata when inside a Pipeline
1 participant