Handling missing values

scikit-learn · Practical · 9 min

Most estimators raise on NaN, and how you fill gaps can change results and leak information.

Most scikit-learn estimators reject NaN with "Input X contains NaN". You have three options.

Impute with SimpleImputer: strategy="mean", "median" (robust to outliers), "most_frequent" (works for categories too) or "constant" with fill_value. It learns the fill values on the training data (statistics_) and reuses them, so like any transformer it belongs inside a pipeline.

Keep the signal that a value was missing. Missingness is often informative (a blank "last purchase date" means "never purchased"). add_indicator=True on an imputer appends a 0/1 column per feature that had missing values in training; MissingIndicator does this alone.

Use estimators with native NaN support. HistGradientBoostingClassifier/Regressor learn at each split which side missing values should go to, and in recent versions DecisionTreeClassifier, RandomForestClassifier and others accept NaN too. This is often the best option for trees.

More sophisticated imputers exist: KNNImputer fills from similar rows, and IterativeImputer models each feature from the others (still experimental: from sklearn.experimental import enable_iterative_imputer first). They can help, but are slower and not automatically better; compare them with cross-validation.

Never compute fill values on the full dataset before splitting.

Example

import numpy as np
from sklearn.impute import SimpleImputer
from sklearn.ensemble import HistGradientBoostingRegressor

X_train = np.array([[1.0, 10.0], [np.nan, 20.0], [3.0, np.nan], [5.0, 40.0]])
X_test = np.array([[np.nan, np.nan]])

imp = SimpleImputer(strategy="median", add_indicator=True).fit(X_train)
print(imp.statistics_)            # [ 3. 20.]
print(imp.transform(X_test))      # [[ 3. 20.  1.  1.]] (values + indicators)

y_train = np.array([1.0, 2.0, 3.0, 4.0])
hgb = HistGradientBoostingRegressor(min_samples_leaf=1, max_iter=10)
hgb.fit(X_train, y_train)         # NaN accepted natively
print(hgb.predict(X_test).shape)  # (1,)

Remember

  • SimpleImputer learns fill values on training data; keep it in the pipeline
  • add_indicator=True preserves the information that a value was missing
  • Histogram gradient boosting handles NaN natively

Watch out for

  • Filling NaN with the mean of the whole dataset before the train/test split.

Check yourself

  1. Why might you set add_indicator=True on an imputer?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: scikit-learn.org/stable/modules/impute.html