Concepts / Creating Custom Estimators in scikit-learn

Creating Custom Estimators in scikit-learn

The offset must be learned before the held-out rows are transformed, and it must be learned only from the training rows of that fold.

  • Programming

Where Built-In Tools Run Out

By this point you have seen a wide range of tools and algorithms that scikit-learn provides. They cover many common machine learning tasks, and for most projects you can assemble a workflow from them without writing anything new. Real projects, however, often have a structure, a rule, or a transformation that is specific to the problem at hand. When that happens, no built-in class may do exactly the work your data needs.

This article follows one practical question: when does a missing processing step push you toward writing your own estimator, and when can you avoid that? The answer depends on a single property of the step, namely whether it depends on the data it is given. Keep that property in mind as we trace what happens to a step as it moves through a workflow.

A Step That Can Be Applied Once

The simplest case is a processing step you can carry out on your data before it reaches a scikit-learn model or pipeline. You transform the data first, then pass the result to the estimator. Nothing about the model's training process has to know how the transformation was produced, so the rest of your code can treat the output as ordinary input.

Because the transformation is a fixed operation that happens outside the modeling workflow, writing a custom estimator is usually not required for a step like this. The key idea is that the transformation's output does not depend on what the rest of the dataset looks like. Each row is processed by the same fixed rule, so the step can be run once over everything you have.

When the Step Must Learn From the Data

Definition

Data-dependent preprocessing is a processing step whose behavior is determined by the data it is given. The step learns something from the rows it receives, and that learned value then shapes how it transforms the data.

The source identifies this as the difficult case. Here the processing you apply is determined by the data itself, and that changes the picture. If you want to use grid search or cross-validation, the simple approach of preprocessing everything up front becomes unreliable, and the work gets trickier.

To make this concrete, consider an illustrative step that shifts each value so the data is centered around zero. The amount it subtracts is the average of the values it was given. This is a teaching example created for this article, not one taken from the source, and it is chosen only to show why the step depends on the data.

Rule

Here $n$ is the number of values the step was given, and each $x_i$ is one of those values. The centering step learns $\bar{x}$ from the data and then subtracts it from every value. Notice that the offset is not a fixed number you could write down in advance. It exists only because of the particular values the step saw.

Tracing a Centering Step Through Its Values

Worked example

Centering a Small Set of Values

A centering step is given the values 4, 6, 8, and 10. What offset does it learn, and what does it output?

  1. 1
    Learn the offset

    The step averages the values it was given: (4 + 6 + 8 + 10) / 4 = 28 / 4 = 7. The learned offset is 7.

  2. 2
    Apply the offset

    The step subtracts 7 from each value: 4 becomes -3, 6 becomes -1, 8 becomes 1, and 10 becomes 3.

  3. 3
    Check the state

    The output values now average to zero. The offset of 7 is part of the step's state, because a different set of input values would have produced a different offset.

Result

The learned offset is 7, and the centered output is -3, -1, 1, 3.

Why Each Fold Needs Its Own Offset

Grid search and cross-validation both repeatedly split data and evaluate a model on different portions of it. Each time, one portion is used to train and another is held back to evaluate. A data-dependent step has to be fitted again for each of these portions, because the values it learns belong to the portion it was fitted on.

The diagram below follows one fold. The step learns its offset only from the training portion of that fold. The held-out portion is then transformed using that offset, and the held-out rows never contribute to the value the step learned.

Training portionrows used to learnCentering steplearns and applies offsetHeld-out portionrows only transformedModel evaluationscore for this fold1. offset learned from these rows2. same offset subtracted3. centered rows scored
Within a single fold, which data is used to learn the offset, and which data is only transformed, and in what order do these happen?

The order matters. The offset must be learned before the held-out rows are transformed, and it must be learned only from the training rows of that fold. If the held-out rows were allowed to influence the offset, the evaluation would no longer measure how the step behaves on data it has not seen.

Why Grid Search Multiplies the Problem

Grid search adds another layer. It tries many parameter settings, and for each setting it runs a full cross-validation. So a single data-dependent step may have to learn its state many times over: once for each parameter setting, and once for each fold within that setting. The learned state from one run must not carry over into another.

