Примечание
Перейти в конец, чтобы скачать полный код примера или запустить этот пример в браузере с помощью JupyterLite или Binder.
Заполнение пропущенных значений перед построением оценщика
Пропущенные значения можно заменить средним, медианой или наиболее часто встречающимся значением с помощью базового SimpleImputer.
В этом примере мы рассмотрим различные методы заполнения пропущенных значений:
- заполнение постоянным значением 0
- заполнение средним значением каждого признака
- заполнение методом k ближайших соседей
- итеративное заполнение
Во всех случаях для каждого признака мы добавляем новый признак, указывающий на наличие пропущенных значений.
Мы будем использовать два набора данных: набор данных Diabetes, состоящий из 10 признаков, собранных у пациентов с диабетом для прогнозирования прогрессирования заболевания, и набор данных California housing, целевым значением которого является медианная стоимость домов в округах Калифорнии.
Поскольку в этих наборах данных нет пропущенных значений, мы удалим некоторые значения, чтобы создать новые версии с искусственно внесенными пропусками. Затем сравним качество работы RandomForestRegressor на исходном наборе данных и на измененных наборах данных, в которых искусственно внесенные пропущенные значения заполнены разными методами.
# Authors: The scikit-learn developers # SPDX-License-Identifier: BSD-3-Clause
Загрузка данных и создание наборов с пропущенными значениями
Сначала загрузим два набора данных. Набор данных Diabetes входит в состав scikit-learn. Он содержит 442 записи, в каждой из которых 10 признаков. Набор данных California housing значительно больше: 20640 записей и 8 признаков. Его необходимо скачать. Для ускорения вычислений мы будем использовать только первые 300 записей, но вы можете использовать весь набор данных.
import numpy as np
from sklearn.datasets import fetch_california_housing, load_diabetes
X_diabetes, y_diabetes = load_diabetes(return_X_y=True)
X_california, y_california = fetch_california_housing(return_X_y=True)
X_diabetes = X_diabetes[:300]
y_diabetes = y_diabetes[:300]
X_california = X_california[:300]
y_california = y_california[:300]
def add_missing_values(X_full, y_full, rng):
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
rng = np.random.RandomState(42)
X_miss_diabetes, y_miss_diabetes = add_missing_values(X_diabetes, y_diabetes, rng)
X_miss_california, y_miss_california = add_missing_values(
X_california, y_california, rng
)
Заполнение пропущенных данных и оценка качества
Теперь напишем функцию для оценки результатов на данных, заполненных разными методами, а также на полном наборе данных без заполнения пропусков. Для регрессии целевого значения мы будем использовать RandomForestRegressor.
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: F401
from sklearn.impute import IterativeImputer, KNNImputer, SimpleImputer
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import RobustScaler
N_SPLITS = 4
def get_score(X, y, imputer=None):
regressor = RandomForestRegressor(random_state=0)
if imputer is not None:
estimator = make_pipeline(imputer, regressor)
else:
estimator = regressor
scores = cross_val_score(
estimator, X, y, scoring="neg_mean_squared_error", cv=N_SPLITS
)
return scores.mean(), scores.std()
x_labels = []
mses_diabetes = np.zeros(5)
stds_diabetes = np.zeros(5)
mses_california = np.zeros(5)
stds_california = np.zeros(5)
Оценка качества
Сначала оценим качество на исходных данных:
mses_diabetes[0], stds_diabetes[0] = get_score(X_diabetes, y_diabetes)
mses_california[0], stds_california[0] = get_score(X_california, y_california)
x_labels.append("Full Data")
Замена пропущенных значений на 0
Теперь оценим качество на данных, в которых пропущенные значения заменены на 0:
imputer = SimpleImputer(strategy="constant", fill_value=0, add_indicator=True)
mses_diabetes[1], stds_diabetes[1] = get_score(
X_miss_diabetes, y_miss_diabetes, imputer
)
mses_california[1], stds_california[1] = get_score(
X_miss_california, y_miss_california, imputer
)
x_labels.append("Zero Imputation")
Заполнение пропущенных значений средним
imputer = SimpleImputer(strategy="mean", add_indicator=True)
mses_diabetes[2], stds_diabetes[2] = get_score(
X_miss_diabetes, y_miss_diabetes, imputer
)
mses_california[2], stds_california[2] = get_score(
X_miss_california, y_miss_california, imputer
)
x_labels.append("Mean Imputation")
Заполнение пропущенных значений методом k ближайших соседей
KNNImputer заполняет пропущенные значения взвешенным или невзвешенным средним заданного числа ближайших соседей. Если признаки имеют сильно различающиеся масштабы (как в наборе данных California housing), рассмотрите возможность их масштабирования, чтобы потенциально улучшить качество.
imputer = KNNImputer(add_indicator=True)
mses_diabetes[3], stds_diabetes[3] = get_score(
X_miss_diabetes, y_miss_diabetes, imputer
)
mses_california[3], stds_california[3] = get_score(
X_miss_california, y_miss_california, make_pipeline(RobustScaler(), imputer)
)
x_labels.append("KNN Imputation")
Итеративное заполнение пропущенных значений
Еще один вариант — IterativeImputer. Этот метод использует циклическую регрессию, по очереди моделируя каждый признак с пропущенными значениями как функцию других признаков. Для прогнозирования пропущенных значений признаков мы используем регрессионную модель, выбранную по умолчанию в классе (BayesianRidge). Сильно различающиеся масштабы признаков могут отрицательно сказаться на качестве прогнозирования, поэтому мы масштабируем признаки в наборе данных California housing.
imputer = IterativeImputer(add_indicator=True)
mses_diabetes[4], stds_diabetes[4] = get_score(
X_miss_diabetes, y_miss_diabetes, imputer
)
mses_california[4], stds_california[4] = get_score(
X_miss_california, y_miss_california, make_pipeline(RobustScaler(), imputer)
)
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 минут 8.572 секунды)
Связанные примеры
© 2007–2026 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.9/auto_examples/impute/plot_missing_values.html