@@ -82,16 +82,57 @@ def _copy_attr(source, target, attributes):
8282 pass
8383
8484
85- class _CloudPickleDataOp (_CloudPickle ):
85+ class _DataOpWrapperMixin (_CloudPickle ):
8686 """
87- Mixin to serialize the `DataOp` attribute with cloudpickle when pickling a
88- learner.
87+ Mixin for learners and estimators that wrap a DataOp.
88+
89+ It exposes some attributes (tags, classes_) needed by scikit-learn by
90+ inspecting the data_op attribute.
91+
92+ It also relies on the _CloudPickle mixin to serialize the DataOp with
93+ cloudpickle rather than the normal pickle protocol when the learner is
94+ pickled.
8995 """
9096
9197 _cloudpickle_attributes = ["data_op" ]
9298
99+ @property
100+ def _estimator_type (self ):
101+ first = find_first_apply (self .data_op )
102+ if first is None :
103+ return "transformer"
104+ estimator = get_default (first ._skrub_impl .estimator )
105+ if isinstance (estimator , DataOp ):
106+ return "transformer"
107+ try :
108+ return estimator ._estimator_type
109+ except AttributeError :
110+ return "transformer"
111+
112+ if hasattr (BaseEstimator , "__sklearn_tags__" ):
113+ # scikit-learn >= 1.6
114+
115+ def __sklearn_tags__ (self ):
116+ first = find_first_apply (self .data_op )
117+ if first is None :
118+ return _default_sklearn_tags ()
119+ estimator = get_default (first ._skrub_impl .estimator )
120+ if isinstance (estimator , DataOp ):
121+ return _default_sklearn_tags ()
122+ try :
123+ return estimator .__sklearn_tags__ ()
124+ except AttributeError :
125+ return _default_sklearn_tags ()
126+
127+ @property
128+ def classes_ (self ):
129+ try :
130+ return _get_classes (self .data_op )
131+ except AttributeError :
132+ attribute_error (self , "classes_" )
133+
93134
94- class SkrubLearner (_CloudPickleDataOp , BaseEstimator ):
135+ class SkrubLearner (_DataOpWrapperMixin , BaseEstimator ):
95136 """Learner that evaluates a skrub DataOp.
96137
97138 This class is not meant to be instantiated manually, ``SkrubLearner``
@@ -482,41 +523,6 @@ def _get_env(self, X, y):
482523 xy_environment [Y_NAME ] = y
483524 return {** self .environment , ** xy_environment }
484525
485- @property
486- def _estimator_type (self ):
487- first = find_first_apply (self .data_op )
488- if first is None :
489- return "transformer"
490- estimator = get_default (first ._skrub_impl .estimator )
491- if isinstance (estimator , DataOp ):
492- return "transformer"
493- try :
494- return estimator ._estimator_type
495- except AttributeError :
496- return "transformer"
497-
498- if hasattr (BaseEstimator , "__sklearn_tags__" ):
499- # scikit-learn >= 1.6
500-
501- def __sklearn_tags__ (self ):
502- first = find_first_apply (self .data_op )
503- if first is None :
504- return _default_sklearn_tags ()
505- estimator = get_default (first ._skrub_impl .estimator )
506- if isinstance (estimator , DataOp ):
507- return _default_sklearn_tags ()
508- try :
509- return estimator .__sklearn_tags__ ()
510- except AttributeError :
511- return _default_sklearn_tags ()
512-
513- @property
514- def classes_ (self ):
515- try :
516- return _get_classes (self .data_op )
517- except AttributeError :
518- attribute_error (self , "classes_" )
519-
520526
521527class _XyPipeline (_XyPipelineMixin , SkrubLearner ):
522528 """
@@ -763,7 +769,7 @@ def iter_cv_splits(data_op, environment, *, keep_subsampling=False, cv=KFOLD_5):
763769 yield split_info
764770
765771
766- class _BaseParamSearch (_CloudPickleDataOp , BaseEstimator ):
772+ class _BaseParamSearch (_DataOpWrapperMixin , BaseEstimator ):
767773 """Base class for hyperparameter search objects.
768774
769775 It defines some default implementations for getting results, plotting, and
0 commit comments