Skrub DataOps

skrub-data.org

Riccardo Cappuzzo

SODA Team - Inria Saclay

2026-10-16

Skrub

Machine learning on tabular data

Textbook ML


\(X \in \mathbb{R}^{n \times p},\ y \in \mathbb{R}^n\)

\(\hat{y} = f_{\hat{\theta}}(X)\)


estimator = TabICLRegressor()

cross_validate(estimator, X, y)

estimator.fit(X_train, y_train)
estimator.predict(X_new)

Data-Science Practice

Textbook ML


\(X \in \mathbb{R}^{n \times p},\ y \in \mathbb{R}^n\)

\(\hat{y} = f_{\hat{\theta}}(X)\)


estimator = TabICLRegressor()

cross_validate(estimator, X, y)

estimator.fit(X_train, y_train)
estimator.predict(X_new)

Data-Science Practice

Textbook ML


\(X \in \mathbb{R}^{n \times p},\ y \in \mathbb{R}^n\)

\(\hat{y} = f_{\hat{\theta}}(X)\)


estimator = TabICLRegressor()

cross_validate(estimator, X, y)

estimator.fit(X_train, y_train)
estimator.predict(X_new)

Data-Science Practice

To build a ML pipeline, we need to:

  • preprocess the data, perform feature engineering, train a model …
  • so we need to learn a state…
  • while we evaluate the predictive performance…
  • as we avoid data leakage…
  • with multi-source input …

How do we deal with that?

With Data Ops…

Data wrangling is part of the pipeline: filtering, resampling, aggregations, joins (i.e. multi-table input), …

Then, after preparing the data:

  • Cross-validate without data leaks.
  • Tune choices with validation scores.
  • Replay on new inputs.

DataOps

  • All the goodies of the scikit-learn framework: fit() & predict(), cross-validation, hyperparameter tuning, serialization.
  • Without the usual restrictions & while supporting arbitrary data processing. Multiple inputs, feature & target construction, filtering samples, dynamic arguments for CV splitters & scorers, etc.
  • And more: dynamic previews, pipeline inspection, …

Basic example

Declare the pipeline

data_path = skrub.var("data_path")
data = data_path.skb.apply_func(pd.read_csv)
X = data.drop(columns="target", errors="ignore").skb.mark_as_X()
y = data["target"].skb.mark_as_y()
pred = X.skb.apply(
    StandardScaler()
).skb.apply(LogisticRegression(), y=y)

Cross-validate

pred.skb.cross_validate(
    environment={"data_path": "historical_data.csv"}
)

Make a “learner” (object with fit() & predict())

learner = pred.skb.make_learner(
).fit(
    environment={"data_path": "historical_data.csv"}
)
learner.predict(
    environment={"data_path": "new_data.csv"}
)

Hyperparameter tuning 1/2

Tuning hyperparameters in scikit-learn can be complex…

pipe = Pipeline([("dim_reduction", PCA()), ("regressor", Ridge())])
grid = [
    {
        "dim_reduction": [PCA()],
        "dim_reduction__n_components": [10, 20, 30],
        "regressor": [Ridge()],
        "regressor__alpha": loguniform(0.1, 10.0),
    },
    {
        "dim_reduction": [SelectKBest()],
        "dim_reduction__k": [10, 20, 30],
        "regressor": [Ridge()],
        "regressor__alpha": loguniform(0.1, 10.0),
    },
    {
        "dim_reduction": [PCA()],
        "dim_reduction__n_components": [10, 20, 30],
        "regressor": [RandomForestRegressor()],
        "regressor__n_estimators": loguniform(20, 200),
    },
    {
        "dim_reduction": [SelectKBest()],
        "dim_reduction__k": [10, 20, 30],
        "regressor": [RandomForestRegressor()],
        "regressor__n_estimators": loguniform(20, 200),
    },
]

Hyperparameter tuning 2/2

With Data Ops, you can define the search space with the estimator:

dim_reduction = X.skb.apply(
    skrub.choose_from(
        {
            "PCA": PCA(n_components=skrub.choose_int(10, 30)),
            "SelectKBest": SelectKBest(k=skrub.choose_int(10, 30))
        }, name="dim_reduction"
    )
)

Choices can be made about any part of the pipeline:

df = pd.DataFrame({
    "region":  ["North", "North", "South", "South", "East", "East", "North", "South"],
    "revenue": [100.0, 225.0, 70.0, 180.0, 90.0, 300.0, 50.0, 80.0],
})
do = skrub.var("data", df)
do.groupby("region")["revenue"].agg(skrub.choose_from(["mean", "sum", "max"]))

Debug the entire plan with the report

Data Ops go beyond tabular data!

Data Ops make no assumption about the underlying data, or code.

In conclusion

  • Data science is harder than what you learn in classes
  • A full ML pipeline involves preprocessing, feature engineering and model training
  • We want to learn a “state” (it’s called machine learning after all), evaluate performance and do so while avoiding data leakage
  • Data Ops are a framework that allows to build stateful pipelines for arbitrary code and inputs
  • Data Ops extend the scikit-learn fit predict paradigm to multi-table inputs, feature and target construction, sample filtering …
  • A Data Ops graph can be exported as a Learner, a single object that includes all learned states to work on new data