Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ New features

Changes
-------
- The :func: `tabular_pipeline` uses a :class:`SquashingScaler` instead of a
:class:`StandardScaler` for centering and scaling numerical features
when linear models are used.
:pr:`1644` by :user:`Simon Dierickx <dierickxsimon>`

Bugfixes
--------
Expand Down
8 changes: 4 additions & 4 deletions doc/modules/default_wrangling/tabular_pipeline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
.. |HistGradientBoostingRegressor| replace:: :class:`~sklearn.ensemble.HistGradientBoostingRegressor`
.. |HistGradientBoostingClassifier| replace:: :class:`~sklearn.ensemble.HistGradientBoostingClassifier`
.. |Pipeline| replace:: :class:`~sklearn.pipeline.Pipeline`
.. |StandardScaler| replace:: :class:`~sklearn.preprocessing.StandardScaler`
.. |SquashingScaler| replace:: :class:`~sklearn.preprocessing.SquashingScaler`
.. |SimpleImputer| replace:: :class:`~sklearn.impute.SimpleImputer`

.. _user_guide_tabular_pipeline:
Expand All @@ -18,15 +18,15 @@ The |tabular_pipeline| is a function that, given a scikit-learn estimator,
returns a full scikit-learn |Pipeline| that contains a |TableVectorizer|
followed by the given estimator.
If the estimator is a linear model (e.g., ``Ridge``, ``LogisticRegression``),
|tabular_pipeline| adds a |StandardScaler| and a |SimpleImputer| to the pipeline.
|tabular_pipeline| adds a |SquashingScaler| and a |SimpleImputer| to the pipeline.

>>> from sklearn.linear_model import LinearRegression
>>> from skrub import tabular_pipeline
>>> tabular_pipeline(LinearRegression()) # doctest: +SKLEARN_VERSION >= "1.4" +ELLIPSIS
Pipeline(steps=[('tablevectorizer',
TableVectorizer(datetime=DatetimeEncoder(periodic_encoding='spline'))),
('simpleimputer', SimpleImputer(add_indicator=True)),
('standardscaler', StandardScaler()),
('squashingscaler', SquashingScaler(max_absolute_value=5)),
('linearregression', LinearRegression())])

It is also possible to call the function with the name of the task that must be
Expand Down Expand Up @@ -63,7 +63,7 @@ problems, but may not beat properly tuned ad-hoc pipelines.
* - Numeric preprocessor
- No processing
- No processing
- :class:`~sklearn.preprocessing.StandardScaler`
- :class:`~sklearn.preprocessing.SquashingScaler`
* - Date preprocessor
- :class:`DatetimeEncoder`
- :class:`DatetimeEncoder`
Expand Down
18 changes: 12 additions & 6 deletions skrub/_tabular_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
from sklearn.base import BaseEstimator
from sklearn.impute import SimpleImputer
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import OrdinalEncoder, StandardScaler
from sklearn.preprocessing import OrdinalEncoder
from sklearn.utils.fixes import parse_version

from ._datetime_encoder import DatetimeEncoder
from ._sklearn_compat import get_tags
from ._squashing_scaler import SquashingScaler
from ._string_encoder import StringEncoder
from ._table_vectorizer import TableVectorizer
from ._to_categorical import ToCategorical
Expand Down Expand Up @@ -99,6 +100,11 @@ def tabular_pipeline(estimator, *, n_jobs=None):
The high cardinality encoder has been changed from
:class:`~skrub.MinHashEncoder` to :class:`~skrub.StringEncoder`.

.. versionchanged:: 0.7.0
The :class:`~skrub.SquashingScaler` with `max_absolute_value=5` is now used instead of
:class:`~sklearn.preprocessing.StandardScaler` for centering and scaling
numerical features when using linear models.

Comment thread
dierickxsimon marked this conversation as resolved.
Parameters
----------
estimator : {"regressor", "regression", "classifier", "classification"} or sklearn.base.BaseEstimator
Expand Down Expand Up @@ -136,7 +142,7 @@ def tabular_pipeline(estimator, *, n_jobs=None):
- An optional :obj:`~sklearn.impute.SimpleImputer` imputes missing values by their
mean and adds binary columns that indicate which values were missing. This step is
only added if the ``estimator`` cannot handle missing values itself.
- An optional :obj:`~sklearn.preprocessing.StandardScaler` centers and rescales the
- An optional :obj:`~skrub.SquashingScaler` centers and rescales the
data. This step is not added (because it is unnecessary) when the ``estimator`` is
a tree ensemble such as random forest or gradient boosting.
- The last step is the provided ``estimator``.
Expand Down Expand Up @@ -215,7 +221,7 @@ def tabular_pipeline(estimator, *, n_jobs=None):
Pipeline(steps=[('tablevectorizer',
TableVectorizer(datetime=DatetimeEncoder(periodic_encoding='spline'))),
('simpleimputer', SimpleImputer(add_indicator=True)),
('standardscaler', StandardScaler()),
('squashingscaler', SquashingScaler(max_absolute_value=5)),
('logisticregression', LogisticRegression())])

By applying only the first pipeline step we can see the transformed data that is
Expand All @@ -235,7 +241,7 @@ def tabular_pipeline(estimator, *, n_jobs=None):
Pipeline(steps=[('tablevectorizer',
TableVectorizer(datetime=DatetimeEncoder(periodic_encoding='spline'))),
('simpleimputer', SimpleImputer(add_indicator=True)),
('standardscaler', StandardScaler()),
('squashingscaler', SquashingScaler(max_absolute_value=5)),
('logisticregression', LogisticRegression())])

For a :obj:`~sklearn.linear_model.LogisticRegression`, we get:
Expand All @@ -247,7 +253,7 @@ def tabular_pipeline(estimator, *, n_jobs=None):
- A :obj:`~sklearn.impute.SimpleImputer`, as the
:obj:`~sklearn.linear_model.LogisticRegression` cannot handle missing values.

- A :obj:`~sklearn.preprocessing.StandardScaler` for centering and standard scaling
- A :obj:`~skrub.SquashingScaler` for centering and scaling
numerical features.

On the other hand, For the :obj:`~sklearn.ensemble.HistGradientBoostingClassifier`
Expand Down Expand Up @@ -331,6 +337,6 @@ def tabular_pipeline(estimator, *, n_jobs=None):
if not get_tags(estimator).input_tags.allow_nan:
steps.append(SimpleImputer(add_indicator=True))
if not isinstance(estimator, _TREE_ENSEMBLE_CLASSES):
steps.append(StandardScaler())
steps.append(SquashingScaler(max_absolute_value=5))
steps.append(estimator)
return make_pipeline(*steps)
5 changes: 3 additions & 2 deletions skrub/tests/test_tabular_learner.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
from sklearn import ensemble
from sklearn.impute import SimpleImputer
from sklearn.linear_model import Ridge
from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder, StandardScaler
from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder
from sklearn.utils.fixes import parse_version

from skrub import (
SquashingScaler,
StringEncoder,
TableVectorizer,
ToCategorical,
Expand Down Expand Up @@ -56,7 +57,7 @@ def test_linear_learner():
assert isinstance(tv.high_cardinality, StringEncoder)
assert isinstance(tv.low_cardinality, OneHotEncoder)
assert isinstance(imputer, SimpleImputer)
assert isinstance(scaler, StandardScaler)
assert isinstance(scaler, SquashingScaler)
assert tv.datetime.periodic_encoding == "spline"


Expand Down