<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://blog.scikit-learn.org/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.scikit-learn.org/" rel="alternate" type="text/html" /><updated>2026-10-09T15:02:29+00:00</updated><id>https://blog.scikit-learn.org/feed.xml</id><title type="html">scikit-learn Blog</title><subtitle>The official blog of scikit-learn, an open source library for machine learning in Python.</subtitle><author><name>{&quot;bio&quot;=&gt;&quot;Open source library for machine learning in Python.&quot;, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github-square&quot;, &quot;url&quot;=&gt;&quot;https://github.com/scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;LinkedIn&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-linkedin&quot;, &quot;url&quot;=&gt;&quot;https://linkedin.com/company/scikit-learn/&quot;}, {&quot;label&quot;=&gt;&quot;Bluesky&quot;, &quot;icon&quot;=&gt;&quot;&quot;, &quot;url&quot;=&gt;&quot;https://bsky.app/profile/scikit-learn.org&quot;}, {&quot;label&quot;=&gt;&quot;Mastodon&quot;, &quot;icon&quot;=&gt;&quot;fab fa-brands fa-mastodon&quot;, &quot;url&quot;=&gt;&quot;https://fosstodon.org/@sklearn&quot;}, {&quot;label&quot;=&gt;&quot;YouTube&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-youtube&quot;, &quot;url&quot;=&gt;&quot;https://www.youtube.com/@scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;Facebook&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-facebook-square&quot;, &quot;url&quot;=&gt;&quot;https://facebook.com/scikitlearnofficial/&quot;}, {&quot;label&quot;=&gt;&quot;Instagram&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-instagram&quot;, &quot;url&quot;=&gt;&quot;https://instagram.com/scikitlearnofficial/&quot;}]}</name></author><entry><title type="html">Community Voices: Interview with Lucy Liu, scikit-learn core maintainer</title><link href="https://blog.scikit-learn.org/team/community-voices-lucy/" rel="alternate" type="text/html" title="Community Voices: Interview with Lucy Liu, scikit-learn core maintainer" /><published>2026-09-23T00:00:00+00:00</published><updated>2026-09-23T00:00:00+00:00</updated><id>https://blog.scikit-learn.org/team/community-voices-lucy</id><content type="html" xml:base="https://blog.scikit-learn.org/team/community-voices-lucy/"><![CDATA[<div>
  <img src="/assets/images/posts_images/" alt="" />
  

  
  
  
  

  

  

Author:  
      <a itemprop="sameAs" content="https://github.com/ccosborne" href="https://github.com/ccosborne" rel="me noopener noreferrer" style="vertical-align:top;"><img src="/assets/images/author_images/cailean-osborne.png" style="width:1em;margin-right:.5em;border-radius: 50%;" alt="Author Icon" class="orcid-icon" />Cailean Osborne</a>
      
        <a href="mailto:cailean@probabl.ai" title="cailean@probabl.ai"><span><i class="elastic-fai fas fa-envelope"></i></span></a>
      

<br /><br />

</div>

<p><em>This post was originally published on the <a href="https://blog.probabl.ai/community-voices-lucy-liu">Probabl blog</a>.</em></p>

<p>scikit-learn is one of the most widely used tools in data science, counting over 200 million downloads every month. You may know it as the Python library, but behind the code there is a global community that develops, maintains, and sustains it for the benefit of all data scientists all over the world.</p>

<p>Community Voices is an interview series where we introduce you to members of this community – maintainers, contributors, educators, community-builders, and many others. Each month we’ll sit down with a different person to hear how they got involved in scikit-learn, what they’re working on, what they’re excited about, and how newcomers can get involved.</p>

<p>Community Voices continues Reshama Shaikh’s (<a href="https://github.com/reshamas"><code class="language-plaintext highlighter-rouge">@reshamas</code></a>) interviews with scikit-learn contributors, which have been published on the <a href="https://blog.scikit-learn.org">scikit-learn.org blog</a> since 2017. Reshama no longer has the time to continue these interviews and, after syncing with her, we decided to jump in and continue her tradition.Thank you, Reshama, for all your work over the years — we’re honored to pick up where you left off!</p>

<h2 id="interview-with-lucy-liu">Interview with Lucy Liu</h2>

<p>To kick off Community Voices , we’re delighted to speak with Lucy Liu (<a href="https://github.com/lucyleeow"><code class="language-plaintext highlighter-rouge">@lucyleeow</code></a>), a scikit-learn core maintainer and software engineer at Quansight Labs. Lucy has led much of the work bringing array API support to scikit-learn. Longtime readers of the scikit-learn blog will recognize her: <a href="https://blog.scikit-learn.org/team/lucy-interview/">Reshama interviewed Lucy</a> back in 2022, and Lucy published an <a href="https://blog.scikit-learn.org/updates/update-array-api/">update about array API adoption in scikit-learn</a> in March this year.</p>

<p>So it’s a pleasure to catch up with Lucy and hear about what she’s working on now.</p>

<p><strong>Cailean:</strong> Hi Lucy! Please tell us a bit about yourself.</p>

<p><strong>Lucy:</strong> I currently live in Australia and am a software engineer at Quansight Labs. I primarily work on scikit-learn but also contribute to or have contributed to Sphinx-Gallery, array-api-strict and napari. My introduction to programming came through R, which I used for bioinformatics research during my master’s degree. It became clear to me fairly early on that I was more interested in software and tool development than biomedical science. Luckily I was able to transition to more software focused roles. At Quansight Labs I get to work alongside many other maintainers in the scientific python ecosystem, helping improve the software that researchers and data scientists rely on.</p>

<p>GitHub: <a href="https://github.com/lucyleeow"><code class="language-plaintext highlighter-rouge">@lucyleeow</code></a>
LinkedIn: <a href="https://www.linkedin.com/in/lucy-jp-liu/"><code class="language-plaintext highlighter-rouge">@lucy-jp-liu</code></a></p>

<p><strong>Cailean:</strong> How did you first get involved in scikit-learn?</p>

<p><strong>Lucy:</strong> Unlike many contributors who were users first, I started working on scikit-learn via my role at INRIA, where many scikit-learn core developers used to work. My role involved working on <a href="https://www.ramp.studio/">RAMP</a>, a platform for collaborative data science, and contributing to open source. I saw the latter as an amazing opportunity to both contribute to the ecosystem and learn from talented open source maintainers, particularly as I had only authored small solo packages previously.</p>

<p>I started with contributing to Sphinx-Gallery, which was a great introduction as it is a small project. Later, I also began contributing to scikit-learn, where I could combine my interests in statistics and software engineering. I’ve continued maintaining both projects ever since.</p>

<p><strong>Cailean:</strong> How would you explain the value of scikit-learn for data scientists to a non-technical reader?</p>

<p><strong>Lucy:</strong> scikit-learn offers a complete toolkit for the data analysis pipeline, from data preprocessing to model training, model evaluation, and visualization. There are three things, in my view, that make it valuable.</p>

<p>First, the documentation, which provides clear explanations, sound guidance, and useful references.</p>

<p>Second, its judicious balance of choice and flexibility. scikit-learn has been very deliberate about what is included, favoring algorithms that are old enough to be stable and cited often enough to be broadly considered reliable, standard methods. This avoids overwhelming the user with choice, while still providing an ecosystem of extensions (e.g., scikit-learn-extra) for niche and expert needs.</p>

<p>Finally, it is thoroughly tried and tested. The large user base, long history, and dedicated maintainers means that most bugs have been fixed or at the very least documented.</p>

<p><strong>Cailean:</strong> Tell us about a scikit-learn feature that you’ve developed and that you’re proud of. What is it and why does it matter for data scientists?</p>

<p><strong>Lucy:</strong> This would definitely be adding array API support to scikit-learn metrics and estimators. scikit-learn was originally written for NumPy which is geared towards single-core CPU execution. With array API support however, users can pass arrays from any array library implementing the standard, including PyTorch and CuPy. This makes scikit-learn more flexible, allowing users to benefit from array library features, namely GPU acceleration, with almost no change in their code.</p>

<p>Since this work spans much of the codebase, it has prompted us to look at the code holistically and make improvements beyond array API support. It has led to refactoring, increased consistency and improved testing structure. Although these improvements are not always visible to users (and are rarely glamorous), it’s invaluable for keeping a large, long-live project like scikit-learn healthy over the long term.</p>

<p><strong>Cailean:</strong> What’s your top priority for the coming year that data scientists should watch out for?</p>

<p><strong>Lucy:</strong> Continued work on adding array API support, particularly around testing infrastructure and defining consistent and predictable behavior when arrays come from different libraries. For example, for cost efficiency a user may want to train a model on a GPU-backed array but use a CPU-backed array to make predictions. The goal is to make scikit-learn more flexible while ensuring its behavior remains predictable and unsurprising.</p>

<p><strong>Cailean:</strong> I know an important topic for you is the community and supporting contributors. Could you share what you think it means to have a healthy open source community and how you’re going about that in scikit-learn?</p>

<p><strong>Lucy:</strong> Every open source community looks different, but in scikit-learn I believe a healthy community is one that supports and mentors new contributors, some of whom eventually become maintainers themselves. This ongoing growth is essential, as maintainers naturally move on over time - whether they finish their PhD, take on new commitments, or their interests shift elsewhere.</p>

<p>Now that LLMs have made opening pull requests (PRs) quite easy, it’s become clear that we need to be more intentional in identifying people who are genuinely interested in contributing to the scikit-learn community. This is something we are still grappling with, similar to many other open source projects.</p>

<p>We have spent more time thinking about what we want the contributor pipeline to look like and have made several changes to support this. This includes updating our contributing documentation to highlight the value of non-code contributions and encourage contributors to work on issues they genuinely care about, instead of “good first issues” which don’t arise often. Contributing to a large project often requires significant effort and waiting for reviews, so we think it’s better when contributors are motivated by the problem they are solving. We have also clarified which issues are ready for contributions and added a section to our PR template where new contributors can introduce themselves. This helps us build relationships with human contributors, and minimize time spent on unsupervised LLM-generated contributions.</p>

<p><strong>Cailean:</strong> If you could make 1 recommendation to a new contributor seeking to get involved in the scikit-learn community today, what would it be?</p>

<p><strong>Lucy:</strong> Take some time to review pull requests (PRs)! It is a great way to learn the project’s norms, both in terms of the codebase and community interactions. It also helps you appreciate the effort involved in reviewing PRs and understand how you can make the process easier for reviewers as an author.</p>

<h2 id="contribute-to-community-voices">Contribute to Community Voices!</h2>
<p>Community Voices celebrates all contributors to scikit-learn – present and past, technical and non-technical. If you’d like to contribute, please go ahead and get in touch by creating an issue in https://github.com/scikit-learn/blog/issues</p>]]></content><author><name>{&quot;bio&quot;=&gt;&quot;Open source library for machine learning in Python.&quot;, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github-square&quot;, &quot;url&quot;=&gt;&quot;https://github.com/scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;LinkedIn&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-linkedin&quot;, &quot;url&quot;=&gt;&quot;https://linkedin.com/company/scikit-learn/&quot;}, {&quot;label&quot;=&gt;&quot;Bluesky&quot;, &quot;icon&quot;=&gt;&quot;&quot;, &quot;url&quot;=&gt;&quot;https://bsky.app/profile/scikit-learn.org&quot;}, {&quot;label&quot;=&gt;&quot;Mastodon&quot;, &quot;icon&quot;=&gt;&quot;fab fa-brands fa-mastodon&quot;, &quot;url&quot;=&gt;&quot;https://fosstodon.org/@sklearn&quot;}, {&quot;label&quot;=&gt;&quot;YouTube&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-youtube&quot;, &quot;url&quot;=&gt;&quot;https://www.youtube.com/@scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;Facebook&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-facebook-square&quot;, &quot;url&quot;=&gt;&quot;https://facebook.com/scikitlearnofficial/&quot;}, {&quot;label&quot;=&gt;&quot;Instagram&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-instagram&quot;, &quot;url&quot;=&gt;&quot;https://instagram.com/scikitlearnofficial/&quot;}]}</name></author><category term="Team" /><category term="Open Source" /><category term="Machine Learning" /><category term="Community" /><summary type="html"><![CDATA[Author: Cailean Osborne]]></summary></entry><entry><title type="html">An Update on Metadata Routing</title><link href="https://blog.scikit-learn.org/updates/update-on-metadata-routing/" rel="alternate" type="text/html" title="An Update on Metadata Routing" /><published>2026-08-25T00:00:00+00:00</published><updated>2026-08-25T00:00:00+00:00</updated><id>https://blog.scikit-learn.org/updates/update-on-metadata-routing</id><content type="html" xml:base="https://blog.scikit-learn.org/updates/update-on-metadata-routing/"><![CDATA[<div>
  

  
  
  
  

  

  

Author:  
      <a itemprop="sameAs" content="https://github.com/StefanieSenger" href="https://github.com/StefanieSenger" rel="me noopener noreferrer" style="vertical-align:top;"><img src="/assets/images/author_images/stefanie_senger.jpg" style="width:1em;margin-right:.5em;border-radius: 50%;" alt="Author Icon" class="orcid-icon" />Stefanie Senger</a>
     

<br /><br />

</div>
<p><em>This blog post is a cross-post of a <a href="https://blog.probabl.ai/update-on-scikit-learn-metadata-routing-api">Probabl blog post</a> and based on a <a href="https://www.youtube.com/watch?v=7gWsV9hdQCc&amp;list=PLYqi92iCr_sU&amp;t=2478">talk</a> given at EuroSciPy 2026 in Kraków (<a href="https://github.com/StefanieSenger/Talks/blob/main/2026_Update_on_Metadata_Routing/Update%20on%20Metadata%20Routing.pdf">slides</a>).</em></p>

<p>Metadata routing has been introduced gradually in experimental mode since scikit-learn
1.3; coverage is now almost complete, and the feature is mature enough that users can
use it in real workflows.</p>

<h2 id="what-is-metadata-routing">What is metadata routing?</h2>

