MeanMedianImputer#

均值插补和中位数插补包括用数值变量的均值或中位数替换数值变量中的缺失数据。这些简单的单变量缺失数据插补技术在为数据科学项目准备数据时是最常用的技术之一。例如,可以看看KDD 2009杯的获胜解决方案:使用集成选择赢得KDD杯Orange挑战赛

通常,均值插补和中位数插补会与添加缺失指示符一起进行,以告知模型尽管这个观察值看起来像大多数(即均值或中位数值),但它实际上是一个缺失值。

均值插补 vs 中位数插补#

在实践中,我们使用均值插补或中位数插补,而没有过多考虑我们想要插补的变量的分布。然而,考虑到均值是变量对称分布中心的一个良好估计是很好的。因此,当数据呈现正态分布或分布对称时,我们会使用均值插补,而当变量偏斜时,则使用中位数插补。

偏斜分布会导致均值的估计出现偏差,使其不能准确代表分布的中心。相比之下,中位数对偏斜不敏感。此外,均值对异常值敏感,而中位数则不受影响。因此,在偏斜分布中,中位数是更好的中心位置估计。

在下图中,我们可以看到当变量有强烈的左偏或右偏时,中位数如何偏离分布中心:

../../_images/1024px-Relationship_between_mean_and_median_under_different_skewness.png

在进行统计分析时,这些细节往往更为重要,而在为机器学习预处理数据时,我们往往忽略它们。然而,请记住,一些回归模型和特征选择程序,如ANOVA,对数据的潜在分布有一些假设。你可以通过数据分析来补充你的插补方法,以了解插补如何影响变量的分布及其与其他变量的关系。

变量分布的影响#

用均值或中位数替换缺失值会影响变量的分布及其与数据集中其他变量的关系。如果缺失的数据点很少,这些影响可以忽略不计。然而,如果大量数据缺失,影响就会变得显著。

使用均值或中位数进行插补会减少变量的变异性,例如其标准差,通过在分布中心附近添加更多数据点。随着变异性的减少,以前未被视为异常值的数据点现在可能被简单的检测方法(如IQR(四分位距)接近规则)标记为异常值。

此外,均值和中位数插补会扭曲插补变量与数据集中其他变量之间的关系——如相关性或协方差——,这可能会影响它们与目标变量之间的关系。因此,依赖于条件联合概率估计的模型的输出可能会受到均值插补和中位数插补的影响,特别是当缺失数据的比例较大时。

均值和中位数插补在训练线性回归或逻辑回归模型时通常是首选。相比之下,基于决策树的算法通常使用任意数值进行插补。当变量之间的关系至关重要时,您可能需要考虑更好的缺失数据估计方法,例如多重插补(即,多元插补)。

MeanMedianImputer#

Feature-engine 的 MeanMedianImputer() 用变量的均值或中值替换缺失数据,这些值是根据观测值确定的。因此,它只能对数值变量进行插补。你可以传递你想要插补的变量列表,或者,MeanMedianImputer() 将自动插补训练集中所有数值变量。

Python 实现#

在本节中,我们将探讨 MeanMedianImputer() 的功能。首先,让我们导入所需的库:

import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_openml
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import train_test_split
from feature_engine.imputation import MeanMedianImputer
from feature_engine.imputation import AddMissingIndicator

我们将使用来自 OpenML 的 房价数据集

# Load dataset
X, y = fetch_openml(name='house_prices', version=1, return_X_y=True, as_frame=True, parser='auto')

在以下代码块中,我们将数据集分割为训练集和测试集,只保留三个特征,并且我们将测试集中包含缺失数据的4个观测值单独放置:

target_features = ['Neighborhood','LotFrontage','MasVnrArea']
X = X[target_features]

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Select specific houses with missing data from the test set
target_idx = [113,292,650, 1018]
X_test_subset = X_test.loc[target_idx]

让我们可视化测试集中包含缺失值的子集:

print(X_test_subset)

在以下输出中,我们看到了五栋房子;其中三栋在LotFrontage或MasVnrArea字段中存在缺失值:

         Neighborhood  LotFrontage  MasVnrArea
113       Crawfor          NaN       184.0
292       Edwards         60.0         0.0
650       Somerst         65.0         NaN
1018      Gilbert          NaN        76.0

现在让我们设置并拟合 MeanMedianImputer() ,使用均值策略,以便我们可以对变量 LotFrontageMasVnrArea 进行插补:

# Set up the imputer
mmi = MeanMedianImputer(
        imputation_method='mean',
        variables=['LotFrontage', 'MasVnrArea']
)

