Up until now we have covered how to clean data with the Cleaner, extract features from different column types, and handle categorical features with specialized encoders. In this section we will show how we can combine all these preprocessing techniques into a complete machine learning pipeline.
A pipeline ensures that:
Data transformations are applied consistently across training and test sets
Data leakage is avoided by fitting transformers only on training data
The workflow is reproducible and deployable
Preprocessing steps are properly chained together
In this chapter, we explore two approaches: building custom pipelines with TableVectorizer, and using the tabular_pipeline function for quick, well-tuned baselines.
7.2 Manual pipeline construction with TableVectorizer
The TableVectorizer can be the foundation of a custom scikit-learn pipeline, where cleaning and feature engineering are dealt with by a single object. Scaling and imputation are not required by all models, so they are not in the TableVectorizer’s scope.
We combine it with other preprocessing steps and a final estimator:
This approach gives complete control over which preprocessing steps to use and in what order. We can customize the TableVectorizer parameters (cardinality threshold, custom encoders, etc.) and add additional preprocessing steps as needed.
In the case of the example we used LogisticRegression as our estimator, but if we used a different estimator, such as the HistogramGradientBoostingClassifier, the scaling and imputation steps could have been avoided.
7.3 The tabular_pipeline
For many common use cases, we can skip the manual pipeline construction and use the tabular_pipeline function. This function automatically creates an appropriate pipeline based on the estimator we provide:
from skrub import tabular_pipelinefrom sklearn.linear_model import LogisticRegression# Create a complete pipeline for a specific estimatormodel = tabular_pipeline(LogisticRegression())
Or, we can use a string to get a pre-configured pipeline with a default estimator:
# Classification with HistGradientBoostingClassifiermodel = tabular_pipeline('classification')# Regression with HistGradientBoostingRegressormodel = tabular_pipeline('regression')
7.4 How tabular_pipeline adapts to different estimators
The tabular_pipeline function configures the preprocessing pipeline based on the estimator type:
7.4.1 For linear models (e.g., LogisticRegression, Ridge)
TableVectorizer: Uses the default configuration, except for the addition of spline-encoded datetime features by the DatetimeEncoder
SimpleImputer: Added because linear models cannot handle missing values
SquashingScaler: Normalizes numeric features to improve convergence and performance
Estimator: The provided linear model
This configuration ensures numeric features are properly scaled and missing values are handled appropriately.
7.4.2 For tree-based ensemble models (RandomForest, HistGradientBoosting)
TableVectorizer: Configured specifically for tree models
Low-cardinality categorical features: Either kept as categorical (HistGradientBoosting) or ordinal encoded (RandomForest)
High-cardinality features: StringEncoder for robust feature extraction
Datetime features: No spline encoding (unnecessary for trees)
Scaler: Not added (unnecessary for tree-based models)
Estimator: The provided tree-based estimator
This configuration leverages the native capabilities of tree models while still providing effective feature engineering through the StringEncoder.
7.5 Customizing the pipeline
Tip
This is unnecessary most of the time!
from sklearn.decomposition import PCAfrom sklearn.linear_model import Ridgefrom sklearn.pipeline import make_pipelinefrom skrub import tabular_pipeline# Create a pipeline that includes two stepsmodel_pipeline = make_pipeline(PCA(n_components=20), Ridge())# Pass the new model to tabular_pipelinefull_pipeline = tabular_pipeline(model_pipeline)[name for name, _ in full_pipeline.steps]
Use tabular_pipeline if: - You need a quick baseline for benchmarking/checking if there is a signal - You want a starting point for experimentation - You don’t need custom preprocessing/feature engineering
Embed a pipeline in tabular_pipeline if : - You need to modify only the end of the pipeline
Use a manual pipeline if : - You need fine-grained control over most of the transformations - Your training process includes custom preprocessing steps - You want to experiment with different transformers
Or… use the skrub Data Ops! (more on that later, maybe)
7.7 Example: Complete Workflow
from sklearn.model_selection import cross_val_score# Create pipelinemodel = tabular_pipeline(LogisticRegression())# Evaluate with cross-validationscores = cross_val_score(model, X, y, cv=5)print(f"Score: {scores.mean():.4f}")
That’s it!
7.8 What we have seen in this chapter
Always use pipelines to prevent data leakage
TableVectorizer handles most of the feature engineering
Manual pipelines give full control
tabular_pipeline provides a good baseline with good defaults
Provide a model, or "classification" or "regression"
---title: "Building a tabular pipeline"format: html: toc: true revealjs: slide-number: true toc: false code-fold: false code-tools: true---## IntroductionUp until now we have covered how to clean data with the `Cleaner`, extract features from different column types, and handle categorical features with specializedencoders. In this section we will show how we can combine all these preprocessingtechniques into a complete machine learning pipeline.A pipeline ensures that:- Data transformations are applied consistently across training and test sets- Data leakage is avoided by fitting transformers only on training data- The workflow is reproducible and deployable- Preprocessing steps are properly chained togetherIn this chapter, we explore two approaches: building custom pipelines with`TableVectorizer`, and using the `tabular_pipeline` function for quick,well-tuned baselines.## Manual pipeline construction with `TableVectorizer`The `TableVectorizer` can be the foundation of a custom scikit-learn pipeline, where cleaning and feature engineering are dealt with by a single object. Scaling and imputation are not required by all models, so they are not in the `TableVectorizer`'s scope. We combine it with other preprocessing steps and a final estimator:```pythonfrom sklearn.pipeline import make_pipelinefrom sklearn.linear_model import LogisticRegressionfrom sklearn.preprocessing import StandardScalerfrom sklearn.impute import SimpleImputerfrom skrub import TableVectorizermodel = make_pipeline( TableVectorizer(), # Feature engineering SimpleImputer(), # Handle missing values StandardScaler(), # Normalize features LogisticRegression() # Final estimator)```This approach gives complete control over which preprocessing steps to use andin what order. We can customize the `TableVectorizer` parameters (cardinalitythreshold, custom encoders, etc.) and add additional preprocessing steps as needed.In the case of the example we used `LogisticRegression` as our estimator, but if weused a different estimator, such as the `HistogramGradientBoostingClassifier`, the scaling and imputation steps could have been avoided. ## The `tabular_pipeline`For many common use cases, we can skip the manual pipeline construction and usethe `tabular_pipeline` function. This function automatically creates an appropriatepipeline based on the estimator we provide:```pythonfrom skrub import tabular_pipelinefrom sklearn.linear_model import LogisticRegression# Create a complete pipeline for a specific estimatormodel = tabular_pipeline(LogisticRegression())```Or, we can use a string to get a pre-configured pipeline with a default estimator:```python# Classification with HistGradientBoostingClassifiermodel = tabular_pipeline('classification')# Regression with HistGradientBoostingRegressormodel = tabular_pipeline('regression')```## How `tabular_pipeline` adapts to different estimatorsThe `tabular_pipeline` function configures the preprocessing pipelinebased on the estimator type:### For linear models (e.g., LogisticRegression, Ridge)- **TableVectorizer**: Uses the default configuration, except for the addition of spline-encoded datetime features by the `DatetimeEncoder`- **SimpleImputer**: Added because linear models cannot handle missing values- **SquashingScaler**: Normalizes numeric features to improve convergence andperformance- **Estimator**: The provided linear modelThis configuration ensures numeric features are properly scaled and missingvalues are handled appropriately.### For tree-based ensemble models (RandomForest, HistGradientBoosting)- **TableVectorizer**: Configured specifically for tree models - Low-cardinality categorical features: Either kept as categorical (HistGradientBoosting) or ordinal encoded (RandomForest) - High-cardinality features: StringEncoder for robust feature extraction - Datetime features: No spline encoding (unnecessary for trees)- **Scaler**: Not added (unnecessary for tree-based models)- **Estimator**: The provided tree-based estimatorThis configuration leverages the native capabilities of tree models while stillproviding effective feature engineering through the `StringEncoder`.## Customizing the pipeline::: {.callout-tip}This is unnecessary most of the time!:::::: {.fragment}```{python}from sklearn.decomposition import PCAfrom sklearn.linear_model import Ridgefrom sklearn.pipeline import make_pipelinefrom skrub import tabular_pipeline# Create a pipeline that includes two stepsmodel_pipeline = make_pipeline(PCA(n_components=20), Ridge())# Pass the new model to tabular_pipelinefull_pipeline = tabular_pipeline(model_pipeline)[name for name, _ in full_pipeline.steps]```:::## When to Use Which Approach**Use `tabular_pipeline`** if:- You need a quick baseline for benchmarking/checking if there is a signal- You want a starting point for experimentation- You don't need custom preprocessing/feature engineering**Embed a pipeline in `tabular_pipeline`** if :- You need to modify only the end of the pipeline**Use a manual pipeline** if :- You need fine-grained control over most of the transformations- Your training process includes custom preprocessing steps- You want to experiment with different transformersOr... use the skrub Data Ops! (more on that later, maybe)## Example: Complete Workflow```{.python}from sklearn.model_selection import cross_val_score# Create pipelinemodel = tabular_pipeline(LogisticRegression())# Evaluate with cross-validationscores = cross_val_score(model, X, y, cv=5)print(f"Score: {scores.mean():.4f}")```That's it! ## What we have seen in this chapter - Always use pipelines to prevent data leakage- `TableVectorizer` handles most of the feature engineering- Manual pipelines give full control- `tabular_pipeline` provides a good baseline with good defaults- Provide a model, or `"classification"` or `"regression"`