<p>In scikit-learn, <strong>metadata</strong> is data you want to apply <em>on top of</em> your tabular
features and your target. It influences how a function treats <code class="language-plaintext highlighter-rouge">X</code> and <code class="language-plaintext highlighter-rouge">y</code>.</p>

<p>You may be familiar with two common kinds of metadata from scikit-learn: <code class="language-plaintext highlighter-rouge">sample_weight</code>
and <code class="language-plaintext highlighter-rouge">groups</code>. In addition to these, libraries such as <a href="https://fairlearn.org">fairlearn</a>
expose their own kinds of metadata, and you can define custom metadata to be used in
business logic, for instance. The benefit of using metadata is usually not a higher
score on the model, but a <strong>more realistic or better tuned model</strong> to begin with.</p>

<p><strong>Routing</strong> is the mechanism that passes that metadata between several components of a
pipeline to where it is finally used (“consumed”). Before the routing API, using
metadata was only possible in limited cases. With routing enabled, you can pass
<code class="language-plaintext highlighter-rouge">sample_weight</code> and <code class="language-plaintext highlighter-rouge">groups</code> through nested meta-estimators, combine third-party objects
with scikit-learn estimators while still forwarding their metadata, and define custom
metrics, scorers, and estimators that consume metadata you invent yourself.</p>

<table>
  <thead>
    <tr>
      <th>Without routing (<code class="language-plaintext highlighter-rouge">enable_metadata_routing=False</code>, the default)</th>
      <th>With routing (<code class="language-plaintext highlighter-rouge">enable_metadata_routing=True</code>)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Restricted use of <code class="language-plaintext highlighter-rouge">sample_weight</code> and <code class="language-plaintext highlighter-rouge">groups</code></td>
      <td><code class="language-plaintext highlighter-rouge">sample_weight</code> and <code class="language-plaintext highlighter-rouge">groups</code> can be used in nested structures</td>
    </tr>
    <tr>
      <td>Metadata from other libraries cannot be passed through scikit-learn objects</td>
      <td>scikit-learn objects can route metadata to objects from other libraries</td>
    </tr>
    <tr>
      <td>Local use only of custom metadata</td>
      <td>Custom metadata can be routed to custom functions and methods</td>
    </tr>
  </tbody>
</table>

<p>The Metadata Routing API is a potent and flexible tool that allows users to define in
detail where their metadata gets used. It enables new use cases and enhances
interoperability with third-party libraries. The adoption of the routing API is
spreading in the ecosystem, for example in <a href="https://fairlearn.org">fairlearn</a>,
<a href="https://imbalanced-learn.org/stable">imbalanced-learn</a>,
<a href="https://github.com/scikit-adaptation/skada">skada</a>,
<a href="https://skorch.readthedocs.io">skorch</a>, and <a href="https://skfolio.org">skfolio</a>.</p>

<h2 id="metadata-in-the-wild">Metadata in the wild</h2>

<p>Let’s walk through an example.</p>

<p>Imagine a medical study on the effectiveness of a new treatment. Here we have
observational data that is getting used in that study. Features include “sex”, “age”,
“severity”, and whether a patient received a medication; the target is the “recovery
time”. This data is naturally biased, because it does <em>not</em> come from a randomized
trial. It entails all the imbalance and structure that real world data usually implies.</p>

<p><img src="/assets/images/posts_images/fig01_hospital_groups.png" alt="Hospital-grouped patient table: features and recovery-time target, with patients
tagged by hospital" /></p>

<p>Figure 1: Table of data and target for our example study.</p>

<p>Patients come from different hospitals that differ in systematic factors such as medical
devices, policies, and the socioeconomic mix of patients. A sample’s provenance from a
certain hospital is useful for evaluation, but it is not a feature we want the model to
treat like “age” or “severity”. Instead we keep it as <strong>groups</strong> with shape
<code class="language-plaintext highlighter-rouge">(n_samples,)</code>, but separate from <code class="language-plaintext highlighter-rouge">X</code>.</p>

<p><img src="/assets/images/posts_images/fig02_groups_as_metadata.png" alt="Same table with an explicit groups column (Hospital: Blue / Black / Orange) beside
data and target" /></p>

<p>Figure 2: Table of data and target with an additional <code class="language-plaintext highlighter-rouge">groups</code> metadata.</p>

<p>During cross-validation we want a realistic estimate of how well a model can generalize.
If samples from the same hospital appear in both the training and validation fold, the
model can look better than it will on a new hospital, which is a form of <a href="https://en.wikipedia.org/wiki/Leakage_(machine_learning)">data
leakage</a>.</p>

<p>Instead of allowing data to be leaked, we use the metadata <strong>groups</strong> that we pass into
cross-validation. scikit-learn’s <code class="language-plaintext highlighter-rouge">GroupKFold</code> keeps each group entirely in either the
train set <em>or</em> the validation set for a given fold:</p>

<p><img src="/assets/images/posts_images/fig03_groupkfold.png" alt="GroupKFold diagram: three folds where each hospital group is wholly in train or
validation" /></p>

<p>Figure 3: Training and validation set after splitting with <code class="language-plaintext highlighter-rouge">GroupKFold</code>.</p>

<p>Passing <code class="language-plaintext highlighter-rouge">groups</code> into <code class="language-plaintext highlighter-rouge">cross_validate</code> together with a grouped splitter has worked in
scikit-learn for a long time and keeps functioning the same way:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">GroupKFold</span><span class="p">,</span> <span class="n">cross_validate</span>
<span class="kn">from</span> <span class="nn">sklearn.linear_model</span> <span class="kn">import</span> <span class="n">Ridge</span>