Parameter settingone candidate in the gridTraining rows of afoldfresh for each foldLearned offsetcomputed from this foldonlyScore for thiscandidateaveraged over foldsHeld-out rows of samefoldtransformed with thatoffsetsplit into foldsstep learns statestate appliedfold result
When grid search tries a new parameter setting, where does the step's learned state come from, and how is it recomputed for each fold?

Reading the flow from the top, the parameter setting is never the source of the learned state. The state always comes from the training rows of a particular fold, and it is recomputed for every fold of every candidate. This is the reason the source says that data-dependent preprocessing makes grid search and cross-validation harder to combine with a preprocess-first workflow.

Applied Once Versus Data-Dependent

The two kinds of step can now be set side by side. What separates them is whether the output for a given row would change if the rest of the dataset were different.

Fixedtransformationsame rule for every rowOutput independent ofother rowsRun before theworkflowno custom estimator neededData-dependent steprule set by the dataOutput depends ontraining rowse.g. a learned averageFitted again per foldcustom estimator is the fitleads toleads toleads toleads to
What is the difference between a transformation whose output is the same no matter which rows are seen, and one whose output depends on statistics learned from the training rows?

The fixed transformation can be carried out once on the whole dataset, and the rest of the workflow treats its output as ordinary input. The data-dependent step cannot be settled in advance, because its output depends on the statistics it learns from whichever rows it is given. That is the situation where, according to the source, a custom estimator is needed in order to work with scikit-learn's tools.

What a Custom Estimator Carries With It

A custom estimator is the natural way to express a data-dependent step in a form that scikit-learn's tools can work with. The reason is that the step then carries its own learned state with it. In the centering example, the offset of 7 from the earlier worked example would be stored as part of the step itself, rather than being computed by hand outside the workflow and passed along separately.

Because the state travels with the step, the library's tools can learn it from the training portion of each fold and reuse it for the held-out portion, without you rewriting the procedure for every split. The source does not go into implementation details at this point, so the purpose to remember is the condition itself: a custom estimator is needed when a step's behavior is data-dependent and the workflow must also handle grid search or cross-validation.

Mistakes That Undermine Cross-Validation

  • Common mistake

    Learning the data-dependent offset from the whole dataset before splitting

    What it looks like

    The average is computed over all rows, then the data is split into folds for grid search.

    Why it fails

    The held-out rows have already influenced the learned state, so the evaluation no longer reflects unseen data.

    Do this instead

    Let the step learn its state only from the training portion of each fold, recomputing it for every split.

  • Common mistake

    Assuming a fixed transformation needs a custom estimator

    Why it fails

    A step whose output does not depend on the data can be carried out once before the workflow begins.

    Do this instead

    Apply fixed transformations up front, and save the custom estimator for steps whose behavior is data-dependent.

  • Common mistake

    Believing grid search reuses one learned state across all parameter settings

Checking Your Understanding of a Centering Step

EASY

A centering step is given the values 2, 4, 6, and 8 in one training fold. Using the same rule as the worked example, what offset does it learn? Then, if the held-out fold contains the value 10, what centered value does it produce using that offset?

Hints
  • The offset is the average of the training values only.
  • Average 2, 4, 6, and 8, then subtract that offset from 10.
MEDIUM

Explain in your own words why the offset learned for one fold cannot simply be reused for a different fold during cross-validation.

Hints
  • Think about which rows the offset was computed from.
  • Consider what it would mean for the held-out rows to influence the step's learned state.

Key Takeaways

  • Built-in scikit-learn tools cover many common tasks, but a dataset may need a processing step the library does not supply, and then a custom step is required.
  • A preprocessing step whose output does not depend on the data can usually be applied once before the model or pipeline, without a custom estimator.
  • A data-dependent step learns its behavior from the rows it receives, so it must be fitted again for each training portion used in grid search and cross-validation.
  • A custom estimator is the natural way to express a data-dependent step in a form scikit-learn's tools can use, because the step carries its learned state with it.
  • Write a custom estimator when a step's behavior is data-dependent and the workflow must also handle grid search or cross-validation.

Related concepts

More concepts starting with C