Spec-Zone.ru › scikit-learn

Примечание

Перейти к концу для загрузки полного примера кода. Или запустить этот пример в браузере через 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()
Imputation Techniques with Diabetes Data, Imputation Techniques with California Data

Вы также можете попробовать разные методы. Например, медиана является более устойчивой оценкой для данных с переменными высокой величины, которые могут доминировать в результатах (иначе известная как «длинный хвост»).

Общее время выполнения сценария: (0 минут 9.437 секунд)

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_missing_values.ipynb

Download Python source code: plot_missing_values.py

Download zipped: plot_missing_values.zip

Связанные примеры

Заполнение пропущенных значений с вариантами IterativeImputer

Основные моменты выпуска scikit-learn 0.22

Анализ типа концентрационного предиката для изменения смеси Гауссовских распределений Байеса

Основные моменты выпуска scikit-learn 1.5

© 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API