<span class="n">ridge</span> <span class="o">=</span> <span class="n">Ridge</span><span class="p">()</span>
<span class="n">cv</span> <span class="o">=</span> <span class="n">GroupKFold</span><span class="p">(</span><span class="n">n_splits</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="n">cross_validate</span><span class="p">(</span><span class="n">ridge</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">cv</span><span class="o">=</span><span class="n">cv</span><span class="p">,</span> <span class="n">groups</span><span class="o">=</span><span class="n">groups</span><span class="p">)</span>
</code></pre></div></div>

<p>For our patient data set, <code class="language-plaintext highlighter-rouge">sample_weight</code> draws the model’s attention toward (or away
from) particular samples. It can be used if biases refer to how features are distributed
or relate to one another. For instance, if we suspect that race, age or socioeconomic
status of a patient determined if they got the new treatment at all, <code class="language-plaintext highlighter-rouge">sample_weight</code> can
re-balance the over- or under-representation of a certain group of patients and draw the
model to emphasize reducing training error on the higher weighted samples more.</p>

<p>One method to determine <code class="language-plaintext highlighter-rouge">sample_weight</code> values is inverse probability of treatment
weighting (IPTW) in observational studies (see Florian Wilhelm, <a href="https://florianwilhelm.info/2017/04/causal_inference_propensity_score/">Causal Inference and
Propensity Score
Methods</a>
(walkthrough with scikit-learn)). Probabl Whiteboard Series has also published an
exploration on the usefulness of <code class="language-plaintext highlighter-rouge">sample_weight</code> from a different angle (see <a href="https://www.youtube.com/watch?v=REIg5NH2SNc">Improving
models via subsets</a>).</p>

<p>In practice, since <code class="language-plaintext highlighter-rouge">Ridge.fit</code> can consume <code class="language-plaintext highlighter-rouge">sample_weight</code>, you might reasonably try:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cross_validate</span><span class="p">(</span><span class="n">ridge</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">cv</span><span class="o">=</span><span class="n">cv</span><span class="p">,</span> <span class="n">sample_weight</span><span class="o">=</span><span class="n">sample_weight</span><span class="p">)</span>
</code></pre></div></div>

<p>…and hit a wall:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>TypeError: got an unexpected keyword argument 'sample_weight'
</code></pre></div></div>

<p>In practice you often nest further. Maybe you want to <code class="language-plaintext highlighter-rouge">cross_validate</code> around a
<code class="language-plaintext highlighter-rouge">GridSearchCV</code> that tunes <code class="language-plaintext highlighter-rouge">Ridge</code>, with a scorer that can also take <code class="language-plaintext highlighter-rouge">sample_weight</code> and
a <code class="language-plaintext highlighter-rouge">GroupKFold</code> that needs <code class="language-plaintext highlighter-rouge">groups</code>. Before routing, that stack failed: <code class="language-plaintext highlighter-rouge">cross_validate</code>
had no way to forward <code class="language-plaintext highlighter-rouge">sample_weight</code> into the nested <code class="language-plaintext highlighter-rouge">fit</code> and <code class="language-plaintext highlighter-rouge">score</code> calls, even
though those methods support it. The same limitation blocked metadata from many
third-party libraries when combined with scikit-learn’s cross-validation tools.</p>

<p>If we want fairer, less leaky models to predict the treatment effect for future
patients, we need metadata to move through several layers of other tools by contract.
Metadata Routing API was built to bridge exactly this gap: you can use it to get your
metadata to be used inside the functions that consume it.</p>

<h2 id="using-the-metadata-routing-api">Using the metadata routing API</h2>

<p>With metadata routing, the code stays close to what you already know. The orange boxed
snippets show you what you need to add to take advantage of the routing in experimental
mode:</p>

<p><img src="/assets/images/posts_images/fig04_routing_api.png" alt="Slide showing the three routing steps: enable metadata routing, pass metadata at the
top level, and set requests where metadata is
consumed" /></p>

<p>Figure 4: The three metadata routing steps: enable, pass at the top, request metadata
where it gets used. See <a href="https://scikit-learn.org/stable/metadata_routing.html">Metadata Routing in scikit-learn User
Guide</a> for a full example.</p>

<ol>
  <li><strong>Enable</strong> the experimental feature. <code class="language-plaintext highlighter-rouge">set_config(enable_metadata_routing=True)</code> turns
routing on. Disable it when you no longer need it.</li>
  <li><strong>Pass</strong> metadata once at the top-level tool (here <code class="language-plaintext highlighter-rouge">cross_validate</code>). That top-level
object could also be a <code class="language-plaintext highlighter-rouge">Pipeline</code> or a meta-estimator (an estimator that takes
another estimator as an argument).</li>
  <li><strong>Request</strong> metadata where it should be consumed, with <code class="language-plaintext highlighter-rouge">set_*_request</code>
(<code class="language-plaintext highlighter-rouge">set_fit_request</code>, <code class="language-plaintext highlighter-rouge">set_score_request</code>, and so on). Grouped splitters such as
<code class="language-plaintext highlighter-rouge">GroupKFold</code> already request <code class="language-plaintext highlighter-rouge">groups</code> by design, so you do not set that yourself.</li>
</ol>

<p>In experimental mode, users need to use <code class="language-plaintext highlighter-rouge">set_*_request</code> methods everywhere a metadata
can be consumed. These methods exist to grant users maximum flexibility. In future
releases, these will come with default settings, so that users in the most common use
cases don’t need to touch them anymore.</p>

<p>This is the core mental model: <strong>pass at the top, request at the leaves</strong>.</p>

<h2 id="pipelines-that-transform-validation-sets">Pipelines that transform validation sets</h2>

<p>Metadata routing also unlocks a new feature that was impossible before and rescues data
scientists from awkward workarounds: <strong>validation sets that are transformed alongside
<code class="language-plaintext highlighter-rouge">X</code></strong> in a <code class="language-plaintext highlighter-rouge">Pipeline</code>.</p>

<p>Some estimators such as <code class="language-plaintext highlighter-rouge">HistGradientBoostingClassifier</code> can split off a validation set
<em>inside</em> <code class="language-plaintext highlighter-rouge">fit</code> for validating early stopping. If used in a <code class="language-plaintext highlighter-rouge">Pipeline</code> with preprocessing
steps that were applied on the full matrix, that internal split leaks information from
the train set into the validation set. Validation data should be split <em>before</em>
transformation, then run through the same steps as training <code class="language-plaintext highlighter-rouge">X</code>.</p>

<p><code class="language-plaintext highlighter-rouge">Pipeline</code>’s <code class="language-plaintext highlighter-rouge">transform_input</code> parameter (introduced in version 1.6) allows users to
define metadata that should be transformed along with <code class="language-plaintext highlighter-rouge">X</code> until a step consumes it.
<a href="https://lightgbm.readthedocs.io/en/latest/index.html">LightGBM</a> estimators are now
compatible with this API. <a href="https://xgboost.readthedocs.io/en/stable">XGBoost</a> does not
support <code class="language-plaintext highlighter-rouge">transform_input</code> yet at the time of writing.</p>

<p>The new feature allows users to pass a validation set of their liking through a
<code class="language-plaintext highlighter-rouge">Pipeline</code>, for instance by performing a <code class="language-plaintext highlighter-rouge">train_test_split</code> beforehand:</p>

<p><img src="/assets/images/posts_images/fig05_transform_input.png" alt="Pipeline with transform_input=['X_val'] and
HistGradientBoostingClassifier.set_fit_request(X_val=True,
y_val=True)" /></p>

<p>Figure 5: Passing <code class="language-plaintext highlighter-rouge">X_val</code> through a <code class="language-plaintext highlighter-rouge">Pipeline</code> with <code class="language-plaintext highlighter-rouge">transform_input</code> for early
stopping.</p>

<p>Here <code class="language-plaintext highlighter-rouge">X_val</code> is transformed like <code class="language-plaintext highlighter-rouge">X_train</code> at every pipeline step until
<code class="language-plaintext highlighter-rouge">HistGradientBoostingClassifier.fit</code> consumes it for early stopping.</p>

<h2 id="recent-updates-and-ongoing-work">Recent updates and ongoing work</h2>

<p>Metadata routing is still experimental, but it is pretty mature in practice. On top of
the pure routing, we continue developing features based on the metadata routing
mechanism. Some are already implemented; others are still in progress:</p>

<p>Already available since 1.9:</p>
<ul>
  <li><code class="language-plaintext highlighter-rouge">TargetEncoder</code> can use grouped splitters
(<a href="https://github.com/scikit-learn/scikit-learn/pull/33089">#33089</a>)</li>
</ul>

<p>In progress:</p>
<ul>
  <li>Default requests, so users don’t need explicit <code class="language-plaintext highlighter-rouge">set_*_request</code> for common cases
(<a href="https://github.com/scikit-learn/scikit-learn/issues/31413">#31413</a>)</li>
  <li>Callbacks (e.g. <code class="language-plaintext highlighter-rouge">ScoringMonitor</code>) can accept metadata such as <code class="language-plaintext highlighter-rouge">X_val</code> and
<code class="language-plaintext highlighter-rouge">y_val</code> (<a href="https://github.com/scikit-learn/scikit-learn/issues/34137">#34137</a>)</li>
  <li>Developer API for customised metadata requests in consumers
(<a href="https://github.com/scikit-learn/scikit-learn/issues/34314">#34314</a>) (for further
information see <a href="https://scikit-learn.org/stable/auto_examples/miscellaneous/plot_metadata_routing.html">Developing estimators compliant with metadata
routing</a>)</li>
  <li>Visualization and debugging tools for metadata routing
(<a href="https://github.com/scikit-learn/scikit-learn/issues/31535">#31535</a>)</li>
</ul>

<p>Once Metadata Routing gets released as a stable feature, the user’s code will look as
simple as it always was for default cases, except we can now pass metadata and it will
be used internally.</p>

<h2 id="takeaway">Takeaway</h2>

<p>Metadata routing turns “please somehow get this array into the right nested
<code class="language-plaintext highlighter-rouge">fit</code>/<code class="language-plaintext highlighter-rouge">predict</code>/<code class="language-plaintext highlighter-rouge">score</code> call” into a deliberate contract: pass values at the top and
request them where they are consumed. This unlocks many new use cases and a tighter
integration of scikit-learn compatible libraries in the ecosystem. The API is still
experimental, but worth trying if your real data is grouped, weighted, or otherwise
richer than <code class="language-plaintext highlighter-rouge">(X, y)</code>.</p>

<h2 id="acknowledgements">Acknowledgements</h2>

<p>I would like to thank <a href="https://github.com/adrinjalali">Adrin Jalali</a>, without whose consistent work on Metadata Routing, this feature wouldn’t exist.</p>]]></content><author><name>{&quot;bio&quot;=&gt;&quot;Open source library for machine learning in Python.&quot;, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github-square&quot;, &quot;url&quot;=&gt;&quot;https://github.com/scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;LinkedIn&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-linkedin&quot;, &quot;url&quot;=&gt;&quot;https://linkedin.com/company/scikit-learn/&quot;}, {&quot;label&quot;=&gt;&quot;Bluesky&quot;, &quot;icon&quot;=&gt;&quot;&quot;, &quot;url&quot;=&gt;&quot;https://bsky.app/profile/scikit-learn.org&quot;}, {&quot;label&quot;=&gt;&quot;Mastodon&quot;, &quot;icon&quot;=&gt;&quot;fab fa-brands fa-mastodon&quot;, &quot;url&quot;=&gt;&quot;https://fosstodon.org/@sklearn&quot;}, {&quot;label&quot;=&gt;&quot;YouTube&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-youtube&quot;, &quot;url&quot;=&gt;&quot;https://www.youtube.com/@scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;Facebook&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-facebook-square&quot;, &quot;url&quot;=&gt;&quot;https://facebook.com/scikitlearnofficial/&quot;}, {&quot;label&quot;=&gt;&quot;Instagram&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-instagram&quot;, &quot;url&quot;=&gt;&quot;https://instagram.com/scikitlearnofficial/&quot;}]}</name></author><category term="Updates" /><category term="Metadata Routing" /><category term="New Feature" /><category term="API" /><category term="Machine Learning" /><summary type="html"><![CDATA[Author: Stefanie Senger This blog post is a cross-post of a Probabl blog post and based on a talk given at EuroSciPy 2026 in Kraków (slides).]]></summary></entry><entry><title type="html">scikit-learn release 1.9: better numerics, new core functionality</title><link href="https://blog.scikit-learn.org/updates/release-1-9/" rel="alternate" type="text/html" title="scikit-learn release 1.9: better numerics, new core functionality" /><published>2026-06-12T00:00:00+00:00</published><updated>2026-06-12T00:00:00+00:00</updated><id>https://blog.scikit-learn.org/updates/release-1-9</id><content type="html" xml:base="https://blog.scikit-learn.org/updates/release-1-9/"><![CDATA[<div>
  <img src="/assets/images/posts_images/1_9_release/scikit-learn_1_9.png" alt="" />
  

  
  
  
  

  

  

Author:  
      <a itemprop="sameAs" content="https://gael-varoquaux.info/" href="https://gael-varoquaux.info/" rel="me noopener noreferrer" style="vertical-align:top;"><img src="/assets/images/author_images/gael_varoquaux.png" style="width:1em;margin-right:.5em;border-radius: 50%;" alt="Author Icon" class="orcid-icon" />Gael Varoquaux</a>
     

<br /><br />

</div>

<p>Scikit-learn 1.9 release is out, and it comes with solid improvements to
many existing estimators, making them faster, more stable, handling
missing values, adding GPU support… The release also enhances the
estimator displays in notebooks, and introduces a callback mechanism that
opens the door to progress bars or advanced monitoring of convergence.</p>

<h2 id="improvement-richer-html-views">Improvement: Richer HTML views</h2>

<p>The improvements that most will easily view are those on the estimator displays.<br />
Since recent versions, the estimator views displayed in notebooks can show the parameters of the estimators (revealed by clicking on the estimator name). Latest release adds a view of the fitted attribute, as visible below:</p>

<figure>
 <img src="/assets/images/posts_images/1_9_release/fitted_attr.png" alt="HTML displays showing the fitted attributes" style="border-width: thick" max-width="50%" max-height="50%" /> 
 <figcaption>
  HTML display in a notebook, with the fitted attributes visible.
 </figcaption>
</figure>
<p>In addition, the ColumnTransformer’s view has been enhanced to help the user understand how features are assembled:</p>

<figure>
 <img src="/assets/images/posts_images/1_9_release/feature_names.png" alt="HTML displays showing the output feature names" style="border-width: thick" max-width="50%" max-height="50%" /> 
 <figcaption>
  HTML display in a notebook, with the output feature names visible.
 </figcaption>
</figure>

<h2 id="a-new-promise-callbacks">A new promise: Callbacks</h2>

<p>Scikit-learn 1.9 comes with a callback mechanism, currently experimental. We spent a lot of time designing it so that it enables many different uses: nested tracking of progress (even in parallel computing) on a variety of measures, early stopping…<br />
The release notes come with <a href="https://scikit-learn.org/dev/auto_examples/release_highlights/plot_release_highlights_1_9_0.html#callbacks">an example on how to use these callbacks to monitor scores and to display progress bars</a> – <a href="https://scikit-learn.org/stable/auto_examples/callbacks/plot_scoring_monitor.html">a more advance monitoring example</a>.</p>
<figure>
 <a href="https://scikit-learn.org/dev/auto_examples/release_highlights/plot_release_highlights_1_9_0.html#callbacks">
 <img src="/assets/images/posts_images/1_9_release/callbacks.png" alt="The logging and progress-bar callbacks in a notebook" style="border-width: thick" max-width="50%" max-height="50%" />
 </a>
 <figcaption>
  The logging and progress-bar callbacks in a notebook.
 </figcaption>
</figure>

<p>As of today, the callbacks are implemented in logistic regression (with LBFGS solver), the various *SearchCV objects, Pipeline, StandardScaler. The next releases will progressively add callbacks in more and more estimators (this is a place where contributors can help).</p>

<h2 id="improved-statistics-and-numerics">Improved statistics and numerics</h2>

<p>As users, what we like about scikit-learn routines is that they tend to
be “fire-and-forget”, because they reliably run on a huge diversity of
inputs: sparse inputs, missing values, different data types. This
diversity of inputs is compounded by a diversity of modeling choices:
different losses, sample weights…</p>

<p>Each release of scikit-learn extends the toolbox, sometimes by completing
the combinatorial of options and data types rather than adding new
estimators. Release 1.9 was a real consolidation in this respect:</p>

<h3 id="tree-based-models">Tree-based models</h3>

<ul>
  <li>
    <p>Native missing-value support in RandomForestRegressor when minimizing
the absolute error criterion</p>
  </li>
  <li>
    <p>Support of missing-values for tree-based models monotonic constraints</p>
  </li>
  <li>
    <p>Improved the statistical correctness of fitting with sample weights in <a href="https://scikit-learn.org/stable/modules/ensemble.html#histogram-based-gradient-boosting">HistGradientBoosting</a>, <a href="https://scikit-learn.org/stable/modules/ensemble.html#random-forests">RandomForest</a> and <a href="https://scikit-learn.org/stable/modules/ensemble.html#extremely-randomized-trees">ExtraTree</a> (having exact support of sample weights in complex pipelines is challenging)</p>
  </li>
</ul>

<h3 id="linear-models">Linear models</h3>

<ul>
  <li>
    <p>Logistic regression can use natively float32, thus removing memory pressure</p>
  </li>
  <li>
    <p>Multi-Task linear models support fitting on sparse X and sample weights</p>
  </li>
  <li>
    <p>More stable and faster <a href="https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.RidgeCV.html"><code class="language-plaintext highlighter-rouge">RidgeCV</code></a> and <a href="https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.RidgeClassifierCV.html"><code class="language-plaintext highlighter-rouge">RidgeClassifierCV</code></a></p>
  </li>
  <li>
    <p>Gap safe screening of features for very fast fitting of sparse
squared-loss regressors</p>
  </li>
</ul>

<h3 id="other-models">Other models</h3>

<ul>
  <li>
    <p>Sample weight support in <a href="https://scikit-learn.org/stable/modules/generated/sklearn.cluster.MiniBatchKMeans.html">minibatch kmeans</a> (a very scalable clustering)</p>
  </li>
  <li>
    <p>Numeric stability of <code class="language-plaintext highlighter-rouge">yeo-johnson</code> in the <a href="https://scikit-learn.org/dev/modules/generated/sklearn.preprocessing.PowerTransformer.html#sklearn.preprocessing.PowerTransformer"><code class="language-plaintext highlighter-rouge">preprocessing.PowerTransformer</code></a></p>
  </li>
  <li>
    <p>Faster <a href="https://scikit-learn.org/stable/modules/generated/sklearn.manifold.SpectralEmbedding.html">Spectral embedding</a></p>
  </li>
</ul>

<h3 id="staying-up-to-date-with-the-ecosystem">Staying up to date with the ecosystem</h3>

<p>Scikit-learn can now return sparse arrays, rather than sparse matrices.
Indeed, scipy is slowly de-emphasizing sparse matrices, which often
surprise users with their behavior that depart from arrays.</p>

<h2 id="increasing-support-for-gpu">Increasing support for GPU</h2>

<p>Scikit-learn is increasingly gaining support for optimized compute backends, which enables it, for instance, to run on GPUs. The challenge (and the value) is the incredible diversity of estimators and usecases supported by scikit-learn, and the package is progressively adding backend support in more and more places.<br />
In the 1.9 release, the major features to gain GPU support were:</p>

<ul>
  <li><a href="https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html">Logistic regression</a> and <a href="https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.PoissonRegressor.html">Poisson regression</a> with LBFGS solver</li>
  <li>More metrics (eg average precision score, …)</li>
  <li><a href="https://scikit-learn.org/stable/modules/generated/sklearn.kernel_approximation.Nystroem.html">Nystroem kernel approximation</a></li>
</ul>

<p>See <a href="https://scikit-learn.org/dev/modules/array_api.html#array-api-support-experimental">the docs</a> for all details on how to use the compute backends and which estimator support them.</p>

<p>PS: the user experience is currently not as good as with the default compute backend (numpy). But adding and improving GPU support (with the “array API”) is a good place for talented volunteers to help move the project forward.</p>

<h2 id="acknowledgements">Acknowledgements</h2>

<p>Scikit-learn is the work of <a href="https://scikit-learn.org/stable/about.html#the-people-behind-scikit-learn">many contributors</a>, with people volunteering
their time as well as financial sponsors –
see <a href="https://scikit-learn.org/dev/institutional_support.html#funding">the funding page</a>.</p>]]></content><author><name>{&quot;bio&quot;=&gt;&quot;Open source library for machine learning in Python.&quot;, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github-square&quot;, &quot;url&quot;=&gt;&quot;https://github.com/scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;LinkedIn&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-linkedin&quot;, &quot;url&quot;=&gt;&quot;https://linkedin.com/company/scikit-learn/&quot;}, {&quot;label&quot;=&gt;&quot;Bluesky&quot;, &quot;icon&quot;=&gt;&quot;&quot;, &quot;url&quot;=&gt;&quot;https://bsky.app/profile/scikit-learn.org&quot;}, {&quot;label&quot;=&gt;&quot;Mastodon&quot;, &quot;icon&quot;=&gt;&quot;fab fa-brands fa-mastodon&quot;, &quot;url&quot;=&gt;&quot;https://fosstodon.org/@sklearn&quot;}, {&quot;label&quot;=&gt;&quot;YouTube&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-youtube&quot;, &quot;url&quot;=&gt;&quot;https://www.youtube.com/@scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;Facebook&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-facebook-square&quot;, &quot;url&quot;=&gt;&quot;https://facebook.com/scikitlearnofficial/&quot;}, {&quot;label&quot;=&gt;&quot;Instagram&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-instagram&quot;, &quot;url&quot;=&gt;&quot;https://instagram.com/scikitlearnofficial/&quot;}]}</name></author><category term="Updates" /><category term="Release" /><category term="Open Source" /><category term="Machine Learning" /><category term="Array API" /><category term="Performance" /><summary type="html"><![CDATA[Author: Gael Varoquaux]]></summary></entry><entry><title type="html">Update on array API adoption in scikit-learn</title><link href="https://blog.scikit-learn.org/updates/update-array-api/" rel="alternate" type="text/html" title="Update on array API adoption in scikit-learn" /><published>2026-03-05T00:00:00+00:00</published><updated>2026-03-05T00:00:00+00:00</updated><id>https://blog.scikit-learn.org/updates/update-array-api</id><content type="html" xml:base="https://blog.scikit-learn.org/updates/update-array-api/"><![CDATA[<div>
  <img src="/assets/images/posts_images/array-api-scikit-learn-2026-feature.png" alt="" />
  

  
  
  
  

  

  

Author:  
      <a itemprop="sameAs" content="https://github.com/lucyleeow" href="https://github.com/lucyleeow" rel="me noopener noreferrer" style="vertical-align:top;"><img src="/assets/images/author_images/lucyliu.jpeg" style="width:1em;margin-right:.5em;border-radius: 50%;" alt="Author Icon" class="orcid-icon" />Lucy Liu</a>
     

<br /><br />

</div>
<p><em>Note: this blog post is a cross-post of a <a href="https://labs.quansight.org/blog/array-api-scikit-learn-2026">Quansight Labs blog post</a>.</em></p>

<p>The <a href="https://data-apis.org/">Consortium for Python Data API Standards</a>
developed the <a href="https://data-apis.org/array-api/">Python array API standard</a>
to define a consistent interface for array libraries, specifing core
operations, data types, and behaviours. This enables ‘array-consuming’
libraries (such as scikit-learn) to write array-agnostic code that can
be run on any array API compliant backend. Adopting array API support in scikit-learn
means that users can pass arrays from any array API compliant library to
functions that have been converted to be array-agnostic. This is useful because it
allows users to take advantage of array library features, such as hardware
acceleration, most notably via GPUs.</p>

<p>Indeed, GPU support in scikit-learn has been of interest for a long time - 11 years
ago, we added an entry to our FAQ page explaining that we had no plans to add GPU
support in the near future due to the software dependencies and platform specific
issues it would introduce. By relying on the array API standard, however, these
concerns can now be avoided.</p>

<p>In this blog post, I will provide an update to the array API adoption work in
scikit-learn, since it’s initial introduction in version 1.3 two years ago.
Thomas Fan’s <a href="https://labs.quansight.org/blog/array-api-support-scikit-learn">blog post</a>
provides details on the status when array API support was initially added.</p>

<h2 id="current-status">Current status</h2>

<p>Since the introduction of array API support in version 1.3 of scikit-learn,
several key developments have followed.</p>

<h3 id="vendoring-array-api-compat-and-array-api-extra">Vendoring <code class="language-plaintext highlighter-rouge">array-api-compat</code> and <code class="language-plaintext highlighter-rouge">array-api-extra</code></h3>

<p>Scikit-learn now vendors both
<a href="https://data-apis.org/array-api-compat/"><code class="language-plaintext highlighter-rouge">array-api-compat</code></a> and
<a href="https://data-apis.org/array-api-extra/"><code class="language-plaintext highlighter-rouge">array-api-extra</code></a>.
<code class="language-plaintext highlighter-rouge">array-api-compat</code> is a wrapper around common array libraries (e.g., PyTorch,
CuPy, JAX) that bridges gaps to ensure compatibility with the standard. It
enables adoption of backwards incompatible changes while still allowing array
libraries time to adopt the standard slowly. <code class="language-plaintext highlighter-rouge">array-api-extra</code> provides array
functions not included in the standard but deemed useful for array-consuming
libraries.</p>

<p>We chose to vendor these now much more mature libraries in order to avoid the
complexity of conditionally handling optional dependencies throughout the
codebase. This approach also follows precedent, as SciPy also vendors these
packages.</p>

<h3 id="array-libraries-supported">Array libraries supported</h3>

<p>Scikit-learn currently supports CuPy ndarrays, PyTorch tensors (testing
against all devices: ‘cpu’, ‘cuda’, ‘mps’ and ‘xpu’) and NumPy arrays. JAX
support is also on the horizon. The main focus of this work is addressing
in-place mutations in the codebase. Follow
<a href="https://github.com/scikit-learn/scikit-learn/pull/29647">PR #29647</a> for
updates.</p>

<p>Beyond these libraries, scikit-learn also tests against <code class="language-plaintext highlighter-rouge">array-api-strict</code>, a
reference implementation that strictly adheres to the array API specification.
The purpose of <code class="language-plaintext highlighter-rouge">array-api-strict</code> is to help automate compliance checks for
consuming libraries and to enable development and testing of array
API functionality without the need for GPU or other specialized hardware.
Array libraries that conform to the standard and pass the <code class="language-plaintext highlighter-rouge">array-api-tests</code> suite
should be accepted by scikit-learn and SciPy, without any additional modifications
from maintainers.</p>

<h3 id="estimators-and-metrics-with-array-api-support">Estimators and metrics with array API support</h3>

<p>The full list of metrics and estimators that now support array API can be
found in our
<a href="https://scikit-learn.org/dev/modules/array_api.html#">Array API support</a>
documentation page. The majority of high impact metrics have now been
converted to be array API compatible. Many transformers are also now
supported, notably <code class="language-plaintext highlighter-rouge">LabelBinarizer</code> which is widely used internally and
simplifies other conversions.</p>

<p>Conversion of estimators is much more complicated as it often involves
benchmarking different variations of code or consensus gathering on
implementation choices. It generally requires many months of work by several
maintainers. Nonetheless, support for <code class="language-plaintext highlighter-rouge">LogisticRegression</code>, <code class="language-plaintext highlighter-rouge">GaussianNB</code>,
<code class="language-plaintext highlighter-rouge">GaussianMixture</code>, <code class="language-plaintext highlighter-rouge">Ridge</code> (and family: <code class="language-plaintext highlighter-rouge">RidgeCV</code>, <code class="language-plaintext highlighter-rouge">RidgeClassifier</code>,
<code class="language-plaintext highlighter-rouge">RidgeClassifierCV</code>), <code class="language-plaintext highlighter-rouge">Nystroem</code> and <code class="language-plaintext highlighter-rouge">PCA</code> has been added. Work on
<code class="language-plaintext highlighter-rouge">GaussianProcessRegressor</code> is also underway (follow at
<a href="https://github.com/scikit-learn/scikit-learn/pull/33096">PR #33096</a>).</p>

<h3 id="handling-mixed-array-namespaces-and-devices">Handling mixed array namespaces and devices</h3>

<p>scikit-learn takes a unique approach among ‘array-consuming’ libraries by
supporting mixed array namespace and device inputs. This design choice enables
the framework to handle the practical complexities of end-to-end machine
learning pipelines.</p>

<p>String-valued class labels are common in classification tasks and enable users
to work with interpretable categories rather than integer codes. NumPy is
currently the only array library with string array support, meaning that any
workflow involving both GPU-accelerated computation and string labels
necessarily involves mixed array type inputs.</p>

<p>Mixed array input support also enables flexible pipeline workflows. Pipelines
provide significant value by chaining preprocessing steps and estimators into
reusable workflows that prevent data leakage and ensure consistent
preprocessing. However, they have an intentional design limitation: pipeline
steps can transform feature arrays (<code class="language-plaintext highlighter-rouge">X</code>) but cannot modify target arrays
(<code class="language-plaintext highlighter-rouge">y</code>). Allowing mixed array inputs means a pipeline can include a
<code class="language-plaintext highlighter-rouge">FunctionTransformer</code> step that moves feature data from CPU to GPU to leverage
hardware acceleration, while allowing the target array, which cannot be
modified, to remain on CPU.</p>

<p>For example, mixed array inputs enable a pipeline where string classification
features are encoded on CPU (as only NumPy supports string arrays), converted
to torch CUDA tensors, then passed to the array API-compatible
<code class="language-plaintext highlighter-rouge">RidgeClassifier</code> for GPU-accelerated computation:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">partial</span>

<span class="kn">from</span> <span class="nn">sklearn.linear_model</span> <span class="kn">import</span> <span class="n">RidgeClassifier</span>
<span class="kn">from</span> <span class="nn">sklearn.pipeline</span> <span class="kn">import</span> <span class="n">make_pipeline</span>
<span class="kn">from</span> <span class="nn">sklearn.preprocessing</span> <span class="kn">import</span> <span class="n">FunctionTransformer</span><span class="p">,</span> <span class="n">TargetEncoder</span>

<span class="n">pipeline</span> <span class="o">=</span> <span class="n">make_pipeline</span><span class="p">(</span>
    <span class="c1"># Encode string categories with average target values
</span>    <span class="n">TargetEncoder</span><span class="p">(),</span>
    <span class="c1"># Convert feature array `X` to Torch CUDA device
</span>    <span class="n">FunctionTransformer</span><span class="p">(</span><span class="n">partial</span><span class="p">(</span><span class="n">torch</span><span class="p">.</span><span class="n">asarray</span><span class="p">,</span> <span class="n">dtype</span><span class="o">=</span><span class="s">"float32"</span><span class="p">,</span> <span class="n">device</span><span class="o">=</span><span class="s">"cuda"</span><span class="p">))</span>
    <span class="n">RidgeClassifier</span><span class="p">(</span><span class="n">solver</span><span class="o">=</span><span class="s">"svd"</span><span class="p">),</span>
<span class="p">)</span>
</code></pre></div></div>

<p>Work on adding mixed array type inputs for metrics and estimators is underway
and expected to progress quickly. This work includes developing a robust
testing framework, including for pipelines using mixed array types (follow
<a href="https://github.com/scikit-learn/scikit-learn/pull/32755">PR #32755</a> for details).</p>

<p>Finally, we have also revived our work to support the ability to fit and
predict on different namespaces/devices. This allows users to train models on
GPU hardware but deploy predictions on CPU hardware, optimizing costs and
accommodating different resource availability between training and production
environments. Follow
<a href="https://github.com/scikit-learn/scikit-learn/pull/33076">PR #33076</a> for
details.</p>

<h2 id="challenges">Challenges</h2>

<p>The challenges of array API adoption remain largely unchanged from when this
work began. These are also common to other array-consuming libraries, with a
notable addition: the need to handle array movement between namespaces and
devices to support mixed array type inputs.</p>

<h3 id="array-api-standard-is-a-subset-of-numpys-api">Array API Standard is a subset of NumPy’s API</h3>

<p>The array API standard only includes widely-used functions implemented across
most array libraries, meaning many NumPy functions are absent. When such a
function is encountered while adding array API support, we have the following
options:</p>

<ul>
  <li>add the function to <code class="language-plaintext highlighter-rouge">array-api-extra</code> - this allows other array-consuming
libraries to benefit and allows sharing of maintenance burden, but is only
relevant for more widely used functions</li>
  <li>add our own implementation in scikit-learn - these functions live in
<code class="language-plaintext highlighter-rouge">sklearn/utils/_array_api.py</code></li>
  <li>check if SciPy implements an array API compatible version of the function</li>
</ul>

<p>The <code class="language-plaintext highlighter-rouge">quantile</code> function illustrates this decision-making process. <code class="language-plaintext highlighter-rouge">quantile</code>
is not included in the standard as it is not widely used (outside of
scikit-learn) and while it is implemented in most array libraries, the
set of quantile methods supported and their APIs vary. Currently, scikit-learn maintains its
own array API compatible version that supports both weights and NaNs, but due
to the maintenance burden we decided to investigate alternatives. SciPy has an
array API compatible implementation, but it did not support weights. We thus
investigated adding <code class="language-plaintext highlighter-rouge">quantile</code> to <code class="language-plaintext highlighter-rouge">array-api-extra</code>; however, during this
effort, SciPy decided to add weight support. Thus, we ultimately decided to
transition to the SciPy implementation once our minimum SciPy version allows.</p>

<h3 id="compiled-code">Compiled code</h3>

<p>Many performance-critical parts of scikit-learn are written using compiled
code extensions in Cython, C or C++. These directly access the underlying
memory buffers of NumPy arrays and are thus restricted to CPU.</p>

<p>Metrics and estimators, with compiled code, handle this in one of two ways:
convert arrays to NumPy first or maintain two parallel branches of code, one
for NumPy (compiled) and one for other array types (array API compatible).
When performance is less critical or array API conversion provides no gains
(e.g., <code class="language-plaintext highlighter-rouge">confusion_matrix</code>), we convert to NumPy. When performance gains are
significant, we accept the maintenance burden of dual code paths. This was the case for
<code class="language-plaintext highlighter-rouge">LogisticRegression</code> and the extensive process required for making such implementation
decisions can be seen in the
<a href="https://github.com/scikit-learn/scikit-learn/pull/32644">PR #32644</a>.</p>

<h3 id="unspecified-behaviour-in-the-standard">Unspecified behaviour in the standard</h3>

<p>The array API standard intentionally leaves some function behaviors
unspecified, permitting implementation differences across array libraries. For
example, the order of unique elements is not specified for the <code class="language-plaintext highlighter-rouge">unique_*</code>
functions and as of NumPy version 2.3, some <code class="language-plaintext highlighter-rouge">unique_*</code> functions no longer
return sorted values. This will require code amendments in cases where sorted
output was relied upon.</p>

<p>Similarly, NaN handing is also unspecified for <code class="language-plaintext highlighter-rouge">sort</code>; however, in this case, all
array libraries currently supported by scikit-learn follow NumPy’s NaN
semantics, placing NaNs at the end. This consistency eliminates the need for
special handling code, though comprehensive testing remains essential when
adding support for new array libraries.</p>

<h3 id="device-transfer">Device transfer</h3>

<p>Mixed array namespace and device inputs necessitates conversion of arrays
between different namespaces and devices. This presented a number of
considerations and challenges.</p>

<p>The array API standard adopted DLPack as the recommended
<a href="https://data-apis.org/array-api/latest/design_topics/data_interchange.html#data-interchange">data interchange</a>
protocol. This protocol is widely implemented in array libraries and offers an
efficient, C ABI compatible protocol for array conversion. While this provided
us with an easy way to implement these transfers, there were limitations.
Cross-device transfer capability was only introduced in DLPack v1, released in
September 2024. This meant that only the latest PyTorch and CuPy versions have
support for DLPack v1. Moreover, not all array libraries have adopted support
yet. We therefore implemented a ‘manual’ fallback; however, this requires
conversion via NumPy when the transfer involves two non-NumPy arrays.
Additionally, there are no DLPack tests in
<a href="https://github.com/data-apis/array-api-tests">array-api-tests</a>, a testing
suite to verify standard compliance, leaving DLPack implementation bugs easier
to overlook. Despite these challenges, scikit-learn will benefit from future
improvements, such as addition of a C-level API for DLPack exchange that
bypasses Python function calls, offering significant benefit for GPU
applications.</p>

<p>Beyond the technical considerations, there were also user interface
considerations. How should we inform users that these conversions, which incur
memory and performance cost, are occurring? We decided against warnings, which
risk being ignored or becoming a nuisance, and to instead clearly document this
behaviour. Additionally, different devices have different data type limitations;
for example, Apple MPS only supports float32. How best to handle these differences
when performing conversions while ensuring users are informed of precision
impacts is an ongoing consideration.</p>

<h2 id="a-quick-benchmark">A quick benchmark</h2>

<p>Array API support for <code class="language-plaintext highlighter-rouge">Ridge</code> regression was added in version 1.5, enabling
GPU-accelerated linear models in scikit-learn. Combined with support of
several transformers, this allows for complete preprocessing and estimation
pipelines on GPU.</p>

<p>The following benchmark shows the use of the <code class="language-plaintext highlighter-rouge">MaxAbsScaler</code> transformed
followed by <code class="language-plaintext highlighter-rouge">Ridge</code> regression using randomly generated data with 500,000
samples and 300 features. The benchmarks were run on AMD Ryzen Threadripper
2970WX CPU, NVIDIA Quadro RTX 8000 GPU and Apple M4 GPU (Metal 3).</p>

<p>The figure below shows the performance speed up on CuPy, Torch CPU and Torch
GPU relative to NumPy.</p>

<p><img src="/assets/images/posts_images/array_api_timings.png" alt="Benchmarking of MaxAbsScaler/Ridge pipeline" title="Benchmarking of MaxAbsScaler/Ridge pipeline" /></p>

<p><em>Performance speedup relative to NumPy across different backends.</em></p>

<p>The observed speedups are representative of performance gains achievable with
sufficiently large datasets on datacenter-grade GPUs for linear
algebra-intensive workloads. Mobile GPUs, such as those in laptops, would
typically yield more modest improvements.</p>

<p>Note that scikit-learn’s <code class="language-plaintext highlighter-rouge">Ridge</code> regressor currently only supports ‘svd’
solver. We selected this solver for initial implementation as it exclusively
uses standard-compliant functions available across all backends and is the
most stable solver. Support for the ‘cholesky’ solver is also underway (see
details in <a href="https://github.com/scikit-learn/scikit-learn/pull/29318">PR #29318</a>).</p>

<h2 id="looking-forward">Looking forward</h2>

<p>As of version 1.8, array API support is still in experimental mode and thus
not enabled by default. However, we welcome early adopters and interested
users to try it and report any
<a href="https://github.com/scikit-learn/scikit-learn/issues">issues</a>. See
<a href="https://scikit-learn.org/dev/modules/array_api.html#enabling-array-api-support">our documentation</a>
for details on enabling array API support.</p>

<p>Before removing experimental status, we would like to:</p>

<ul>
  <li>develop a system for automatically documenting functions and classes that
support array API, potentially with the ability to add relevant details</li>
  <li>mixed array type input support</li>
  <li>support fit and predict on different hardware by allowing conversion of
fitted estimators between namespaces/devices using utility functions</li>
  <li>improved testing, in particular for the new mixed array type
functionalities</li>
  <li>improved documentation, including adding an example to our gallery</li>
  <li>decide on the minimal dependency versions required</li>
  <li>get real world user feedback</li>
</ul>

<p>Alongside these infrastructure and framework improvements, we look forward to
adding support for more estimators. These improvements will deliver
production-ready GPU support and flexible deployment options to scikit-learn
users. We welcome community involvement through testing and feedback
throughout this development phase.</p>

<h2 id="acknowledgements">Acknowledgements</h2>

<p>Work on array API in scikit-learn has been a combined effort from many
contributors. This work was partly funded by CZI and NASA Roses.</p>

<p>I would like to thank <a href="https://github.com/ogrisel">Olivier Grisel</a>,
<a href="https://github.com/betatim">Tim Head</a> and
<a href="https://github.com/ev-br">Evgeni Burovski</a> for helping me with my array API
questions.</p>]]></content><author><name>{&quot;bio&quot;=&gt;&quot;Open source library for machine learning in Python.&quot;, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github-square&quot;, &quot;url&quot;=&gt;&quot;https://github.com/scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;LinkedIn&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-linkedin&quot;, &quot;url&quot;=&gt;&quot;https://linkedin.com/company/scikit-learn/&quot;}, {&quot;label&quot;=&gt;&quot;Bluesky&quot;, &quot;icon&quot;=&gt;&quot;&quot;, &quot;url&quot;=&gt;&quot;https://bsky.app/profile/scikit-learn.org&quot;}, {&quot;label&quot;=&gt;&quot;Mastodon&quot;, &quot;icon&quot;=&gt;&quot;fab fa-brands fa-mastodon&quot;, &quot;url&quot;=&gt;&quot;https://fosstodon.org/@sklearn&quot;}, {&quot;label&quot;=&gt;&quot;YouTube&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-youtube&quot;, &quot;url&quot;=&gt;&quot;https://www.youtube.com/@scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;Facebook&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-facebook-square&quot;, &quot;url&quot;=&gt;&quot;https://facebook.com/scikitlearnofficial/&quot;}, {&quot;label&quot;=&gt;&quot;Instagram&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-instagram&quot;, &quot;url&quot;=&gt;&quot;https://instagram.com/scikitlearnofficial/&quot;}]}</name></author><category term="Updates" /><category term="Open Source" /><category term="Machine Learning" /><category term="Array API" /><category term="Performance" /><summary type="html"><![CDATA[Author: Lucy Liu Note: this blog post is a cross-post of a Quansight Labs blog post.]]></summary></entry><entry><title type="html">Enhancing user experience through interactive inspection</title><link href="https://blog.scikit-learn.org/updates/enhancing-user-experience/" rel="alternate" type="text/html" title="Enhancing user experience through interactive inspection" /><published>2026-01-06T00:00:00+00:00</published><updated>2026-01-06T00:00:00+00:00</updated><id>https://blog.scikit-learn.org/updates/enhancing-user-experience</id><content type="html" xml:base="https://blog.scikit-learn.org/updates/enhancing-user-experience/"><![CDATA[<div>
  <img src="/assets/images/posts_images/sklearn_czi.png" alt="" />
  

  
  
  
  

  

  

Author:  
      <a itemprop="sameAs" content="https://deamarialeon.com" href="https://deamarialeon.com" rel="me noopener noreferrer" style="vertical-align:top;"><img src="/assets/images/author_images/dea-leon.png" style="width:1em;margin-right:.5em;border-radius: 50%;" alt="Author Icon" class="orcid-icon" />Dea María Léon</a>
      
        <a href="mailto:deamarialeon@gmail.com" title="deamarialeon@gmail.com"><span><i class="elastic-fai fas fa-envelope"></i></span></a>
      

<br /><br />

</div>

<p>User experience (UX) has always been an important focus for <code class="language-plaintext highlighter-rouge">scikit-learn</code>. 
As we know, UX encompasses many aspects, but here we will focus specifically on 
how easy it is for the user to understand <code class="language-plaintext highlighter-rouge">scikit-learn</code> models during development, 
especially while using tools like jupyter notebooks.</p>

<h2 id="first-visualizations">First visualizations</h2>

<p>Initial work to allow users to inspect their models interactively began in 2019, 
when Thomas J. Fan introduced HTML visualizations for estimators. 
He continued to build on this foundation with additional improvements 
in subsequent contributions.</p>

<h2 id="lack-of-resources-to-go-forward">Lack of resources to go forward</h2>

<p>In June 2023, <a href="https://github.com/
scikit-learn/scikit-learn/issues/26595">issue 26595 was opened by Gaël Varoquaux</a> outlining several potential enhancements 
to the HTML displays. These ideas stemmed from direct interactions with users, 
which clearly highlighted the need for further work in this area. 
Unfortunately, due to a lack of resources, the issue remained open for 
approximately a year and a half.</p>

<h2 id="wellcome-grant-awarded-to-scikit-learn">Wellcome grant awarded to <code class="language-plaintext highlighter-rouge">scikit-learn</code></h2>

<p>This was until the end of 2023, when Guillaume Lemaitre applied for a grant with
the help of NumFOCUS, that the broader topic of Predictive model evaluation and 
inspection was formalized. Enhancing user experience through interactive inspection 
is an essential part of this effort and falls within the scope of the grant.</p>

<p>The grant was awarded to <code class="language-plaintext highlighter-rouge">scikit-learn</code>and it is from the Chan Zuckerberg 
Initiative (CZI) through its Essential Open-Source Software for Science 
(EOSS) program. It is funded by The Wellcome Trust and administered by NumFOCUS. 
Thanks to this financial support, work is well underway. And several objectives
from the said issue have already been completed. 
<a href="https://github.com/scikit-learn/
administrative/blob/master/czi_eoss_proposal/EOSS6-0000000551_202312181059.pdf">See the grant application here.</a></p>

<h2 id="first-milestone-added-interactive-parameters-table-for-each-element">First milestone: Added interactive parameters table for each element</h2>

<p>The first milestone was introduced in<code class="language-plaintext highlighter-rouge">scikit-learn</code> version 1.7, released in 
June 2025. A parameters table was added to the HTML representation of models, 
displaying parameter names and their corresponding values. 
Non-default parameters—those explicitly set by the user—are highlighted. 
In addition, a copy-to-clipboard button is available for each parameter name. 
The parameter name that is copied to the clipboard is the fully classified name, 
which is shown on hover as well. The parameters table is collapsed by default 
and can be opened by the user.</p>

<p>The following two images show a pipeline table before and after the milestone.</p>

<figure>
<img src="/assets/images/posts_images/enhancing-UX/before1_7.png" alt="HTML visualization before scikit-learn 1.7" />
<figcaption>
HTML visualization before scikit-learn version 1.7
</figcaption>
</figure>

<figure>
<img src="/assets/images/posts_images/enhancing-UX/scikit-learn1_7.png" alt="HTML visualization with scikit-learn 1.7" style="width:50%" />
<figcaption>
HTML visualization with scikit-learn version 1.7
</figcaption>
</figure>

<h2 id="second-milestone-links-to-parameters-documentation-and-tooltip-preview">Second milestone: Links to parameters documentation and tooltip preview</h2>

<p>This feature was further enhanced in version 1.8, released in December 2025.
We added tooltips that provide documentation for each parameter, 
as well as links to the online documentation. 
See the GIF below or this example for more details: 
<a href="https://scikit-learn.org/
stable/auto_examples/miscellaneous/plot_estimator_representation.html">Displaying estimators and complex pipelines</a>.</p>

<figure>
<img src="/assets/images/posts_images/enhancing-UX/scikit-learn-1_8.gif" alt="HTML visualization with scikit-learn 1.8" />
<figcaption>
HTML visualization after scikit-learn 1.8
</figcaption>
</figure>

<h2 id="planned-improvements">Planned improvements</h2>

<p>More features are now being implemented. In particular, users will be able to 
visualize feature names and values, display fitted attributes and further improve 
the overall appearance of the interactive displays.</p>]]></content><author><name>{&quot;bio&quot;=&gt;&quot;Open source library for machine learning in Python.&quot;, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github-square&quot;, &quot;url&quot;=&gt;&quot;https://github.com/scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;LinkedIn&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-linkedin&quot;, &quot;url&quot;=&gt;&quot;https://linkedin.com/company/scikit-learn/&quot;}, {&quot;label&quot;=&gt;&quot;Bluesky&quot;, &quot;icon&quot;=&gt;&quot;&quot;, &quot;url&quot;=&gt;&quot;https://bsky.app/profile/scikit-learn.org&quot;}, {&quot;label&quot;=&gt;&quot;Mastodon&quot;, &quot;icon&quot;=&gt;&quot;fab fa-brands fa-mastodon&quot;, &quot;url&quot;=&gt;&quot;https://fosstodon.org/@sklearn&quot;}, {&quot;label&quot;=&gt;&quot;YouTube&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-youtube&quot;, &quot;url&quot;=&gt;&quot;https://www.youtube.com/@scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;Facebook&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-facebook-square&quot;, &quot;url&quot;=&gt;&quot;https://facebook.com/scikitlearnofficial/&quot;}, {&quot;label&quot;=&gt;&quot;Instagram&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-instagram&quot;, &quot;url&quot;=&gt;&quot;https://instagram.com/scikitlearnofficial/&quot;}]}</name></author><category term="Updates" /><category term="Open Source" /><category term="Funding" /><category term="Diversity" /><category term="Machine Learning" /><summary type="html"><![CDATA[Author: Dea María Léon]]></summary></entry><entry><title type="html">Interview with Virgil Chan, scikit-learn Team Member</title><link href="https://blog.scikit-learn.org/team/virgil-chan-interview/" rel="alternate" type="text/html" title="Interview with Virgil Chan, scikit-learn Team Member" /><published>2025-11-26T00:00:00+00:00</published><updated>2025-11-26T00:00:00+00:00</updated><id>https://blog.scikit-learn.org/team/virgil-chan-interview</id><content type="html" xml:base="https://blog.scikit-learn.org/team/virgil-chan-interview/"><![CDATA[<div>
  <img src="/assets/images/posts_images/" alt="" />
  

  
  
  
  

  

  

Author:  
      <a itemprop="sameAs" content="https://reshamas.github.io" href="https://reshamas.github.io" rel="me noopener noreferrer" style="vertical-align:top;"><img src="/assets/images/author_images/reshama_shaikh.jpeg" style="width:1em;margin-right:.5em;border-radius: 50%;" alt="Author Icon" class="orcid-icon" />Reshama Shaikh</a>
     , 


  
  
  
  

  

  


      <a itemprop="sameAs" content="https://virchan.github.io" href="https://virchan.github.io" rel="me noopener noreferrer" style="vertical-align:top;"><img src="/assets/images/author_images/virgil-chan.jpg" style="width:1em;margin-right:.5em;border-radius: 50%;" alt="Author Icon" class="orcid-icon" />Virgil Chan</a>
     

<br /><br />

</div>

<p>BIO: Virgil Chan is currently a Forward Deployed Engineer - Pre-Sales at Union.ai. Before that, he worked as a consultant in the San Francisco Bay Area, specialising in predictive data analytics and machine learning. Earlier, he studied mathematics before moving into data science. Virgil joined the scikit-learn team as a Contributor Experience Team member in December 2024.</p>

<ul>
  <li>GitHub: <a href="https://github.com/virchan">@virchan</a></li>
  <li>LinkedIn: <a href="https://www.linkedin.com/in/virgil-chan-0a65b11b8">@virgil-chan</a></li>
  <li>Website: <a href="https://virchan.github.io">https://virchan.github.io</a></li>
</ul>

<ol>
  <li>
    <p><strong>Tell us about yourself.</strong></p>

    <p>My name is Virgil, and I’m currently working as a Forward Deployed Engineer – Pre-Sales at Union.ai. Based in San Jose, California, I previously worked as a consultant, using libraries from the scientific Python ecosystem on data science and machine-learning projects, including medical data analysis, traffic-network prediction, and model evaluation. Before deciding that computers are more fun, I was doing mathematical research in topology.</p>
  </li>
  <li>
    <p><strong>How did you first get involved in open source?</strong></p>

    <p>I first got involved in open source during the COVID-19 lockdown. I used that time to study Python programming, data science, analytics, and machine learning, and that’s when I discovered libraries like NumPy, Pandas, scikit-learn, NetworkX, and TensorFlow. Once I became more confident in my skills, I started working as a consultant and used these libraries to deliver data-driven solutions for clients.</p>
  </li>
  <li>
    <p><strong>We would love to learn of your open source journey.</strong></p>

    <p>I was transitioning from academia into software development, and I quickly learnt that companies valued hands-on experience more than an advanced degree. At the same time, the rise of GPU-driven workloads and LLM-based solutions made my earlier consulting projects look less impressive on paper. I ended up stuck in the infinite loop of no-job-no-experience.</p>

    <p>Even though I came from a non-traditional background, and my resume didn’t match what recruiters and ATS systems usually look for, I’ve always believed that my experience is something I can build myself. Since companies weren’t keen on training junior developers, open source became one of the not-so-many viable paths. I started looking for a project where I could grow, be useful, and apply my academic training in a meaningful way. That search naturally led me to scikit-learn.</p>
  </li>
  <li>
    <p><strong>How did you get involved in scikit-learn?</strong></p>

    <p>My first PR to scikit-learn (<a href="https://github.com/scikit-learn/scikit-learn/pull/27913">scikit-learn/scikit-learn#27913</a>) was a classic “good first issue”: adding the URL of a scikit-learn example to the relevant places in the documentation. I opened it in December 2023 and it was merged into the main branch in March 2024. Maren helped me navigate the codebase and understand the CI workflow, which gave me a solid foundation for later contributions. Even though I’m now more experienced with the contributing workflow, I still revisit that PR from time to time to remind myself of the challenges first-time contributors face, and how I can support them.</p>

    <p>My next PR (<a href="https://github.com/scikit-learn/scikit-learn/pull/29709">scikit-learn/scikit-learn#29709</a>) was more technical, fixing a bug in the (root) mean squared log error function. The expected behaviour was to check that inputs were in the domain of $\log(1 + x)$, but the implementation at the time checked the domain of $\log(x)$ instead. It was one of the few issues I fully understood and knew how to solve, so I volunteered to create a PR. Adrin reviewed it and mentored me throughout the process. Once everything looked good and the CI passed, he asked me to add array API support to the function. And that’s where the fun began.</p>

    <p>I had no idea what the array API was, but I already had the habit of reading discussions and merged PRs in my spare time. With a bit of Googling, I quickly understood what needed to be done and the broader importance of the array API project. In fact, completing the array API project has become one of my mid-term goals for my scikit-learn work. Under the guidance of Adrin, Guillaume, Olivier, and Omar, my PRs improved, and contributing became even more rewarding because of how supportive the maintainers were. I also started reviewing PRs, especially from first-time contributors working on the same “good first issue” I began with. In December 2024, I joined the scikit-learn team.</p>

    <p>I’m honoured that the team welcomed me and trusted me with more responsibility, such as representing scikit-learn at the <a href="https://scientific-python.org/summits/developer/2025/">Scientific Python Developer Summit in May 2025</a>, <a href="https://github.com/scikit-learn/scikit-learn/pull/31068">implementing temperature scaling as a new feature (with Christian)</a>, and having the ability to run <a href="https://betatim.github.io/posts/github-action-with-gpu/">CUDA CI</a> myself. It feels good to pass the same positivity I received back into the community.</p>
  </li>
  <li>
    <p><strong>To which OSS projects and communities do you contribute?</strong></p>

    <p>I’m also interested in scaling machine-learning algorithms, so I’ve been exploring CUDA and cuML as well.</p>
  </li>
  <li>
    <p><strong>What is alluring about OSS?</strong></p>

    <p>Open source fosters a collaborative environment where everyone wins: end-users, maintainers, and contributors. Because it is volunteer-driven, it becomes easier to recognise that the problem itself is the problem, the bug or the issue, rather than the people involved. As a result, the usual institutional complications, such as power or ego struggles, conflicts of interest over funding, or pressure from deadlines, are far less likely to drag the project down. People have more freedom to focus on solving problems, which creates an ideal environment for exploration, experimentation, collaboration, learning, and growth.</p>

    <p>Open source has given me the chance to grow, develop new skills, and broaden my perspective, something I’ve been battling since finishing college. By trading my time for responsibility, I’ve found open source to be a meaningful and genuinely rewarding experience.</p>
  </li>
  <li>
    <p><strong>What are your favorite resources, books, courses, conferences, etc?</strong></p>

    <p>I found the <a href="https://www.youtube.com/watch?v=dMbWkAosBVA">interview between scikit-learn and Code for Thought</a> on YouTube. The maintainers shared their open-source journeys from how they got started to how they became involved in scikit-learn, which I found inspiring and motivating. For example, I can’t agree more with Gael’s point that “open source should be spontaneous” and that “a diversity of opinion will make better software.” I also learned from Adrin that I could get more involved in the project by becoming the second reviewer for a PR, which gave me the confidence to start reviewing PRs. I think this interview can help people understand the project from a more human and non-technical perspective.</p>
  </li>
  <li>
    <p><strong>What are your hobbies, outside of work and open source?</strong></p>

    <p>If I’m done with work and house chores, I usually listen to music. I enjoy classical music (Mozart, Brahms, Rachmaninoff, etc.), and I’m currently getting more exposure to Chopin’s work. I also like Rock ‘n’ Roll (Led Zeppelin, Eric Clapton, Deep Purple, etc.), and I find that AC/DC can “push me to eleven” whenever I’m stuck at work.</p>

    <p>I also enjoy reading novels. At the moment I’m reading The Silmarillion by Tolkien, and my to-read list keeps growing.</p>

    <p>I like hanging out with cats as well. I volunteer with an animal rescue group in San Jose, where I help care for the cats in their sanctuary and assist at adoption fairs.</p>
  </li>
</ol>]]></content><author><name>{&quot;bio&quot;=&gt;&quot;Open source library for machine learning in Python.&quot;, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github-square&quot;, &quot;url&quot;=&gt;&quot;https://github.com/scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;LinkedIn&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-linkedin&quot;, &quot;url&quot;=&gt;&quot;https://linkedin.com/company/scikit-learn/&quot;}, {&quot;label&quot;=&gt;&quot;Bluesky&quot;, &quot;icon&quot;=&gt;&quot;&quot;, &quot;url&quot;=&gt;&quot;https://bsky.app/profile/scikit-learn.org&quot;}, {&quot;label&quot;=&gt;&quot;Mastodon&quot;, &quot;icon&quot;=&gt;&quot;fab fa-brands fa-mastodon&quot;, &quot;url&quot;=&gt;&quot;https://fosstodon.org/@sklearn&quot;}, {&quot;label&quot;=&gt;&quot;YouTube&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-youtube&quot;, &quot;url&quot;=&gt;&quot;https://www.youtube.com/@scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;Facebook&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-facebook-square&quot;, &quot;url&quot;=&gt;&quot;https://facebook.com/scikitlearnofficial/&quot;}, {&quot;label&quot;=&gt;&quot;Instagram&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-instagram&quot;, &quot;url&quot;=&gt;&quot;https://instagram.com/scikitlearnofficial/&quot;}]}</name></author><category term="Team" /><category term="Open Source" /><summary type="html"><![CDATA[Author: Reshama Shaikh , Virgil Chan]]></summary></entry><entry><title type="html">scikit-learn Completes the GitHub Secure Open Source Training</title><link href="https://blog.scikit-learn.org/press/gh-sosf/" rel="alternate" type="text/html" title="scikit-learn Completes the GitHub Secure Open Source Training" /><published>2025-08-16T00:00:00+00:00</published><updated>2025-08-16T00:00:00+00:00</updated><id>https://blog.scikit-learn.org/press/gh-sosf</id><content type="html" xml:base="https://blog.scikit-learn.org/press/gh-sosf/"><![CDATA[<div>
  <img src="/assets/images/posts_images/gh-sosf/cover.png" alt="" />
  

  
  
  
  

  

  

Author:  
      <a itemprop="sameAs" content="https://reshamas.github.io" href="https://reshamas.github.io" rel="me noopener noreferrer" style="vertical-align:top;"><img src="/assets/images/author_images/reshama_shaikh.jpeg" style="width:1em;margin-right:.5em;border-radius: 50%;" alt="Author Icon" class="orcid-icon" />Reshama Shaikh</a>
     

<br /><br />

</div>

<h2 id="summary">Summary</h2>

<p>scikit-learn was honored to be selected to participate in Cohort 2 of the GitHub Secure Open Source Fund (OSF) Training Program. Cohort 1 took place earlier in 2025 with 19 projects, and Cohort 2 took place with 52 projects during June 2025.</p>

<figure>
 <img src="/assets/images/posts_images/gh-sosf/blog-title.png" alt="GitHub announcement of GH-S-OS Fund" style="border-width: thick" max-width="50%" max-height="50%" /> 
 <figcaption>
 Original post: <a href="https://github.blog/open-source/maintainers/securing-the-supply-chain-at-scale-starting-with-71-important-open-source-projects">GH Secure OSS Announcement</a>
 </figcaption>
</figure>

<p>It was an intense 3-week training program, with over 90 open source maintainers joining the training. Read the announcement from GitHub: <a href="https://github.blog/open-source/maintainers/securing-the-supply-chain-at-scale-starting-with-71-important-open-source-projects">Securing the supply chain at scale: Starting with 71 important open source projects</a></p>

<p>There were numerous workshops delivered by experts in the GitHub Security Lab. For many of these workshops, the learning materials are publicly available, and they are shared below.</p>

<h3 id="github-security-lab">GitHub Security Lab</h3>
<p>GitHub has its own security department, and GitHub Security Lab’s mission is to empower developers and secure open source.</p>
<ul>
  <li>GitHub Security Lab: <a href="https://securitylab.github.com/resources-os">Resources</a></li>
</ul>

<figure>
 <img src="/assets/images/posts_images/gh-sosf/gh-security-lab.png" alt="GitHub Security Lab" style="padding:1px;border:solid black" max-width="50%" max-height="50%" />  
 <figcaption>
 Original post: <a href="https://github.com/GitHubSecurityLab">GitHub Security Lab</a>
 </figcaption>
</figure>

<h2 id="resources-for-security-training">Resources for Security Training</h2>
<p>The training provided many trainings by experts in the field. Below we share trainings that are available to the public.</p>

<ul>
  <li><a href="https://docs.github.com/en/code-security/security-advisories/working-with-repository-security-advisories/configuring-private-vulnerability-reporting-for-a-repository">Configuring private vulnerability reporting for a repository</a>
    <blockquote>
      <p>Owners and administrators of public repositories can allow security researchers to report vulnerabilities securely in the repository by enabling private vulnerability reporting.</p>
    </blockquote>
  </li>
  <li><a href="https://securityscorecards.dev">OpenSSF Scorecard</a></li>
  <li><a href="https://microsoft.design/articles/secure-by-design-a-ux-toolkit">Secure by design: A UX toolkit</a></li>
</ul>

<h4 id="codeql-from-zero-to-hero">CodeQL: From Zero to Hero</h4>

<p>This workshop introduces fundamentals of security research and static analysis used when looking for vulnerabilities in software. They use an example of a simple vulnerability, walk through how CodeQL could detect it, and provide examples on how the audience could use CodeQL to find vulnerabilities themselves.</p>

<p>slides: <a href="https://github.com/sylwia-budzynska/2025-soss-codeql-workshop/blob/main/SOSS-CodeQL-slides.pdf">Finding Vulnerabilities with CodeQL</a></p>

<figure>
 <img src="/assets/images/posts_images/gh-sosf/CodeQL.png" alt="CodeQL audience and topics covered" style="padding:1px;border:solid black" max-width="50%" max-height="50%" /> 
 <figcaption>
 Original post: <a href="https://github.com/sylwia-budzynska/2025-soss-codeql-workshop">Finding Vulnerabilities with CodeQL</a>
 </figcaption>
</figure>

<h4 id="developing-secure-software">Developing Secure Software</h4>

<p>This course includes specific tips on how to use and develop open source and other software securely. Learn the security basics to develop software that is hardened against attacks, and understand how you can reduce the damage and speed the response when a vulnerability is exploited.</p>

<p>It was developed by the Open Source Security Foundation (OpenSSF), a cross-industry collaboration that brings together leaders to improve the security of open source software by building a broader community, targeted initiatives, and best practices.</p>

<ul>
  <li>Online, Self Paced</li>
  <li>16-20 Hours of Course Material</li>
  <li>Quizzes and Hands-on Labs</li>
</ul>

<figure>
 <img src="/assets/images/posts_images/gh-sosf/dss-lfd121.png" alt="course: Developing Secure Software" style="padding:1px;border:solid black" max-width="50%" max-height="50%" /> 
 <figcaption>
 Original post: <a href="https://training.linuxfoundation.org/training/developing-secure-software-lfd121">LFD121: Developing Secure Software</a>
 </figcaption>
</figure>

<h4 id="oss-fuzz">OSS-Fuzz</h4>
<p><a href="https://en.wikipedia.org/wiki/Fuzzing">Fuzz testing</a> is a well-known technique for uncovering programming errors in software.</p>

<figure>
 <img src="/assets/images/posts_images/gh-sosf/oss-fuzz.png" alt="OSS-Fuzz" style="padding:1px;border:solid black" max-width="50%" max-height="50%" /> 
 <figcaption>
 Original post: <a href="https://github.com/google/oss-fuzz">OSS-Fuzz</a>
 </figcaption>
</figure>

<h3 id="secure-code-game">Secure Code Game</h3>
<p>Secure Code Game is a GitHub Security Lab initiative, providing an in-repo learning experience, where learners to secure intentionally vulnerable code. At the same time, this is an open source project that welcomes your contributions as a way to give back to the community.</p>

<figure>
 <img src="/assets/images/posts_images/gh-sosf/secure-code-game.png" alt="Secure Code Game" style="padding:1px;border:solid black" max-width="50%" max-height="50%" /> 
 <figcaption>
 Original post: <a href="https://github.com/skills/secure-code-game">Secure Code Game</a>
 </figcaption>
</figure>

<h3 id="participate-in-future-cohorts-of-the-github-secure-open-source-training">Participate in Future Cohorts of the GitHub Secure Open Source Training</h3>
<p>If you are a maintainer of an open source project, this training is an excellent opportunity to secure your project with guidance from highly trained experts in the security field. <a href="https://docs.google.com/forms/d/e/1FAIpQLScDBalom0XhmJrvyI3kwD7dZ-dD4_uhmLNysVXtA8fH_WUKoA/viewform">Applications are open</a>.</p>

<h3 id="references">References</h3>
<ul>
  <li><a href="https://github.blog/open-source/maintainers/securing-the-supply-chain-at-scale-starting-with-71-important-open-source-projects">Securing the supply chain at scale: Starting with 71 important open source projects</a> (11-Aug-2025)</li>
  <li>TechCrunch: <a href="https://techcrunch.com/2024/11/19/github-launches-1-25m-open-source-fund-with-a-focus-on-security">GitHub launches $1.25M open source fund with a focus on security</a> (19-Nov-2024)</li>
  <li><a href="https://resources.github.com/github-secure-open-source-fund/">GitHub Secure Open Source Fund</a></li>
  <li><a href="https://www.eclipse.org/security/policy">Eclipse Foundation Security Policy</a></li>
  <li><a href="https://www.linuxfoundation.org/security">Linux Foundation Security Policy</a></li>
</ul>

<h3 id="blogs-from-participating-open-source-projects">Blogs from Participating Open Source Projects</h3>
<ul>
  <li>OpenCV: <a href="https://opencv.org/blog/opencvs-participation-in-the-github-secure-open-source-fund">OpenCV’s Participation in the GitHub Secure Open Source Fund</a></li>
  <li>Bootstrap: <a href="https://www.linkedin.com/pulse/bootstrap-github-secure-open-source-fund-julien-d%2525C3%2525A9ramond-cvjie">Bootstrap at GitHub Secure Open Source Fund</a></li>
  <li>Cobra &amp; Viper: <a href="https://spf13.com/p/cobra-viper-fortify-security-as-part-of-github-secure-open-source-fund">Cobra &amp; Viper Fortify Security as Part of GitHub Secure Open Source Fund</a></li>
  <li>Zitadel: <a href="https://zitadel.com/blog/github-secure-open-source-fund">A Leap Forward in Security: Our Journey with the GitHub Secure Open Source Fund</a></li>
</ul>

<h2 id="acknowledgments">Acknowledgments</h2>

<p>Thank you to the funders and ecosystem partners of the GitHub Secure Open Source Fund.</p>

<p><strong>Funding Partners:</strong> Alfred P. Sloan Foundation, American Express, Chainguard, Datadog, Herodevs, Kraken, Mayfield, Microsoft, Shopify, Stripe, Superbloom, Vercel, Zerodha, 1Password</p>

<figure>
 <img src="/assets/images/posts_images/gh-sosf/funders2.png" alt="Sponsors" style="padding:1px;border:solid black" max-width="50%" max-height="50%" /> 
 <figcaption>
 <a href="https://github.blog/open-source/maintainers/securing-the-supply-chain-at-scale-starting-with-71-important-open-source-projects"></a>
 </figcaption>
</figure>

<p><strong>Ecosystem Partners:</strong> Ecosyste.ms, CURIOSS, Digital Data Design Institute Lab for Innovation Science, Digital Infrastructure Insights Fund, Microsoft for Startups, Mozilla, OpenForum Europe, Open Source Collective, OpenUK, Open Technology Fund, OpenSSF, Open Source Initiative, OpenJS Foundation, University of California, Santa Cruz OSPO, Sovereign Tech Agency, SustainOSS</p>

<figure>
 <img src="/assets/images/posts_images/gh-sosf/ecosystem.png" alt="Ecosystem Partners" style="padding:1px;border:solid black" max-width="50%" max-height="50%" /> 
 <figcaption>
 <a href="https://github.blog/open-source/maintainers/securing-the-supply-chain-at-scale-starting-with-71-important-open-source-projects"></a>
 </figcaption>
</figure>]]></content><author><name>{&quot;bio&quot;=&gt;&quot;Open source library for machine learning in Python.&quot;, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github-square&quot;, &quot;url&quot;=&gt;&quot;https://github.com/scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;LinkedIn&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-linkedin&quot;, &quot;url&quot;=&gt;&quot;https://linkedin.com/company/scikit-learn/&quot;}, {&quot;label&quot;=&gt;&quot;Bluesky&quot;, &quot;icon&quot;=&gt;&quot;&quot;, &quot;url&quot;=&gt;&quot;https://bsky.app/profile/scikit-learn.org&quot;}, {&quot;label&quot;=&gt;&quot;Mastodon&quot;, &quot;icon&quot;=&gt;&quot;fab fa-brands fa-mastodon&quot;, &quot;url&quot;=&gt;&quot;https://fosstodon.org/@sklearn&quot;}, {&quot;label&quot;=&gt;&quot;YouTube&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-youtube&quot;, &quot;url&quot;=&gt;&quot;https://www.youtube.com/@scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;Facebook&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-facebook-square&quot;, &quot;url&quot;=&gt;&quot;https://facebook.com/scikitlearnofficial/&quot;}, {&quot;label&quot;=&gt;&quot;Instagram&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-instagram&quot;, &quot;url&quot;=&gt;&quot;https://instagram.com/scikitlearnofficial/&quot;}]}</name></author><category term="Press" /><category term="Open Source" /><summary type="html"><![CDATA[Author: Reshama Shaikh]]></summary></entry><entry><title type="html">Skolar: an open-source initiative to democratize open data science</title><link href="https://blog.scikit-learn.org/updates/probabl-skolar/" rel="alternate" type="text/html" title="Skolar: an open-source initiative to democratize open data science" /><published>2025-06-30T00:00:00+00:00</published><updated>2025-06-30T00:00:00+00:00</updated><id>https://blog.scikit-learn.org/updates/probabl-skolar</id><content type="html" xml:base="https://blog.scikit-learn.org/updates/probabl-skolar/"><![CDATA[<div>
  <img src="/assets/images/posts_images/sklearn_skolar.png" alt="" />
  

  
  
  
  

  

  

Author:  
      <a itemprop="sameAs" content="https://skolar.probabl.ai/" href="https://skolar.probabl.ai/" rel="me noopener noreferrer" style="vertical-align:top;"><img src="/assets/images/author_images/skolar-logo.png" style="width:1em;margin-right:.5em;border-radius: 50%;" alt="Author Icon" class="orcid-icon" />Skolar</a>
     , 


  
  
  
  

  

  


      <a itemprop="sameAs" content="https://www.linkedin.com/in/gittospenelope-data-analyst-growth-bilingual/" href="https://www.linkedin.com/in/gittospenelope-data-analyst-growth-bilingual/" rel="me noopener noreferrer" style="vertical-align:top;"><img src="/assets/images/author_images/penelope_gittos.jpeg" style="width:1em;margin-right:.5em;border-radius: 50%;" alt="Author Icon" class="orcid-icon" />Pénélope Gittos</a>
     

<br /><br />

</div>

<p><span style="color:red"><em>This blog post has been submitted by Probabl, a sponsor of scikit-learn.</em> </span>
The scikit-learn project values educational efforts that build and nurture a
strong vibrant open-source community. The goal of this is straightforward: give
everyone, everywhere, the tools they need to easily grasp, engage with, and
meaningfully contribute to data science using open-source software. This mission
is shared and actively supported by <a href="https://probabl.ai/">Probabl</a>, a company
that helps maintain scikit-learn by employing many of its core contributors and
investing in its long-term sustainability. With Probabl’s support and a deep
commitment from the community, the scikit-learn ecosystem continues building bridges between research,
software, and education.</p>

<p>When the <a href="https://inria.github.io/scikit-learn-mooc/">Inria scikit-learn MOOC</a>
(Massive Open Online Course) first went live, the community got a front-row seat
to the amazing impact of practical, accessible and open learning. Created by
several core developers and maintainers of scikit-learn—now working at
Probabl—the MOOC has reached over 40,000 learners worldwide, clearly
highlighting the demand for organized, hands-on resources that blend theory with
real-world practice.</p>

<p>Today, Probabl is excited to introduce
<a href="https://app.arcade.software/share/vCN6ik9dR22zD35XP5a7">Skolar</a>, a new, fully
open-source educational initiative, built directly from your feedback and all
the lessons we’ve learned along the way. Developed and extended by those same
core developers of scikit-learn, Skolar is designed specifically for data
science practitioners, offering hands-on, high-quality learning resources
grounded in real-world applications and open-source values.</p>

<p>Skolar exists to boost our shared values: openness, teamwork, and practicality.
It offers clear, interactive tutorials and structured courses carefully designed
to match industry challenges and specialized use-cases. But even more
importantly, it captures the true spirit of open source: encouraging
collaboration, peer-to-peer learning, and guidance from experts.</p>

<p>Right now, we’re just at the beginning. Today, you can dive into our
Scikit-learn Associate Practitioner online course, adapted from the popular
Inria MOOC but enhanced with new material on unsupervised learning, especially
clustering.</p>

<p>The next stages, professional and expert levels, will be released soon. We’ll
also add more courses covering other open-source libraries such as
<a href="https://skrub-data.org">skrub</a> (for data wrangling),
<a href="https://soda-inria.github.io/hazardous/">hazardous</a> (for survival analysis),
and <a href="https://fairlearn.org/">fairlearn</a> (for fairness).
Additionally, our scikit-learn team is planning to create  industry-specific
modules tackling real-world needs in fields like healthcare, finance, medicine,
and beyond.</p>

<p>At its core, Skolar is about empowering people through education, driven
entirely by our passion for openness and collaboration. We firmly believe that
true open data science begins with community-built learning resources. We warmly
welcome you, whether you’re a contributor, learner, teacher, or just someone
curious, to join us. Help shape Skolar’s future and support open-source
education in data science.</p>

<p>Create your account on Skolar today: https://skolar.probabl.ai</p>

<p>Contribute to the <a href="https://github.com/probabl-ai/scikit-learn-course">scikit-learn course
contents</a>, or contribute to
the learning platform’s <a href="https://github.com/France-ioi/AlgoreaBackend">backend</a>
or <a href="https://github.com/France-ioi/AlgoreaFrontend">frontend</a>.</p>]]></content><author><name>{&quot;bio&quot;=&gt;&quot;Open source library for machine learning in Python.&quot;, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github-square&quot;, &quot;url&quot;=&gt;&quot;https://github.com/scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;LinkedIn&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-linkedin&quot;, &quot;url&quot;=&gt;&quot;https://linkedin.com/company/scikit-learn/&quot;}, {&quot;label&quot;=&gt;&quot;Bluesky&quot;, &quot;icon&quot;=&gt;&quot;&quot;, &quot;url&quot;=&gt;&quot;https://bsky.app/profile/scikit-learn.org&quot;}, {&quot;label&quot;=&gt;&quot;Mastodon&quot;, &quot;icon&quot;=&gt;&quot;fab fa-brands fa-mastodon&quot;, &quot;url&quot;=&gt;&quot;https://fosstodon.org/@sklearn&quot;}, {&quot;label&quot;=&gt;&quot;YouTube&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-youtube&quot;, &quot;url&quot;=&gt;&quot;https://www.youtube.com/@scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;Facebook&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-facebook-square&quot;, &quot;url&quot;=&gt;&quot;https://facebook.com/scikitlearnofficial/&quot;}, {&quot;label&quot;=&gt;&quot;Instagram&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-instagram&quot;, &quot;url&quot;=&gt;&quot;https://instagram.com/scikitlearnofficial/&quot;}]}</name></author><category term="Updates" /><category term="Sponsor" /><category term="Open Source" /><category term="Machine Learning" /><summary type="html"><![CDATA[Author: Skolar , Pénélope Gittos]]></summary></entry><entry><title type="html">Changes and development of scikit-learn’s developer API</title><link href="https://blog.scikit-learn.org/updates/dev-api/" rel="alternate" type="text/html" title="Changes and development of scikit-learn’s developer API" /><published>2024-12-12T00:00:00+00:00</published><updated>2024-12-12T00:00:00+00:00</updated><id>https://blog.scikit-learn.org/updates/dev-api</id><content type="html" xml:base="https://blog.scikit-learn.org/updates/dev-api/"><![CDATA[<div>
  <img src="/assets/images/posts_images/BSD_watermark.svg" alt="" />
  

  
  
  
  

  

  

Author:  
      <a itemprop="sameAs" content="https://adrin.info/" href="https://adrin.info/" rel="me noopener noreferrer" style="vertical-align:top;"><img src="/assets/images/author_images/adrin-jalali.jpeg" style="width:1em;margin-right:.5em;border-radius: 50%;" alt="Author Icon" class="orcid-icon" />Adrin Jalali</a>
     

<br /><br />

</div>

<p>Historically, scikit-learn’s API has been divided into public and private. Public API is
intended to be used by users, and private API is used internally in scikit-learn to
develop new features and estimators. However, many of those functionalities have become
essential to develop scikit-learn estimators by third parties who develop them outside
the scikit-learn codebase.</p>

<p>When it comes to our public API, we have very strict and high standards on backward
compatibility. The rule of thumb is that no change should cause a change in users’
code unless we warn about it for two release cycles, which means we give users a year
time to update their code.</p>

<p>On the other hand, we have no such guarantees or constraints on our private API. This
brings an issue to third party developers who would like to use methods used by
scikit-learn developers to develop their estimators. Constantly changing private API
without prior warning brings certain challenges to third party developers which is not
ideal.</p>

<p>As a result, we’ve been working on creating a developer API which would sit somewhere
between our public and private API in terms of backward compatibility. That means we
intend to try to keep that API stable, and if needed, introduce changes with one release
cycle warning.</p>

<p>In the past few releases, we’ve slowly introduced more functionalities under this
umbrella. <code class="language-plaintext highlighter-rouge">__sklearn_clone__</code> and <code class="language-plaintext highlighter-rouge">__sklearn_is_fitted__</code> are two examples.</p>

<p>In the 1.6 release, we focused on the testing infrastructure and estimator tag system.
Estimator tags used to be private, and we were not sure about their design. In the 1.6
release, new tags are introduced and using them looks like the following:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.base</span> <span class="kn">import</span> <span class="n">BaseEstimator</span><span class="p">,</span> <span class="n">ClassifierMixin</span>

<span class="k">class</span> <span class="nc">MyEstimator</span><span class="p">(</span><span class="n">ClassifierMixin</span><span class="p">,</span> <span class="n">BaseEstimator</span><span class="p">):</span>

  <span class="p">...</span>

  <span class="k">def</span> <span class="nf">__sklearn_tags__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="n">tags</span> <span class="o">=</span> <span class="nb">super</span><span class="p">().</span><span class="n">__sklearn_tags__</span><span class="p">()</span>
    <span class="c1"># modify tags here
</span>    <span class="n">tags</span><span class="p">.</span><span class="n">non_deterministic</span> <span class="o">=</span> <span class="bp">True</span>
    <span class="k">return</span> <span class="n">tags</span>
</code></pre></div></div>

<p>The new tags mostly follow the same structure as the old tags, but there are certain
changes to them. The main change is that the old <code class="language-plaintext highlighter-rouge">_xfail_checks</code> is no longer present
in the new tags. That tag was used to tell the common testing tools about the tests
which are known to fail and are to be skipped. That information is now directly passed
to the test functionalities. The old way of skipping a test was the following:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.base</span> <span class="kn">import</span> <span class="n">BaseEstimator</span><span class="p">,</span> <span class="n">ClassifierMixin</span>

<span class="k">class</span> <span class="nc">MyEstimator</span><span class="p">(</span><span class="n">ClassifierMixin</span><span class="p">,</span> <span class="n">BaseEstimator</span><span class="p">):</span>

  <span class="p">...</span>

  <span class="k">def</span> <span class="nf">_more_tags</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="k">return</span> <span class="p">{</span>
      <span class="s">"_xfail_checks"</span><span class="p">:</span> <span class="p">{</span>
        <span class="s">"check_to_skip_name"</span><span class="p">:</span> <span class="s">"this check is known to fail"</span><span class="p">,</span>
        <span class="p">...</span>
      <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p>And then when calling <code class="language-plaintext highlighter-rouge">check_estimator</code> or using <code class="language-plaintext highlighter-rouge">parametrize_with_checks</code> with <code class="language-plaintext highlighter-rouge">pytest</code>
would automatically ignore those tests for the estimator.</p>

<p>Instead, in this release, you pass that information directly to those methods:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.utils.estimator_checks</span> <span class="kn">import</span> <span class="n">check_estimator</span><span class="p">,</span> <span class="n">parametrize_with_checks</span>

<span class="n">CHECKS_EXPECTED_TO_FAIL</span> <span class="o">=</span> <span class="p">{</span>
  <span class="s">"check_to_skip_name"</span><span class="p">:</span> <span class="s">"this check is known to fail"</span><span class="p">,</span>
  <span class="p">...</span>
<span class="p">}</span>

<span class="c1"># Using check_estimator
</span><span class="k">def</span> <span class="nf">test_with_check_estimator</span><span class="p">():</span>
  <span class="n">check_estimator</span><span class="p">(</span><span class="n">MyEstimator</span><span class="p">(),</span> <span class="n">expected_failed_checks</span><span class="o">=</span><span class="n">CHECKS_EXPECTED_TO_FAIL</span><span class="p">)</span>

<span class="c1"># Using parametrize_with_checks
</span><span class="o">@</span><span class="n">parametrize_with_checks</span><span class="p">(</span>
  <span class="p">[</span><span class="n">MyEstimator</span><span class="p">()],</span>
  <span class="n">expected_failed_checks</span><span class="o">=</span><span class="k">lambda</span> <span class="n">est</span><span class="p">:</span> <span class="n">CHECKS_EXPECTED_TO_FAIL</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">test_with_parametrize_with_checks</span><span class="p">(</span><span class="n">estimator</span><span class="p">,</span> <span class="n">check</span><span class="p">):</span>
  <span class="n">check</span><span class="p">(</span><span class="n">estimator</span><span class="p">)</span>
</code></pre></div></div>

<p>While working on the testing infrastructure, we have also been working on improving our
tests and that means in this release we had a particularly high number of changes in
their names and what they do. The changes will make it easier for developers to fix
issues with their estimators. Note that you can now pass <code class="language-plaintext highlighter-rouge">legacy=False</code> to both
<code class="language-plaintext highlighter-rouge">check_estimator</code> and <code class="language-plaintext highlighter-rouge">parametrize_with_checks</code> to include only strictly API related
tests.</p>

<p>The above changes mean developers need to update their estimators and depending on
what they use, write scikit-learn version specific code to handle supporting multiple
scikit-learn versions. To make that process easier, we’ve worked on a package called
<a href="https://github.com/sklearn-compat/sklearn-compat/"><code class="language-plaintext highlighter-rouge">sklearn_compat</code></a>. You can either
depend on it as a package dependency, or vendor a single file inside your project. At
the moment this project is in its infancy and might change in the future. But hopefully
it helps developers out there.</p>

<p>If you think there are missing functionalities in the developer API, please let us know
and give us feedback on our <a href="https://github.com/scikit-learn/scikit-learn/issues">issue tracker</a>.</p>]]></content><author><name>{&quot;bio&quot;=&gt;&quot;Open source library for machine learning in Python.&quot;, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github-square&quot;, &quot;url&quot;=&gt;&quot;https://github.com/scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;LinkedIn&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-linkedin&quot;, &quot;url&quot;=&gt;&quot;https://linkedin.com/company/scikit-learn/&quot;}, {&quot;label&quot;=&gt;&quot;Bluesky&quot;, &quot;icon&quot;=&gt;&quot;&quot;, &quot;url&quot;=&gt;&quot;https://bsky.app/profile/scikit-learn.org&quot;}, {&quot;label&quot;=&gt;&quot;Mastodon&quot;, &quot;icon&quot;=&gt;&quot;fab fa-brands fa-mastodon&quot;, &quot;url&quot;=&gt;&quot;https://fosstodon.org/@sklearn&quot;}, {&quot;label&quot;=&gt;&quot;YouTube&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-youtube&quot;, &quot;url&quot;=&gt;&quot;https://www.youtube.com/@scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;Facebook&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-facebook-square&quot;, &quot;url&quot;=&gt;&quot;https://facebook.com/scikitlearnofficial/&quot;}, {&quot;label&quot;=&gt;&quot;Instagram&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-instagram&quot;, &quot;url&quot;=&gt;&quot;https://instagram.com/scikitlearnofficial/&quot;}]}</name></author><category term="Updates" /><category term="Open Source" /><category term="Machine Learning" /><category term="License" /><summary type="html"><![CDATA[Author: Adrin Jalali]]></summary></entry><entry><title type="html">Announcing the launch of the scikit-learn user survey</title><link href="https://blog.scikit-learn.org/updates/survey-announcement/" rel="alternate" type="text/html" title="Announcing the launch of the scikit-learn user survey" /><published>2024-09-02T00:00:00+00:00</published><updated>2024-09-02T00:00:00+00:00</updated><id>https://blog.scikit-learn.org/updates/survey-announcement</id><content type="html" xml:base="https://blog.scikit-learn.org/updates/survey-announcement/"><![CDATA[<div>
  <img src="/assets/images/posts_images/" alt="" />
  

  
  
  
  

  

  

Author:  
      <a itemprop="sameAs" content="https://github.com/inessapawson" href="https://github.com/inessapawson" rel="me noopener noreferrer" style="vertical-align:top;"><img src="/assets/images/author_images/inessa-pawson.jpg" style="width:1em;margin-right:.5em;border-radius: 50%;" alt="Author Icon" class="orcid-icon" />Inessa Pawson</a>
      
        <a href="mailto:inessapawson@gmail.com" title="inessapawson@gmail.com"><span><i class="elastic-fai fas fa-envelope"></i></span></a>
      , 


  
  
  
  

  

  


      <a itemprop="sameAs" content="https://github.com/francoisgoupil" href="https://github.com/francoisgoupil" rel="me noopener noreferrer" style="vertical-align:top;"><img src="/assets/images/author_images/francois_goupil.jpeg" style="width:1em;margin-right:.5em;border-radius: 50%;" alt="Author Icon" class="orcid-icon" />François Goupil</a>
      
        <a href="mailto:francois.goupil@inria.fr" title="francois.goupil@inria.fr"><span><i class="elastic-fai fas fa-envelope"></i></span></a>
      

<br /><br />

</div>

<p>We are excited to announce the launch of the scikit-learn user survey! Scikit-learn
continues to evolve thanks to contributions from its diverse user community. As we plan
for future releases, we want to ensure we are focusing on what matters most to you — our
users.</p>

<p>The goal of this survey is to better understand how users interact with the library,
identify any pain points, learn about the features you find most useful, and what’s
missing. This is your chance to have a say in how the library grows and adapts to meet
the evolving needs of the machine learning community.</p>

<p>The survey will take about 15 minutes of your time. It is available in Arabic, French,
English, Japanese, Mandarin, Spanish, and Portuguese. You have the option to remain
completely anonymous, and the data collected will be used solely for the purpose of
improving scikit-learn.</p>

<p>This user survey is a truly collaborative effort. We would like to thank the teams from
probabl, University of Oxford (UK), and POSSEE OpenTeams, as well as many scikit-learn
contributors, for their time and effort in designing and translating it.</p>

<p>Once the survey closes, we’ll analyze the responses and publish the findings in a
follow-up blog post.</p>

<p>To take the survey, visit: 
<a href="https://forms.gle/p5P7AweCJCbFMzfo6">https://forms.gle/p5P7AweCJCbFMzfo6</a>. 
The survey will remain open until October 14th, 2024, and we encourage you to share it with your 
colleagues and extended network.</p>

<p>We value every contribution in our community, and we’re committed to making scikit-learn
even better. Your feedback is the foundation upon which scikit-learn will continue to
grow and evolve. We look forward to hearing from you!</p>]]></content><author><name>{&quot;bio&quot;=&gt;&quot;Open source library for machine learning in Python.&quot;, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github-square&quot;, &quot;url&quot;=&gt;&quot;https://github.com/scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;LinkedIn&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-linkedin&quot;, &quot;url&quot;=&gt;&quot;https://linkedin.com/company/scikit-learn/&quot;}, {&quot;label&quot;=&gt;&quot;Bluesky&quot;, &quot;icon&quot;=&gt;&quot;&quot;, &quot;url&quot;=&gt;&quot;https://bsky.app/profile/scikit-learn.org&quot;}, {&quot;label&quot;=&gt;&quot;Mastodon&quot;, &quot;icon&quot;=&gt;&quot;fab fa-brands fa-mastodon&quot;, &quot;url&quot;=&gt;&quot;https://fosstodon.org/@sklearn&quot;}, {&quot;label&quot;=&gt;&quot;YouTube&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-youtube&quot;, &quot;url&quot;=&gt;&quot;https://www.youtube.com/@scikit-learn&quot;}, {&quot;label&quot;=&gt;&quot;Facebook&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-facebook-square&quot;, &quot;url&quot;=&gt;&quot;https://facebook.com/scikitlearnofficial/&quot;}, {&quot;label&quot;=&gt;&quot;Instagram&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-instagram&quot;, &quot;url&quot;=&gt;&quot;https://instagram.com/scikitlearnofficial/&quot;}]}</name></author><category term="Updates" /><category term="Community" /><category term="Open Source" /><summary type="html"><![CDATA[Author: Inessa Pawson , François Goupil]]></summary></entry></feed>