注意
转到末尾以下载完整示例代码或通过 JupyterLite 或 Binder 在浏览器中运行此示例。
在构建估算器之前填充缺失值#
使用基本的 SimpleImputer 可以将缺失值替换为均值、中位数或最频繁值。
在本例中,我们将研究不同的填充技术:
使用常量值 0 进行填充
使用每个特征的均值进行填充
k 近邻填充
迭代填充
在所有情况下,对于每个特征,我们都会添加一个指示缺失性的新特征。
我们将使用两个数据集:糖尿病数据集,其中包含从糖尿病患者收集的 10 个特征变量,旨在预测疾病进展;加州住房数据集,其目标是加州各区的中位数房价。
由于这些数据集都没有缺失值,我们将删除一些值来创建具有人工缺失数据的新版本。然后,将 RandomForestRegressor 在完整原始数据集上的性能与在经过不同技术填充人工缺失值后的更改数据集上的性能进行比较。
# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause
下载数据并创建缺失值集#
首先,我们下载这两个数据集。糖尿病数据集随 scikit-learn 提供。它有 442 个条目,每个条目有 10 个特征。加州住房数据集要大得多,有 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")
kNN 填充缺失值#
KNNImputer 使用所需数量的最近邻的加权或非加权均值来填充缺失值。如果您的特征具有截然不同的尺度(如加州住房数据集),请考虑重新缩放它们以潜在地提高性能。
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)来预测缺失特征值。预测器的性能可能会受到特征尺度截然不同的负面影响,因此我们重新缩放加州住房数据集中的特征。
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 minutes 8.208 seconds)
相关示例