SkrubLearner#
- class skrub.SkrubLearner(data_op)[source]#
Learner that evaluates a skrub DataOp.
This class is not meant to be instantiated manually,
SkrubLearnerobjects are created by callingDataOp.skb.make_learner()on a DataOp, or by accessing thebest_learner_attribute of aParamSearchafter fitting it.- Attributes:
- classes_
Methods
Describe parameters for this learner.
find_fitted_estimator(what)Find the scikit-learn estimator that has been fitted in a
.skb.apply()step.Get the outcomes that have been set for named choices in the DataOp.
get_params([deep])Get parameters for this estimator.
report(*, environment, mode, ...)Call the method specified by
modeand return the result and full report.set_named_params(**params)Set the tunable parameters (choices), indexed by choice name.
set_params(**params)Set the parameters of this estimator.
truncated_after(what)Extract the part of the learner that leads up to the given step.
get_param_grid
- describe_params()[source]#
Describe parameters for this learner.
Returns a human-readable description (in form of a dict) of the parameters (outcomes of
choose_*objects contained in the DataOp).
- find_fitted_estimator(what)[source]#
Find the scikit-learn estimator that has been fitted in a
.skb.apply()step.This can be useful for example to inspect the fitted attributes of the estimator.
- Parameters:
- what
str,intorcallable() Indicates which (Apply) node to look for and extract the estimator from.
If a string, it is the name (set with
DataOp.skb.set_name()) of the step we want to find.If an int, it is the id (
DataOp.skb.id) of the node to search for.If a callable, it is the search predicate: it accepts a DataOp and returns a Boolean. The first node for which it returns True is used.
- what
- Returns:
- scikit-learn estimator
The fitted estimator. Depending on the nature of the estimator it may be wrapped in a
ApplyToColsorskrub._apply_to_sub_frame.ApplyToSubFrame, see examples below.
See also
DataOp.skb.findSearch for a node directly from a DataOp.
skrub.DataOp.skb.set_nameGive a name to this DataOp.
skrub.DataOp.skb.applyApply a scikit-learn estimator to a dataframe or numpy array.
Notes
The IDs of nodes can be inspected with
DataOp.skb.id, by passingshow_ids=TruetoDataOp.skb.draw_graph(), or in the nodes’ detailed pages generated byDataOp.skb.full_report().Examples
>>> from sklearn.decomposition import PCA >>> from sklearn.dummy import DummyClassifier >>> import skrub >>> from skrub import selectors as s
>>> orders = skrub.datasets.toy_orders() >>> X, y = skrub.X(), skrub.y() >>> pred = ( ... X.skb.apply(skrub.StringEncoder(n_components=2), cols=["product"]) ... .skb.set_name("product_encoder") ... .skb.apply(skrub.ToDatetime(), cols=["date"]) ... .skb.apply(skrub.DatetimeEncoder(add_total_seconds=False), cols=["date"]) ... .skb.apply(PCA(n_components=2), cols=s.glob("date_*")) ... .skb.set_name("pca") ... .skb.apply(DummyClassifier(), y=y) ... .skb.set_name("classifier") ... ) >>> learner = pred.skb.make_learner() >>> learner.fit({'X': orders.X, 'y': orders.y}) SkrubLearner(data_op=<classifier | Apply DummyClassifier>)
We can retrieve the fitted transformer for a given step with
find_fitted_estimator:>>> learner.find_fitted_estimator("classifier") DummyClassifier()
Depending on the parameters passed to
DataOp.skb.apply(), the estimator we provide may or may not be wrapped in aApplyToColstransformer.Case 1: the
StringEncoderis a skrub single-column transformer: it transforms a single column. In the learner it gets wrapped in aApplyToColswhich independently fits a separate instance of theStringEncoderto each of the columns it transforms (in this case there is only one column,'product'). The individual transformers can be found in the fitted attributetransformers_which maps column names to the corresponding fitted transformer.>>> encoder = learner.find_fitted_estimator('product_encoder') >>> encoder.transformers_ {'product': StringEncoder(n_components=2)} >>> encoder.transformers_['product'].vectorizer_.vocabulary_ {' pe': 2, 'pen': 12, 'en ': 8, ' pen': 3, 'pen ': 13, ' cu': 0, 'cup': 6, 'up ': 18, ' cup': 1, 'cup ': 7, ' sp': 4, 'spo': 16, 'poo': 14, 'oon': 10, 'on ': 9, ' spo': 5, 'spoo': 17, 'poon': 15, 'oon ': 11}
This case happens when the estimator is a skrub single-column transformer (it has a
__single_column_transformer__attribute), the input is a DataFrame and we passno_wrap=False(the default).Case 2: the
PCAis a regular scikit-learn transformer. In the learner it gets wrapped in aApplyToColswhich applies it to the subset of columns in the dataframe selected by thecolsargument passed to.skb.apply(). The fittedPCAcan be found in the fitted attributetransformer_.>>> pca = learner.find_fitted_estimator('pca') >>> pca ApplyToSubFrame(cols=glob('date_*'), transformer=PCA(n_components=2)) >>> pca.transformer_ PCA(n_components=2) >>> pca.transformer_.mean_ array([2020., 4., 4.], dtype=float32)
This case happens when the estimator is a scikit-learn transformer but not a single-column transformer, the input is a DataFrame and we pass
no_wrap=False(the default).The
DummyRegressoris a scikit-learn predictor. In the learner it gets applied directly to the input dataframe without any wrapping.>>> classifier = learner.find_fitted_estimator('classifier') >>> classifier DummyClassifier() >>> classifier.class_prior_ array([0.75, 0.25])
This case (no wrapping) happens when the estimator is a scikit-learn predictor (not a transformer), the input is not a dataframe (e.g. it is a numpy array), or we pass
.skb.apply(no_wrap=True).
- get_named_params()[source]#
Get the outcomes that have been set for named choices in the DataOp.
The returned dictionary can be used with
SkrubLearner.set_named_params(). Only choices that have been given an explicit name are included in the result.- Returns:
dictThe choices set on this SkrubLearner. The key is the choice name. For discrete choices (created with
skrub.choose_from(),skrub.choose_bool(), …) the value is the index of the selected outcome in the outcome list (not its value).
See also
SkrubLearner.set_named_paramsSet the choices returned by
get_named_paramson a learner.SkrubLearner.describe_paramsGet a dictionary describing all choices. It cannot be used to set parameters but is more helpful for manual inspection.
Notes
This is similar to the standard scikit-learn interface implemented by
SkrubLearner.get_params()andSkrubLearner.set_params(), but a more robust way to transfer hyperparameters to another DataOp with a different topology, as relies on choice names rather than indices.Examples
See the documentation for
SkrubLearner.set_named_params()for examples.
- report(*, environment, mode, **full_report_kwargs)[source]#
Call the method specified by
modeand return the result and full report.See
DataOp.skb.full_report()for more information.- Parameters:
- Returns:
dictThe result of
DataOp.skb.full_report: a dict containing'result','error'and'report_path'.
Examples
We start by creating the learner for a simple DataOp:
>>> import skrub >>> from sklearn.linear_model import LogisticRegression >>> from sklearn.datasets import make_classification >>> pred = skrub.X().skb.apply(LogisticRegression(), y=skrub.y()) >>> X, y = make_classification(n_samples=20, random_state=0) >>> split = pred.skb.train_test_split({'X': X, 'y': y}, shuffle=False) >>> learner = pred.skb.make_learner()
We can now obtain reports for the different methods of the learner such as ‘fit’, ‘predict_proba’, etc.
>>> fit_results = learner.report( ... environment=split["train"], mode="fit", open=False ... ) >>> fit_results['report_path'] PosixPath('.../skrub_data/execution_reports/full_data_op_report_.../index.html')
Note that our learner has been fitted now, we can use it for predictions.
>>> predict_results = learner.report( ... environment=split["train"], mode="predict", open=False ... ) >>> predict_results['report_path'] PosixPath('.../skrub_data/execution_reports/full_data_op_report_.../index.html')
In addition to the report, we can also retrieve the actual output of the ‘predict’ method:
>>> predict_results['result'] array([0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0])
- set_named_params(**params)[source]#
Set the tunable parameters (choices), indexed by choice name.
Typically, the passed dictionary is created by
SkrubLearner.get_named_params().The choice outcomes are set in-place, i.e. the input SkrubLearner is modified.
- Parameters:
- params
dict The key is the name of a skrub choice.
For numeric choices (
choose_int()andchoose_bool()), the value is the choice outcome i.e. the number that will be used e.g. 0.05.For enumerated choices (
choose_from(),choose_bool(),optional()), the value is an int: the index (position) of the outcome to select from the outcome list (or dict). The list can be checked withchoice.outcomes.
- params
See also
SkrubLearner.get_named_paramsGet the dictionary of choices, which can be used to set them on another learner.
Notes
This is similar to the standard scikit-learn interface implemented by
SkrubLearner.get_params()andSkrubLearner.set_params(), but a more robust way to transfer hyperparameters to another DataOp with a different topology, as relies on choice names rather than indices.Examples
>>> import skrub >>> from sklearn.decomposition import PCA >>> from sklearn.preprocessing import StandardScaler, MinMaxScaler >>> from sklearn.linear_model import Ridge >>> from sklearn.datasets import make_regression
>>> X, y = make_regression(random_state=0) >>> scaler = skrub.choose_from( ... [MinMaxScaler(), StandardScaler(), skrub.SquashingScaler()], ... name="scaler", ... ) >>> transform = ( ... skrub.X(X) ... .skb.apply(scaler) ... .skb.apply( ... PCA(n_components=skrub.choose_int(10, 30, name="n_components")) ... ) ... ) >>> pred = transform.skb.apply( ... Ridge(alpha=skrub.choose_float(0.1, 10.0, log=True)), y=skrub.y(y) ... ) >>> best_learner = pred.skb.make_randomized_search( ... fitted=True, random_state=0 ... ).best_learner_
We can inspect the best hyperparameters found by the search:
>>> best_learner.describe_params() {'scaler': 'SquashingScaler()', 'n_components': 11, 'choose_float(0.1, 10.0, log=True)': 0.351...}
Now suppose we want to transfer them to a learner for a different DataOp, for example one that only does the transformation:
>>> transformer = transform.skb.make_learner()
This transformer has no values set, it uses the default parameters:
>>> transformer.describe_params() {'scaler': 'MinMaxScaler()', 'n_components': 20} >>> transformer.fit_transform({"X": X}).shape (100, 20)
We can get the params out of our best learner:
>>> best_learner.get_named_params() {'scaler': 2, 'n_components': np.int64(11)}
Note that the ridge’s
alphadoes not appear, as it has no name.Also note that the value for the scaler is the outcome’s index, rather than its value. Here the SquashingScaler is the third item in the outcome list:
>>> scaler.outcomes [MinMaxScaler(), StandardScaler(), SquashingScaler()]
So we get
'scaler': 2in the named params.>>> transformer.set_named_params(**best_learner.get_named_params()) SkrubLearner(data_op=<Apply PCA>) >>> transformer.describe_params() {'scaler': 'SquashingScaler()', 'n_components': 11}
(note that our
transformerhas been modified in-place.)>>> transformer.fit_transform({"X": X}).shape (100, 11)
We can also set parameters manually:
>>> transformer.set_named_params(n_components=7) SkrubLearner(data_op=<Apply PCA>) >>> transformer.describe_params() {'scaler': 'SquashingScaler()', 'n_components': 7} >>> transformer.fit_transform({"X": X}).shape (100, 7)
Here also, note that for enumerated choices we must use the index:
>>> transformer.set_named_params(scaler=1) SkrubLearner(data_op=<Apply PCA>) >>> transformer.describe_params() {'scaler': 'StandardScaler()', 'n_components': 7}
trying to set a value directly results in an error:
>>> best_learner.set_named_params(scaler=StandardScaler()) Traceback (most recent call last): ... TypeError: For enumerated choices, the value must be a positional index (int). Got value StandardScaler() of type StandardScaler for choice choose_from([MinMaxScaler(), StandardScaler(), SquashingScaler()], name='scaler').
- set_params(**params)[source]#
Set the parameters of this estimator.
The method works on simple estimators as well as on nested objects (such as
Pipeline). The latter have parameters of the form<component>__<parameter>so that it’s possible to update each component of a nested object.- Parameters:
- **params
dict Estimator parameters.
- **params
- Returns:
- selfestimator instance
Estimator instance.
- truncated_after(what)[source]#
Extract the part of the learner that leads up to the given step.
This is similar to slicing a scikit-learn pipeline. It can be useful for example to drive the hyperparameter selection with a supervised task but then extract only the part of the learner that performs feature extraction.
- Parameters:
- what
str,intorcallable() If a string, it is the name (set with
DataOp.skb.set_name()) of the step we want to extract.If an int, it is the id (
DataOp.skb.id) of the node to search for.If a callable, it is the search predicate: it accepts a DataOp and returns a Boolean. The first node for which it returns True is returned.
- what
- Returns:
- SkrubLearner
A skrub learner that performs all the transformations leading up to (and including) the required step.
See also
DataOp.skb.findSearch for a node directly from a DataOp rather than a SkrubLearner.
DataOp.skb.find_X_yFind the nodes that have been marked with
DataOp.skb.mark_as_X()andDataOp.skb.mark_as_y().
Notes
The IDs of nodes can be inspected with
DataOp.skb.id, by passingshow_ids=TruetoDataOp.skb.draw_graph(), or in the nodes’ detailed pages generated byDataOp.skb.full_report().Examples
>>> from sklearn.dummy import DummyClassifier >>> import skrub
>>> orders = skrub.datasets.toy_orders() >>> X, y = skrub.X(), skrub.y() >>> pred = ( ... X.skb.apply( ... skrub.TableVectorizer(datetime=skrub.DatetimeEncoder(add_total_seconds=False)) ... ) ... .skb.set_name("vectorizer") ... .skb.apply(DummyClassifier(), y=y) ... ) >>> learner = pred.skb.make_learner() >>> learner.fit({"X": orders.X, "y": orders.y}) SkrubLearner(data_op=<Apply DummyClassifier>) >>> learner.predict({"X": orders.X}) array([False, False, False, False])
Truncate the learner after vectorization:
>>> vectorizer = learner.truncated_after("vectorizer") >>> vectorizer SkrubLearner(data_op=<vectorizer | Apply TableVectorizer>) >>> vectorizer.transform({"X": orders.X}) ID product_cup product_pen ... date_year date_month date_day 0 1.0 0.0 1.0 ... 2020.0 4.0 3.0 1 2.0 1.0 0.0 ... 2020.0 4.0 4.0 2 3.0 1.0 0.0 ... 2020.0 4.0 4.0 3 4.0 0.0 0.0 ... 2020.0 4.0 5.0
Note this differs from
find_fitted_estimatorwhich extracts the inner scikit-learn estimator that has been fitted inside of a single step.This contains the full transformation up to the given step:
>>> learner.truncated_after("vectorizer") SkrubLearner(data_op=<vectorizer | Apply TableVectorizer>)
The result of
find_fitted_estimatoronly contains the innerTableVectorizerthat was fitted inside of the"vectorizer"step:>>> learner.find_fitted_estimator("vectorizer") ApplyToSubFrame(transformer=TableVectorizer(datetime=DatetimeEncoder(add_total_seconds=False)))
Gallery examples#
Multiples tables: building machine learning pipelines with DataOps
Use case: developing locally and deploying to production