Примечание
Перейти к концу для загрузки полного примера кода. Или запустить этот пример в браузере через JupyterLite или Binder
Заполнение пропущенных значений перед построением оценщика
Пропущенные значения можно заменить средним, медианой или наиболее частым значением, используя базовый SimpleImputer.
В этом примере мы рассмотрим различные методы заполнения:
- Заполнение константным значением 0
- Заполнение средним значением каждого признака в сочетании с дополнительной переменной индикатора пропущенных значений
- Заполнение методом k ближайших соседей
- Итеративное заполнение
Мы будем использовать два набора данных: набор данных по диабету, который состоит из 10 переменных признаков, собранных от пациентов с диабетом с целью прогнозирования прогрессирования заболевания, и набор данных по жилищному строительству Калифорнии, для которого целевым значением является медианная стоимость домов в районах Калифорнии.
Поскольку ни один из этих наборов данных не содержит пропущенных значений, мы удалим некоторые значения, чтобы создать новые версии с искусственно пропущенными данными. Затем сравнивается производительность RandomForestRegressor на полном исходном наборе данных с производительностью на измененных наборах данных с искусственно пропущенными значениями, заполненными с использованием различных методов.
# Authors: The scikit-learn developers # SPDX-License-Identifier: BSD-3-Clause
Загрузка данных и создание наборов с пропущенными значениями
Сначала мы загружаем два набора данных. Набор данных по диабету поставляется с scikit-learn. Он содержит 442 записи, каждая с 10 признаками. Набор данных по жилищному строительству Калифорнии намного больше, с 20640 записями и 8 признаками. Его необходимо загрузить. Мы будем использовать только первые 400 записей для ускорения вычислений, но можете использовать весь набор данных.
import numpy as np
from sklearn.datasets import fetch_california_housing, load_diabetes
rng = np.random.RandomState(42)
X_diabetes, y_diabetes = load_diabetes(return_X_y=True)
X_california, y_california = fetch_california_housing(return_X_y=True)
X_california = X_california[:300]
y_california = y_california[:300]
X_diabetes = X_diabetes[:300]
y_diabetes = y_diabetes[:300]
def add_missing_values(X_full, y_full):
n_samples, n_features = X_full.shape
# Add missing values in 75% of the lines
missing_rate = 0.75
n_missing_samples = int(n_samples * missing_rate)
missing_samples = np.zeros(n_samples, dtype=bool)
missing_samples[:n_missing_samples] = True
rng.shuffle(missing_samples)
missing_features = rng.randint(0, n_features, n_missing_samples)
X_missing = X_full.copy()
X_missing[missing_samples, missing_features] = np.nan
y_missing = y_full.copy()
return X_missing, y_missing
X_miss_california, y_miss_california = add_missing_values(X_california, y_california)
X_miss_diabetes, y_miss_diabetes = add_missing_values(X_diabetes, y_diabetes)
Заполнение пропущенных данных и оценка
Теперь мы напишем функцию, которая будет оценивать результаты на данных с разными методами заполнения. Давайте рассмотрим каждый метод заполнения по отдельности:
rng = np.random.RandomState(0) from sklearn.ensemble import RandomForestRegressor # To use the experimental IterativeImputer, we need to explicitly ask for it: from sklearn.experimental import enable_iterative_imputer # noqa from sklearn.impute import IterativeImputer, KNNImputer, SimpleImputer from sklearn.model_selection import cross_val_score from sklearn.pipeline import make_pipeline N_SPLITS = 4 regressor = RandomForestRegressor(random_state=0)
Пропущенная информация
Помимо заполнения пропущенных значений, методы заполнения имеют add_indicator параметр, который отмечает пропущенные значения, которые могут нести некоторую информацию.
def get_scores_for_imputer(imputer, X_missing, y_missing):
estimator = make_pipeline(imputer, regressor)
impute_scores = cross_val_score(
estimator, X_missing, y_missing, scoring="neg_mean_squared_error", cv=N_SPLITS
)
return impute_scores
x_labels = []
mses_california = np.zeros(5)
stds_california = np.zeros(5)
mses_diabetes = np.zeros(5)
stds_diabetes = np.zeros(5)
Оценка результата
Сначала мы хотим оценить результат на исходных данных:
def get_full_score(X_full, y_full):
full_scores = cross_val_score(
regressor, X_full, y_full, scoring="neg_mean_squared_error", cv=N_SPLITS
)
return full_scores.mean(), full_scores.std()
mses_california[0], stds_california[0] = get_full_score(X_california, y_california)
mses_diabetes[0], stds_diabetes[0] = get_full_score(X_diabetes, y_diabetes)
x_labels.append("Full data")
Замена пропущенных значений на 0
Теперь мы оценим результат на данных, где пропущенные значения заменены на 0:
def get_impute_zero_score(X_missing, y_missing):
imputer = SimpleImputer(
missing_values=np.nan, add_indicator=True, strategy="constant", fill_value=0
)
zero_impute_scores = get_scores_for_imputer(imputer, X_missing, y_missing)
return zero_impute_scores.mean(), zero_impute_scores.std()
mses_california[1], stds_california[1] = get_impute_zero_score(
X_miss_california, y_miss_california
)
mses_diabetes[1], stds_diabetes[1] = get_impute_zero_score(
X_miss_diabetes, y_miss_diabetes
)
x_labels.append("Zero imputation")
Заполнение методом k ближайших соседей
KNNImputer заполняет пропущенные значения, используя взвешенное или невзвешенное среднее желаемого числа ближайших соседей.
def get_impute_knn_score(X_missing, y_missing):
imputer = KNNImputer(missing_values=np.nan, add_indicator=True)
knn_impute_scores = get_scores_for_imputer(imputer, X_missing, y_missing)
return knn_impute_scores.mean(), knn_impute_scores.std()
mses_california[2], stds_california[2] = get_impute_knn_score(
X_miss_california, y_miss_california
)
mses_diabetes[2], stds_diabetes[2] = get_impute_knn_score(
X_miss_diabetes, y_miss_diabetes
)
x_labels.append("KNN Imputation")
Заполнение пропущенных значений средним значением
def get_impute_mean(X_missing, y_missing):
imputer = SimpleImputer(missing_values=np.nan, strategy="mean", add_indicator=True)
mean_impute_scores = get_scores_for_imputer(imputer, X_missing, y_missing)
return mean_impute_scores.mean(), mean_impute_scores.std()
mses_california[3], stds_california[3] = get_impute_mean(
X_miss_california, y_miss_california
)
mses_diabetes[3], stds_diabetes[3] = get_impute_mean(X_miss_diabetes, y_miss_diabetes)
x_labels.append("Mean Imputation")
Итеративное заполнение пропущенных значений
Другой вариант - IterativeImputer. Он использует линейную регрессию с круговым обменом, моделируя каждый признак с пропущенными значениями как функцию других признаков, по очереди. Реализация предполагает гауссовы (выходные) переменные. Если ваши признаки явно ненормальные, рассмотрите возможность преобразования их, чтобы они выглядели более нормальными, чтобы потенциально улучшить производительность.
def get_impute_iterative(X_missing, y_missing):
imputer = IterativeImputer(
missing_values=np.nan,
add_indicator=True,
random_state=0,
n_nearest_features=3,
max_iter=1,
sample_posterior=True,
)
iterative_impute_scores = get_scores_for_imputer(imputer, X_missing, y_missing)
return iterative_impute_scores.mean(), iterative_impute_scores.std()
mses_california[4], stds_california[4] = get_impute_iterative(
X_miss_california, y_miss_california
)
mses_diabetes[4], stds_diabetes[4] = get_impute_iterative(
X_miss_diabetes, y_miss_diabetes
)
x_labels.append("Iterative Imputation")
mses_diabetes = mses_diabetes * -1
mses_california = mses_california * -1
Построение результатов
Наконец, мы визуализируем результат:
import matplotlib.pyplot as plt
n_bars = len(mses_diabetes)
xval = np.arange(n_bars)
colors = ["r", "g", "b", "orange", "black"]
# plot diabetes results
plt.figure(figsize=(12, 6))
ax1 = plt.subplot(121)
for j in xval:
ax1.barh(
j,
mses_diabetes[j],
xerr=stds_diabetes[j],
color=colors[j],
alpha=0.6,
align="center",
)
ax1.set_title("Imputation Techniques with Diabetes Data")
ax1.set_xlim(left=np.min(mses_diabetes) * 0.9, right=np.max(mses_diabetes) * 1.1)
ax1.set_yticks(xval)
ax1.set_xlabel("MSE")
ax1.invert_yaxis()
ax1.set_yticklabels(x_labels)
# plot california dataset results
ax2 = plt.subplot(122)
for j in xval:
ax2.barh(
j,
mses_california[j],
xerr=stds_california[j],
color=colors[j],
alpha=0.6,
align="center",
)
ax2.set_title("Imputation Techniques with California Data")
ax2.set_yticks(xval)
ax2.set_xlabel("MSE")
ax2.invert_yaxis()
ax2.set_yticklabels([""] * n_bars)
plt.show()

Вы также можете попробовать разные методы. Например, медиана является более устойчивой оценкой для данных с переменными высокой величины, которые могут доминировать в результатах (иначе известная как «длинный хвост»).
Общее время выполнения сценария: (0 минут 9.437 секунд)
Связанные примеры
© 2007–2025 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.6/auto_examples/impute/plot_missing_values.html