scikit-learn
machine learning
data preprocessing
categorical data
imputation

Sklearn Categorical Imputer?

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

scikit-learn does not ship a dedicated estimator literally named CategoricalImputer, but categorical imputation is fully supported. The standard approach is to use SimpleImputer on categorical columns, usually with strategy="most_frequent" or strategy="constant", and place that inside a Pipeline so the same logic runs during both training and inference.

There Is No Special Class, and That Is Fine

The old question often comes from tutorials or code samples that mention a CategoricalImputer helper class. In modern scikit-learn, you normally do not need that extra abstraction because SimpleImputer already works column by column and supports object and string-like data.

That is the key idea:

  • numeric columns often use mean or median
  • categorical columns usually use most_frequent or constant

The estimator is the same. The configuration changes based on the data type.

The Two Most Common Strategies

For categorical features, the main choices are:

  • fill missing values with the most common category
  • fill missing values with a placeholder such as "missing"

A simple example with the mode strategy looks like this:

python
1import pandas as pd
2from sklearn.impute import SimpleImputer
3
4X = pd.DataFrame(
5    {
6        "city": ["Toronto", None, "Montreal", "Toronto"],
7        "segment": ["retail", "retail", None, "enterprise"],
8    }
9)
10
11imputer = SimpleImputer(strategy="most_frequent")
12filled = imputer.fit_transform(X)
13print(filled)

This works well when missing values are uncommon and you want to keep the feature inside its original category set.

The placeholder strategy is also very common:

python
1import pandas as pd
2from sklearn.impute import SimpleImputer
3
4X = pd.DataFrame(
5    {
6        "city": ["Toronto", None, "Montreal", "Toronto"],
7        "segment": ["retail", "retail", None, "enterprise"],
8    }
9)
10
11imputer = SimpleImputer(strategy="constant", fill_value="missing")
12filled = imputer.fit_transform(X)
13print(filled)

That approach preserves the fact that the value was absent, which can be useful if missingness itself carries information.

Put Categorical Imputation Inside a Real Pipeline

In practice, imputation is rarely the only preprocessing step. Categorical columns usually also need encoding, while numeric columns may need a different imputation strategy entirely.

That is why ColumnTransformer and Pipeline are the normal scikit-learn pattern.

python
1import pandas as pd
2from sklearn.compose import ColumnTransformer
3from sklearn.impute import SimpleImputer
4from sklearn.linear_model import LogisticRegression
5from sklearn.pipeline import Pipeline
6from sklearn.preprocessing import OneHotEncoder
7
8X = pd.DataFrame(
9    {
10        "city": ["Toronto", None, "Montreal", "Toronto"],
11        "segment": ["retail", "retail", None, "enterprise"],
12        "age": [34, None, 29, 41],
13    }
14)
15y = [1, 0, 1, 0]
16
17categorical_features = ["city", "segment"]
18numeric_features = ["age"]
19
20categorical_pipeline = Pipeline([
21    ("imputer", SimpleImputer(strategy="constant", fill_value="missing")),
22    ("encoder", OneHotEncoder(handle_unknown="ignore")),
23])
24
25numeric_pipeline = Pipeline([
26    ("imputer", SimpleImputer(strategy="median")),
27])
28
29preprocessor = ColumnTransformer([
30    ("cat", categorical_pipeline, categorical_features),
31    ("num", numeric_pipeline, numeric_features),
32])
33
34model = Pipeline([
35    ("preprocessor", preprocessor),
36    ("classifier", LogisticRegression()),
37])
38
39model.fit(X, y)
40print(model.predict(X))

This is usually better than filling missing values with pandas outside the model pipeline because the transformation is now part of the fitted object. That makes training and prediction behavior consistent.

How To Choose Between most_frequent and constant

most_frequent is a good default when missing values are rare and you believe the best guess is the dominant category.

constant is often better when the absence of a value is meaningful. After one-hot encoding, the placeholder becomes its own feature, so the model can treat "missing" differently from real categories.

There is no universal winner. The choice depends on the semantics of the data.

For example:

  • missing marital_status might mean incomplete form entry and be informative
  • missing browser_type might just be noise and be fine to replace with the most common value

When You Might Need More Than SimpleImputer

Sometimes the fill rule depends on other columns or on grouped behavior. Examples include:

  • fill missing city based on country
  • fill category based on the most frequent value within each customer segment
  • use a learned model to predict the missing category

At that point, SimpleImputer may no longer be enough, and a custom transformer can make sense. But for ordinary categorical missing values, SimpleImputer is the correct built-in solution.

Common Pitfalls

A common mistake is searching for a class literally called CategoricalImputer and assuming scikit-learn lacks categorical support when that name is not found. The supported tool is SimpleImputer.

Another mistake is imputing values with pandas before the pipeline and forgetting to apply the same transformation at inference time. That creates train-serving drift.

People also often choose most_frequent automatically without asking whether missingness should be modeled explicitly. Sometimes a dedicated "missing" category is the better design.

Finally, imputation and encoding solve different problems. Filling nulls does not handle unseen categories at prediction time, so you still need an encoder configured safely, such as OneHotEncoder(handle_unknown="ignore").

Summary

  • scikit-learn does not need a separate CategoricalImputer class because SimpleImputer already handles categorical columns.
  • For categorical features, use strategy="most_frequent" or strategy="constant" most of the time.
  • Put imputation inside a Pipeline and ColumnTransformer so preprocessing stays consistent.
  • Use a placeholder category when missingness itself may carry signal.
  • Move to a custom transformer only when the fill logic depends on more than the current column.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.