SkrubLearner#

class skrub.SkrubLearner(data_op)[source]#

Learner that evaluates a skrub DataOp.

This class is not meant to be instantiated manually, SkrubLearner objects are created by calling DataOp.skb.make_learner() on a DataOp, or by accessing the best_learner_ attribute of a ParamSearch after fitting it.

Attributes:
classes_

Methods

describe_params()

Describe parameters for this learner.

find_fitted_estimator(what)

Find the scikit-learn estimator that has been fitted in a .skb.apply() step.

get_named_params()

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 mode and 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:
whatstr, int or callable()

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.

Returns:
scikit-learn estimator

The fitted estimator. Depending on the nature of the estimator it may be wrapped in a ApplyToCols or skrub._apply_to_sub_frame.ApplyToSubFrame, see examples below.

See also

DataOp.skb.find

Search for a node directly from a DataOp.

skrub.DataOp.skb.set_name

Give a name to this DataOp.

skrub.DataOp.skb.apply

Apply a scikit-learn estimator to a dataframe or numpy array.

Notes

The IDs of nodes can be inspected with DataOp.skb.id, by passing show_ids=True to DataOp.skb.draw_graph(), or in the nodes’ detailed pages generated by DataOp.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 a ApplyToCols transformer.

Case 1: the StringEncoder is a skrub single-column transformer: it transforms a single column. In the learner it gets wrapped in a ApplyToCols which independently fits a separate instance of the StringEncoder to each of the columns it transforms (in this case there is only one column, 'product'). The individual transformers can be found in the fitted attribute transformers_ 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 pass no_wrap=False (the default).

Case 2: the PCA is a regular scikit-learn transformer. In the learner it gets wrapped in a ApplyToCols which applies it to the subset of columns in the dataframe selected by the cols argument passed to .skb.apply(). The fitted PCA can be found in the fitted attribute transformer_.

>>> 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 DummyRegressor is 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:
dict

The 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_params

Set the choices returned by get_named_params on a learner.

SkrubLearner.describe_params

Get 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() and SkrubLearner.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.

get_params(deep=True)[source]#

Get parameters for this estimator.

Parameters:
deepbool, default=True

If True, will return the parameters for this estimator and contained subobjects that are estimators.

Returns:
paramsdict

Parameter names mapped to their values.

report(*, environment, mode, **full_report_kwargs)[source]#

Call the method specified by mode and return the result and full report.

See DataOp.skb.full_report() for more information.

Parameters:
environmentdict

Bindings for variables contained in the DataOp that was used to create this learner (e.g. {"X": X_df, "other_table": df, ...}).

modestr

The method to call in order to generate the report, such as "fit", "predict", etc.

full_report_kwargsdict

See DataOp.skb.full_report()

Returns:
dict

The 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:
paramsdict

The key is the name of a skrub choice.

  • For numeric choices (choose_int() and choose_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 with choice.outcomes.

See also

SkrubLearner.get_named_params

Get 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() and SkrubLearner.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 alpha does 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': 2 in 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 transformer has 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:
**paramsdict

Estimator parameters.

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:
whatstr, int or callable()
  • 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.

Returns:
SkrubLearner

A skrub learner that performs all the transformations leading up to (and including) the required step.

See also

DataOp.skb.find

Search for a node directly from a DataOp rather than a SkrubLearner.

DataOp.skb.find_X_y

Find the nodes that have been marked with DataOp.skb.mark_as_X() and DataOp.skb.mark_as_y().

Notes

The IDs of nodes can be inspected with DataOp.skb.id, by passing show_ids=True to DataOp.skb.draw_graph(), or in the nodes’ detailed pages generated by DataOp.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_estimator which 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_estimator only contains the inner TableVectorizer that was fitted inside of the "vectorizer" step:

>>> learner.find_fitted_estimator("vectorizer")
ApplyToSubFrame(transformer=TableVectorizer(datetime=DatetimeEncoder(add_total_seconds=False)))