# Fit transformer with training data
mmi.fit(X_train)

值得注意的是,我们可以灵活地省略 variables 参数,在这种情况下,MeanMedianImputer() 将自动查找并填充所有数值特征。

在拟合 MeanMedianImputer() 之后,我们可以查看每个变量的统计数据(均值或中位数;在此场景中为均值)以进行插补:

# Show mean values learned with the training data
mmi.imputer_dict_

imputer_dict_ 属性显示了学习到的统计数据:

{'LotFrontage': 70.375, 'MasVnrArea': 105.26104023552503}

这个字典在内部用于填补缺失值。

让我们转换之前预览的包含缺失数据的测试数据子集:

# Transform the subset of the test data
X_test_subset_t = mmi.transform(X_test_subset)

如果我们现在执行 X_test_subset_t.head(),我们将看到包含插补值的完整数据集:

         Neighborhood  LotFrontage  MasVnrArea
113       Crawfor       70.375   184.00000
292       Edwards       60.000     0.00000
650       Somerst       65.000   105.26104
1018      Gilbert       70.375    76.00000

填补缺失值以及缺失指示符#

均值或中位数插补通常与添加缺失指示符一起进行。我们可以使用 Feature-engine 中的 AddMissingIndicator() 来添加缺失指示符。

我们可以使用 scikit-learn 管道AddMissingIndicator()MeanMedianImputer() 连接起来。

例如,让我们创建一个输入器管道来添加缺失指示器,然后填补缺失值:

# Create imputer pipeline
imputer = make_pipeline(
        AddMissingIndicator(),
        MeanMedianImputer()
)

# Fit the pipeline
imputer.fit(X_train)

现在,我们可以转换数据:

X_test_subset_t = imputer.transform(X_test_subset)

如果我们现在执行 X_test_subset_t.head(),我们将看到一个数据框,其中 LotFrontageMasVnrArea 现在是完整的,也就是说,缺失值被观测数据的平均值所替代,并且增加了带有缺失指示符的额外列:

         Neighborhood  LotFrontage  MasVnrArea  LotFrontage_na  MasVnrArea_na
113       Crawfor         70.0       184.0               1              0
292       Edwards         60.0         0.0               0              0
650       Somerst         65.0         0.0               0              1
1018      Gilbert         70.0        76.0               1              0

缺失指示列标记那些原本缺失值的观测。

注意,两个类都自动找到了数值变量,因为我们没有指定 variables 参数。

插补后的分布变化#

让我们分析插补可能如何改变变量的分布。

首先,让我们看看训练数据中LotFrontage的缺失数据有多少:

X_train.LotFrontage.isnull().mean().round(2)

因此,我们可以看到近19%的数据缺失:

0.19

在以下代码中,我们将在左侧面板创建一个原始变量分布图,并在右侧面板创建插补后的分布图:

# Customize plot
sns.set(style="ticks")
plt.rcParams['axes.grid'] = True
plt.rcParams['grid.alpha'] = 0.5

# Create figure
fig,axes = plt.subplots(ncols=2, figsize=(10,4), sharex=True, sharey=True)

# Plot histogram with KDE for the original data
sns.histplot(data=X_train, x='LotFrontage', kde=True, ax=axes[0])
axes[0].set_title('Original', weight='bold', y=1.05)

# Plot histogram with KDE for the transformed data
sns.histplot(data=mmi.transform(X_train), x='LotFrontage', kde=True, ax=axes[1])
axes[1].set_title('Imputed', weight='bold', y=1.05)

# Further customize plot
sns.despine(offset=10, trim=True)
plt.tight_layout(w_pad=4)

plt.show()

在插补之后,我们在右侧面板中看到更多的观测值现在位于分布的中心:

../../_images/meanmedianimputater_distributions.png

由于中心观测数量的增加,变量的方差减小,而峰度系数增加。

其他资源#

在下面的 Python Jupyter 笔记本中,您将找到关于 MeanMedianImputer() 功能的更多详细信息,包括如何自动选择数值变量。您还将看到如何导航转换器的不同属性以找到变量的均值或中位数值。

有关此方法和其他特征工程方法的更多详细信息,请查看以下资源:

../../_images/feml.png

机器学习的特征工程#











或者阅读我们的书:

../../_images/cookbook.png

Python 特征工程手册#














我们的书籍和课程都适合初学者和更高级的数据科学家。通过购买它们,您正在支持 Feature-engine 的主要开发者 Sole。