7.4. 插补缺失值#
由于各种原因,许多真实世界的数据集包含缺失值,通常编码为空白,NaN或其他占位符。然而,这样的数据集与scikit-learn估计器不兼容,scikit-learn估计器假设数组中的所有值都是数值,并且都有意义。使用不完整数据集的基本策略是丢弃包含缺失值的整个行和/或列。然而,这是以丢失可能有价值的数据(即使不完整)为代价的。更好的策略是估算缺失的值,即从数据的已知部分推断它们。请参阅术语表条目 imputation .
7.4.1. 单变量与多元插补#
一种类型的插补算法是单变量的,其仅使用第i个特征维度中的非缺失值来插补该特征维度中的值(例如 SimpleImputer
).相比之下,多变量插补算法使用整个可用特征维度集来估计缺失值(例如, IterativeImputer
).
7.4.2. 单变量特征插补#
的 SimpleImputer
类提供了估算缺失值的基本策略。可以使用提供的常数值来估算缺失值,或使用缺失值所在的每列的统计量(平均值、中位数或最频繁)。此类还允许不同的缺失值编码。
下面的代码片段演示了如何替换缺失的值,编码为 np.nan
,使用包含缺失值的列(轴0)的平均值::
>>> import numpy as np
>>> from sklearn.impute import SimpleImputer
>>> imp = SimpleImputer(missing_values=np.nan, strategy='mean')
>>> imp.fit([[1, 2], [np.nan, 3], [7, 6]])
SimpleImputer()
>>> X = [[np.nan, 2], [6, np.nan], [7, 6]]
>>> print(imp.transform(X))
[[4. 2. ]
[6. 3.666]
[7. 6. ]]
的 SimpleImputer
类还支持稀疏矩阵::
>>> import scipy.sparse as sp
>>> X = sp.csc_matrix([[1, 2], [0, -1], [8, 4]])
>>> imp = SimpleImputer(missing_values=-1, strategy='mean')
>>> imp.fit(X)
SimpleImputer(missing_values=-1)
>>> X_test = sp.csc_matrix([[-1, 2], [6, -1], [7, 6]])
>>> print(imp.transform(X_test).toarray())
[[3. 2.]
[6. 3.]
[7. 6.]]
请注意,这种格式并不用于隐式地存储矩阵中缺失的值,因为它会在变换时致密化它。由0编码的缺失值必须与密集输入一起使用。
的 SimpleImputer
当使用 'most_frequent'
或 'constant'
策略::
>>> import pandas as pd
>>> df = pd.DataFrame([["a", "x"],
... [np.nan, "y"],
... ["a", np.nan],
... ["b", "y"]], dtype="category")
...
>>> imp = SimpleImputer(strategy="most_frequent")
>>> print(imp.fit_transform(df))
[['a' 'x']
['a' 'y']
['a' 'y']
['b' 'y']]
有关使用的另一个示例,请参阅 在构建估计器之前输入缺失值 .
7.4.3. 多元特征插补#
A more sophisticated approach is to use the IterativeImputer
class,
which models each feature with missing values as a function of other features,
and uses that estimate for imputation. It does so in an iterated round-robin
fashion: at each step, a feature column is designated as output y
and the
other feature columns are treated as inputs X
. A regressor is fit on (X,
y)
for known y
. Then, the regressor is used to predict the missing values
of y
. This is done for each feature in an iterative fashion, and then is
repeated for max_iter
imputation rounds. The results of the final
imputation round are returned.
备注
这个估计器仍然是 experimental 目前:默认参数或行为细节可能会更改,而无需任何弃用周期。解决以下问题将有助于稳定 IterativeImputer
:收敛标准 (#14338 )和默认估计器 (#13286 ).要使用它,您需要显式导入 enable_iterative_imputer
.
>>> import numpy as np
>>> from sklearn.experimental import enable_iterative_imputer
>>> from sklearn.impute import IterativeImputer
>>> imp = IterativeImputer(max_iter=10, random_state=0)
>>> imp.fit([[1, 2], [3, 6], [4, 8], [np.nan, 3], [7, np.nan]])
IterativeImputer(random_state=0)
>>> X_test = [[np.nan, 2], [6, np.nan], [np.nan, 6]]
>>> # the model learns that the second feature is double the first
>>> print(np.round(imp.transform(X_test)))
[[ 1. 2.]
[ 6. 12.]
[ 3. 6.]]
两 SimpleImputer
和 IterativeImputer
可以在Pipeline中使用,作为构建支持插补的复合估计器的一种方式。看到 在构建估计器之前输入缺失值 .
7.4.3.1. IterativeImputer的灵活性#
R数据科学生态系统中有许多成熟的插补包:Amelia、mi、mice、missForest等。missForest很受欢迎,事实证明是不同顺序插补算法的一个特定实例,这些算法都可以用 IterativeImputer
通过传递不同的回归量以用于预测缺失的特征值。对于missForest,此回归变量是随机森林。看到 使用IterativeImputer的变体输入缺失值 .
7.4.3.2. 多重归因与单一归因#
在统计界,执行多次估算是常见的做法,例如, m
对单个特征矩阵进行单独的估算。这一切成功都 m
然后通过后续分析管道(例如,特征工程、聚类、回归、分类)进行估算。的 m
最终分析结果(例如,保留的验证错误)使数据科学家能够了解由于缺失值引起的固有不确定性而导致的分析结果可能如何不同。上述做法称为多重归责。
贯彻落实 IterativeImputer
灵感来自R MICE包(通过连锁方程进行多元插补) [1], 但与它的不同之处在于返回单个估算而不是多个估算。 然而, IterativeImputer
还可以通过重复将其应用于具有不同随机种子的同一数据集来用于多次插补,当 sample_posterior=True
.看到 [2], 第4章更多地讨论多重估算与单一估算。
当用户对测量缺失值引起的不确定性不感兴趣时,单重插补与多重插补在预测和分类方面的作用如何,这仍然是一个悬而未决的问题。
请注意,调用 transform
方法 IterativeImputer
不允许更改样本数量。因此,无法通过一次调用来实现多重估算 transform
.
引用
7.4.4. 最近邻居的归属#
的 KNNImputer
类提供使用k近邻方法填充缺失值的插补。默认情况下,支持缺失值的欧几里得距离度量, nan_euclidean_distances
,用于寻找最近的邻居。每个缺失的特征都使用以下值进行插补 n_neighbors
具有该特征值的最近邻居。邻居的特征通过到每个邻居的距离均匀平均或加权。如果样本缺少多个特征,则该样本的邻居可能会根据所估算的特定特征而有所不同。当可用邻居的数量少于 n_neighbors
并且到训练集没有定义的距离,则在插补期间使用该特征的训练集平均值。如果至少有一个具有定义距离的邻居,则在插补期间将使用剩余邻居的加权或未加权平均值。如果某个功能在训练中总是缺失,则会在训练期间删除该功能 transform
.有关该方法的更多信息,请参阅参考文献。 [OL2001].
下面的代码片段演示了如何替换缺失的值,编码为 np.nan
,使用具有缺失值的样本的两个最近邻居的平均特征值:
>>> import numpy as np
>>> from sklearn.impute import KNNImputer
>>> nan = np.nan
>>> X = [[1, 2, nan], [3, 4, 3], [nan, 6, 5], [8, 8, 7]]
>>> imputer = KNNImputer(n_neighbors=2, weights="uniform")
>>> imputer.fit_transform(X)
array([[1. , 2. , 4. ],
[3. , 4. , 3. ],
[5.5, 6. , 5. ],
[8. , 8. , 7. ]])
有关使用的另一个示例,请参阅 在构建估计器之前输入缺失值 .
引用
Olga Troyanskaya, Michael Cantor, Gavin Sherlock, Pat Brown, Trevor Hastie, Robert Tibshirani, David Botstein and Russ B. Altman, Missing value estimation methods for DNA microarrays, BIOINFORMATICS Vol. 17 no. 6, 2001 Pages 520-525. <https://academic.oup.com/bioinformatics/article/17/6/520/272365>
_
7.4.5. 保持特征数量不变#
默认情况下,scikit-learn输入器将删除完全空的特征,即只包含缺失值的列。例如::
>>> imputer = SimpleImputer()
>>> X = np.array([[np.nan, 1], [np.nan, 2], [np.nan, 3]])
>>> imputer.fit_transform(X)
array([[1.],
[2.],
[3.]])
中的所述第一特征 X
仅含有 np.nan
在插补后被删除。虽然此功能在预测设置中没有帮助,但删除列将改变 X
当在更复杂的机器学习管道中使用估算器时,这可能会出现问题。参数 keep_empty_features
提供了通过输入恒定值来保留空功能的选项。在大多数情况下,该常数值为零::
>>> imputer.set_params(keep_empty_features=True)
SimpleImputer(keep_empty_features=True)
>>> imputer.fit_transform(X)
array([[0., 1.],
[0., 2.],
[0., 3.]])
7.4.6. 标记估算值#
The MissingIndicator
transformer is useful to transform a dataset into
corresponding binary matrix indicating the presence of missing values in the
dataset. This transformation is useful in conjunction with imputation. When
using imputation, preserving the information about which values had been
missing can be informative. Note that both the SimpleImputer
and
IterativeImputer
have the boolean parameter add_indicator
(False
by default) which when set to True
provides a convenient way of
stacking the output of the MissingIndicator
transformer with the
output of the imputer.
NaN
通常用作缺失值的占位符。但是,它强制数据类型为浮动。参数 missing_values
允许指定其他占位符,例如integer。在下面的例子中,我们将使用 -1
作为缺失值::
>>> from sklearn.impute import MissingIndicator
>>> X = np.array([[-1, -1, 1, 3],
... [4, -1, 0, -1],
... [8, -1, 1, 0]])
>>> indicator = MissingIndicator(missing_values=-1)
>>> mask_missing_values_only = indicator.fit_transform(X)
>>> mask_missing_values_only
array([[ True, True, False],
[False, True, True],
[False, True, False]])
The features
parameter is used to choose the features for which the mask is
constructed. By default, it is 'missing-only'
which returns the imputer
mask of the features containing missing values at fit
time:
>>> indicator.features_
array([0, 1, 3])
的 features
参数可以被设置为 'all'
返回所有要素,无论它们是否包含缺失值::
>>> indicator = MissingIndicator(missing_values=-1, features="all")
>>> mask_all = indicator.fit_transform(X)
>>> mask_all
array([[ True, True, False, False],
[False, True, False, True],
[False, True, False, False]])
>>> indicator.features_
array([0, 1, 2, 3])
当使用 MissingIndicator
中 Pipeline
,请务必使用 FeatureUnion
或 ColumnTransformer
将指示器功能添加到常规功能中。首先我们获得 iris
数据集,并向其中添加一些缺失的值。
>>> from sklearn.datasets import load_iris
>>> from sklearn.impute import SimpleImputer, MissingIndicator
>>> from sklearn.model_selection import train_test_split
>>> from sklearn.pipeline import FeatureUnion, make_pipeline
>>> from sklearn.tree import DecisionTreeClassifier
>>> X, y = load_iris(return_X_y=True)
>>> mask = np.random.randint(0, 2, size=X.shape).astype(bool)
>>> X[mask] = np.nan
>>> X_train, X_test, y_train, _ = train_test_split(X, y, test_size=100,
... random_state=0)
现在我们创建一个 FeatureUnion
.所有功能都将使用 SimpleImputer
,以便使分类器能够处理此数据。此外,它还添加了来自 MissingIndicator
.
>>> transformer = FeatureUnion(
... transformer_list=[
... ('features', SimpleImputer(strategy='mean')),
... ('indicators', MissingIndicator())])
>>> transformer = transformer.fit(X_train, y_train)
>>> results = transformer.transform(X_test)
>>> results.shape
(100, 8)
Of course, we cannot use the transformer to make any predictions. We should
wrap this in a Pipeline
with a classifier (e.g., a
DecisionTreeClassifier
) to be able to make predictions.
>>> clf = make_pipeline(transformer, DecisionTreeClassifier())
>>> clf = clf.fit(X_train, y_train)
>>> results = clf.predict(X_test)
>>> results.shape
(100,)
7.4.7. 处理NaN值的估计器#
一些估计器旨在无需预处理即可处理NaN值。以下是这些估计量的列表,按类型分类(集群、回归量、分类器、变换):
- Estimators that allow NaN values for type
cluster
: - Estimators that allow NaN values for type
regressor
: - Estimators that allow NaN values for type
classifier
: - Estimators that allow NaN values for type
transformer
: