在数据分析和机器学习中,处理缺失值是一个常见的问题。迭代插补是一种有效的处理方法,它通过模拟不同变量之间的复杂关系来估计缺失值。本文将探讨如何使用迭代插补与多种回归分析器结合,以提高模型的准确性。
在本例中,比较了几种不同的估计器,用于缺失特征的插补,包括贝叶斯岭回归、随机森林回归、最近邻回归等。特别关注的是迭代插补器模仿missForest的能力,missForest是一个流行的R语言插补包。需要注意的是,最近邻回归与KNN插补不同,后者通过使用考虑缺失值的距离度量从有缺失值的样本中学习,而不是插补它们。
目标是比较不同的估计器,看看哪一个最适合迭代插补器。在加利福尼亚房屋数据集上使用贝叶斯岭估计器时,发现贝叶斯岭回归和随机森林回归给出了最好的结果。值得注意的是,一些估计器如直方梯度提升回归估计器可以原生处理缺失特征,通常推荐使用,而不是构建复杂的缺失值插补策略的管道。
为了进行比较,首先导入必要的库,包括matplotlib、numpy、pandas和scikit-learn中的相关模块。然后,从scikit-learn的datasets模块中获取加利福尼亚房屋数据集,并对其进行处理,以模拟每行数据中随机移除一个值的情况。
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.datasets import fetch_california_housing
from sklearn.ensemble import RandomForestRegressor
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer, SimpleImputer
from sklearn.kernel_approximation import Nystroem
from sklearn.linear_model import BayesianRidge, Ridge
from sklearn.model_selection import cross_val_score
from sklearn.neighbors import KNeighborsRegressor
from sklearn.pipeline import make_pipeline
N_SPLITS = 5
rng = np.random.RandomState(0)
X_full, y_full = fetch_california_housing(return_X_y=True)
X_full = X_full[:::10]
y_full = y_full[:::10]
n_samples, n_features = X_full.shape
接下来,使用贝叶斯岭回归估计器对完整数据集进行评分,然后向每行数据中添加一个缺失值,并使用不同的插补策略进行评分。最后,使用迭代插补器与不同的估计器结合,对缺失值进行插补,并评分。
# 估计完整数据集的分数,没有缺失值
br_estimator = BayesianRidge()
score_full_data = pd.DataFrame(cross_val_score(br_estimator, X_full, y_full, scoring="neg_mean_squared_error", cv=N_SPLITS), columns=["Full Data"])
# 向每行添加一个缺失值
X_missing = X_full.copy()
y_missing = y_full
missing_samples = np.arange(n_samples)
missing_features = rng.choice(n_features, n_samples, replace=True)
X_missing[missing_samples, missing_features] = np.nan
# 使用不同的插补策略估计分数
score_simple_imputer = pd.DataFrame()
for strategy in ("mean", "median"):
estimator = make_pipeline(SimpleImputer(missing_values=np.nan, strategy=strategy), br_estimator)
score_simple_imputer[strategy] = cross_val_score(estimator, X_missing, y_missing, scoring="neg_mean_squared_error", cv=N_SPLITS)
# 使用迭代插补器与不同的估计器结合估计分数
estimators = [
BayesianRidge(),
RandomForestRegressor(n_estimators=4, max_depth=10, bootstrap=True, max_samples=0.5, n_jobs=2, random_state=0),
make_pipeline(Nystroem(kernel="polynomial", degree=2, random_state=0), Ridge(alpha=1e3)),
KNeighborsRegressor(n_neighbors=15),
]
score_iterative_imputer = pd.DataFrame()
tolerances = (1e-3, 1e-1, 1e-1, 1e-2)
for impute_estimator, tol in zip(estimators, tolerances):
estimator = make_pipeline(IterativeImputer(random_state=0, estimator=impute_estimator, max_iter=25, tol=tol), br_estimator)
score_iterative_imputer[impute_estimator.__class__.__name__] = cross_val_score(estimator, X_missing, y_missing, scoring="neg_mean_squared_error", cv=N_SPLITS)
scores = pd.concat([score_full_data, score_simple_imputer, score_iterative_imputer], keys=["Original", "SimpleImputer", "IterativeImputer"], axis=1)
最后,使用matplotlib绘制加利福尼亚房屋回归结果,比较不同的插补方法。图表显示了不同方法的平均均方误差(MSE),较小的MSE表示更好的性能。
fig, ax = plt.subplots(figsize=(13, 6))
means = -scores.mean()
errors = scores.std()
means.plot.barh(xerr=errors, ax=ax)
ax.set_title("California Housing Regression with Different Imputation Methods")
ax.set_xlabel("MSE (smaller is better)")
ax.set_yticks(np.arange(means.shape[0]))
ax.set_yticklabels([" w/ ".join(label) for label in means.index.tolist()])
plt.tight_layout(pad=1)
plt.show()