本文翻译自:6.4. Imputation of missing values — scikit-learn 1.0.2 documentation
因为各种原因,许多真实数据集包含缺失值,经常被编码成空格,NaN, 或者其他占位符。
然而,这样的数据集与scikit学习估计器不兼容,后者假设数组中的所有值都是数值,并且都有意义。使用不完整数据集的基本策略是丢弃包含缺失值的整行和/或整列。然而,这是以丢失可能有价值(即使不完整)的数据为代价的。更好的策略是插补缺失值,即从数据的已知部分推断缺失值。有关插补,请参见通用术语表和API元素条目。
6.4.1 单元 vs 多元插补
一种类型的插补算法是单变量算法,该算法仅使用第i个特征维度中的非缺失值(例如impute.SimpleImputer)来插补该特征维度中的值。相比之下,多元插补算法使用整个可用特征维度集来估计缺失值(例如 impute.IterativeImputer)。
6.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类还支持使用“最频繁”或“常量”策略时以字符串值或类别表示的类别数据:
>>> 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']]
6.4.3 多变量特征填补
一种更复杂的方法是使用IterativeImputer 类,该类将每个缺失值的特征建模为其他特征的函数,并使用该估计值进行插补。它以迭代循环的方式进行:在每一步,一个特征列被指定为输出y,其他特征列被视为输入X。一个回归器对已知y进行拟合(X,y)。然后,回归器被用来预测y的缺失值。这是以迭代的方式对每个特征进行的,然后重复进行max_iter插补轮。返回最后一轮插补的结果。
注意,这个估计器目前仍处于实验阶段:默认参数或行为细节可能会在没有任何弃用周期的情况下发生变化。解决以下问题将有助于稳定迭代插补器:收敛标准(#14338)、默认估计量(#13286)和随机状态的使用(#15611)。要使用它,您需要显式导入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和IterativeImputter都可以在管道中使用,作为构建支持插补的复合估计器的一种方法。请参见在构建估计器之前输入缺失值。
6.4.3.1 IterativeImputer的灵活性
R数据科学生态系统中有许多完善的插补软件包:Amelia、mi、mice、missForest等。missForest很受欢迎,结果证明是不同序列插补算法的一个特殊实例,这些算法都可以通过迭代插补器来实现,通过传递不同的回归函数来预测缺失的特征值。在missForest的情况下,此回归器是一个随机林。请参见使用IterativeImputer的变体插补缺失值。
6.4.3.2 多元 vs 单元填补
在统计界,通常的做法是执行多重插补,例如,为单个特征矩阵生成m个单独的插补。然后,这些m插补中的每一项都经过后续分析管道(例如特征工程、聚类、回归、分类)。m最终分析结果(例如,保留的验证错误)允许数据科学家了解由于缺失值导致的固有不确定性,分析结果可能会如何不同。上述做法称为多重插补。
我们的IterativeImputer 的实现受到R MICE软件包(链式方程多元插补)的启发,但与之不同的是,它返回一个插补而不是多个插补。但是,当sample_posterior=True时,IterativeImputer 也可用于多次插补,方法是将其重复应用于具有不同随机种子的同一数据集。有关多重插补与单一插补的更多讨论,请参见第4章第2节。
当用户因缺失值而对测量不确定度不感兴趣时,单一插补与多重插补在预测和分类中的作用如何,这仍然是一个悬而未决的问题。
请注意,不允许调用IterativeInputer的transform方法来更改样本数。因此,单次调用transform无法实现多重插补。