Skip to content

Auguste Baum ·

What’s new in skore lib: July 2026 update

At Probabl, we are developing Skore, the Tabular AI platform for teams that ship machine learning models with confidence. One of its components is skore lib, a Python library under the MIT license that wraps your data science pipelines to reduce boilerplate and guard against classic pitfalls. Below I share technical updates from July.

Skore lib in a nutshell

Before I dive into the latest technical updates, I’d like to say some words about why we’re building skore lib.

Notebooks (Jupyter and others) let you run code interactively, in any order. That flexibility has a cost: you can train a model in a cell, delete that cell, and the model object persists in memory. Five cells later, you might have forgotten which data the model was trained with.

This is where methodology meets tool design. skore lib’s EstimatorReport enforces a simple practice: it keeps the estimator and its training data together. You can’t separate them, so you can’t lose the link. That design choice brings several benefits. Since the data and estimator are bundled together, it is possible to automate model evaluation (e.g. classic metrics and plots).

For users, this means fewer lines of code, which leaves fewer places for bugs. Similarly, it is common to store results to disk or remote storage to counteract the volatility of notebooks. skore lib helps with this by exposing a simple API with different backends, including disk storage, MLFlow instances and Skore, Probabl’s Tabular AI platform.

Good practices in data science go beyond “save every model properly.” Checking for overfitting, spotting correlated features, validating on holdout data: these are patterns that recur but get implemented from scratch each time. These checks are built into skore lib, so the methodology becomes the default path instead of extra work.

This applies to human data scientists and to agents. An agent using skore lib inherits the same checks and organization without needing separate instructions for each project. The tool carries the methodology with it. Every run is versioned, audited, and reproducible. In short, skore gives you the confidence to move fast with AI and the proof it worked.

Without further ado, here are the latest updates in skore lib. They can also be found in skore lib’s official documentation.

New in skore lib: July update

Without further ado, here are the latest updates in skore lib. They can also be found in skore lib’s official documentation.

summarize().frame() is now a long-format table

The default format of report.metrics.summarize().frame() is now long-format rather than wide-format. It is now easier to retrieve data from the default DataFrame since its index is no longer a pandas MultiIndex. See #3094 by @glemaitre.

metrics = report.metrics.summarize().frame()

# before
metrics.loc["Accuracy"].iloc[0, 0]

# after
metrics.loc["accuracy"]

metrics.summarize() now catches failing metrics

report.metrics.summarize() no longer aborts the whole computation if one of the metrics raised (e.g. if a custom scorer encounters an edge case). Instead, exceptions are caught and shown as warnings, and the output DataFrame has NaN for failed metrics. See #3124 by @auguste-probabl.

def fail(y_true, y_pred):
    return 1 / 0

report.metrics.add(fail)
report.metrics.summarize().frame()
# # before
# ZeroDivisionError: division by zero
#
# # after
# UserWarning: Metric 'fail' has failed: ZeroDivisionError('division by zero')
# fail                 NaN
# accuracy        0.925000
# precision_0     1.000000
# ...

Custom metric methods are now shown in .help()

Metrics added via report.metrics.add(…) were invisible to report.metrics.help(), since they are defined dynamically. They are now listed alongside the built-ins. See #3139 by @auguste-probabl.

report.metrics.add(lambda estimator, X, y: 1, name="custom")
report.metrics.help()
# ╭────────────────────────────────── Metrics accessor ──────────────────────────────────╮
# │ EstimatorReport                                                                      │
# │ └── .metrics                                                                         │
# │     ├── .accuracy(...)             - Accuracy classification score.                  │
# │     ...                                                                              │
# │     ├── .custom(...)               - Custom                                          │
# │     ...                                                                              │

Pipelines no longer get a spurious score metric in the summary

skore used to always include a score metric in the summary sklearn Pipeline estimators. It now inspects the Pipeline’s last step to recover the default score. See #3110 by @jeromedockes.

report = skore.evaluate(make_pipeline(PCA(), RandomForestClassifier()), X, y)
report.metrics.summarize().frame(flat_index=False, verbose_name=True)
# # before
# Score        ...
# Accuracy     ...
# ...
#
# # after
# Accuracy     ...
# ...

prediction_error(data_source=”both”) is now officially supported

CrossValidationReport.metrics.prediction_error(data_source=”both”) has worked for a long time, but it was not documented, and in fact its legend was broken. This is now fixed. See #3154 by @direkkakkar319-ops.

CrossValidationReport.metrics.summarize() no longer crashes with n_jobs set

Computing a summary with process-based parallelism (n_jobs > 1) used to trigger infinite recursion. See #3178 by @glemaitre.

Baseline checks now support multi-output regression

Appropriate dummy/fast/performance baselines have been added to support this ML task. See #3116 by @GaetandeCast.

report = skore.evaluate(DummyRegressor(), X, y_multioutput, splitter=3)
report.checks.summarize().frame(section="issue")["code"]
# # before
# CheckNotApplicable: Unsupported ML task. Supported tasks are: binary-classification,
# multiclass-classification, regression. Got multioutput-regression.
#
# # after
# 1    SKD002   # underfits vs. baseline
# 8    SKD009   # worse than baseline

report.checks no longer loses column names after preprocessing

When a sklearn Pipeline’s preprocessing output a plain numpy array, the data-quality checks used generic column labels in their explanations. Column names are now retrieved from the pipeline’s final step, so check explanations are clearer. See #3155 by @GaetandeCast.

report = skore.evaluate(
    make_pipeline(StandardScaler(), LinearRegression()),
    pd.DataFrame(X, columns=["col_0", "col_1", "col_2"]),
    y,
)
report.checks.summarize()
# # before
# "A model trained on feature(s) ['Feature 0', 'Feature 1'] alone has similar
# performance to a model trained on all the features..."
#
# # after
# "A model trained on feature(s) ['col_0', 'col_1'] alone has similar
# performance to a model trained on all the features..."

project.put() on skore Hub is now faster

put() no longer computes SVGs for TableReport plots, thanks to improvements in skrub 0.10. This makes put() up to 35% faster. Note that the minimum supported version of skrub is now 0.10. See #3138 by @auguste-probabl.

project.summarize() no longer silently truncates the list of reports

Listing reports from the Hub now returns all reports, rather than the 500 first ones. See #3125 and #3164 by @thomass-dev.

Teamwork makes the dream work!

Thanks to the following contributors for their work this month (in no particular order):

  • @glemaitre
  • @thomass-dev
  • @GaetandeCast
  • @auguste-probabl
  • @jeromedockes
  • @direkkakkar319-ops
  • @rouk1
Portrait of Auguste Baum

Auguste Baum

Software Engineer @ Probabl

Auguste Baum on LinkedIn

Auguste Baum is a Software Engineer at Probabl, working on skore lib, the open source Python library behind Skore. Previously co-founder and CTO of the startup Resilio, Auguste is based in Paris and holds an MSc in Data Science from EPFL.

News on Skore, research on Tabular AI, and upcoming events from the Probabl team.