在机器学习中,一旦我们的数据集缺少了值,这就可能直接导致我们的算法出现问题,甚至会影响我们的模型准确率。
因此,在对预测任务建模之前,最好识别并替换输入数据中每个列的缺失值。这称为缺失数据插补,简称插补。
一种复杂的方法包括定义一个模型,将每个缺失的特征作为所有其他特征的函数进行预测,并多次重复这一估计特征值的过程。重复允许在预测缺失值的后续迭代中使用其他特征的优化估计值作为输入。这通常被称为迭代插补。
在本文中,你将学会如何在机器学习中使用迭代插补策略来处理缺失的数据。
看完本文后,你将知道:
- 缺少的值必须用NaN值标记,并且可以用迭代估计值替换。
- 如何加载缺少值的CSV值,并用NaN值标记缺少的值,并报告每列缺少值的数量和百分比。
- 在评估模型和拟合最终模型对新数据进行预测时,如何用迭代模型估算缺失值作为数据准备方法。
概述
本文分为三部分:
- 迭代插补
- Horse Colic 数据集
- IterativeImputer类的迭代插补
IterativeImputer 数据转换
IterativeImputer与模型评估
IterativeImputer与不同的进位顺序
IterativeImputer与不同的迭代次数
预测时的IterativeImputer变换
迭代插补
数据集可能缺少值。
这些数据行中不存在该行中的一个或多个值或列。也有可能这些值完全丢失了,或者可能标记有特殊字符或值,例如问号“?”.
值可能由于许多原因丢失,但是,通常都是特定于问题域的,并且可能包括诸如损坏的度量或不可用的原因。
大多数机器学习算法都需要数字输入值,并且数据集中的每一行和每一列都有一个值。因此,缺少值可能会导致机器学习算法出现很多问题。
因此,识别数据集中缺少的值并用数值替换它们,这是很常见的方法。这称为数据插补或缺失数据插补。
一种估算缺失值的方法是使用迭代估算模型。
迭代插补是指将每个特征建模为其他特征函数的过程,例如预测缺失值的回归问题。每个特征都是依次输入的,允许在预测后续特征时将先前的输入值用作模型的一部分。
这就是迭代的过程,因为这个过程需要重复多次,允许在估计所有特征的丢失值时计算丢失值的不断改进的估计值。
这种方法通常被称为完全条件规范(FCS)或链式方程(MICE)的多元插补。
如果多元分布是数据的合理描述,这种方法是有吸引力的。FCS通过一组条件密度逐变量指定多变量插补模型,每个条件密度对应一个不完全变量。从初始插补开始,FCS通过迭代条件密度得出插补。只需要很少的迭代次数(比如10-20次)就足够了。
可以使用不同的回归算法来估计每个特征的缺失值,尽管使用线性方法是为了简单起见。过程的迭代通常要保持较小的次数,例如10次。最后,可以考虑按顺序处理特征的顺序,例如从缺失值最少的特征到缺失值最多的特征。
现在我们已经熟悉了缺少值插补的迭代方法,接下来让我们看看缺少值的数据集。
Horse Colic 数据集
Horse Colic数据集描述了患有疝气的马的医学特征以及它们是生是死。
有300行,26个输入变量和一个输出变量。这是一个二元分类预测任务,包括预测1如果马活着,2如果马死了。
一个简单的模型可以达到67%的分类准确率,一个性能最好的模型可以通过三次重复10倍的交叉验证达到85.2%的准确率。这定义了数据集上的预期建模性能范围。
对于许多列,数据集都有许多缺少的值,其中每个缺少的值都用问号字符(“?”).
下面提供了数据集中带有标记的缺失值的行的示例。
2,1,530101,38.50,66,28,3,3,?,2,5,4,4,?,?,?,3,5,45.00,8.40,?,?,2,2,11300,00000,00000,2
1,1,534817,39.2,88,20,?,?,4,1,3,4,2,?,?,?,4,2,50,85,2,2,3,2,02208,00000,00000,2
2,1,530334,38.30,40,24,1,1,3,1,3,3,1,?,?,?,1,1,33.00,6.70,?,?,1,2,00000,00000,00000,1
1,9,5290409,39.10,164,84,4,1,6,2,2,4,4,1,2,5.00,3,?,48.00,7.20,3,5.30,2,1,02208,00000,00000,1
...
有关数据集的更多信息可以通过下方链接了解:
Horse Colic 数据集:https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-
colic.csvHorse Colic 数据集描述:https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.names
不需要下载数据集,因为我们可以在代码中自动下载。
使用Python在加载的数据集中使用NaN(不是数字)值标记丢失的值是一种最佳实践。
我们可以使用read_csv()Pandas函数加载数据集,并指定“na_values”来加载'?'丢失,用NaN值标记。
...
# 加载数据集
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
加载后,我们可以查看加载的数据以确认“?“值标记为NaN。
...
# 总结前几行
print(dataframe.head())
然后,我们可以枚举每一列并报告该列缺少值的行数。
...
# 总结每列缺少值的行数
for i in range(dataframe.shape[1]):
# 计算缺少值的行数
n_miss = dataframe[[i]].isnull().sum()
perc = n_miss / dataframe.shape[0] * 100
print('> %d, Missing: %d (%.1f%%)' % (i, n_miss, perc))
下面是加载和汇总数据集的完整代码示例。
# 总结horse colic数据集
from pandas import read_csv
# 加载数据集
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# 总结前几行
print(dataframe.head())
# 汇总每列缺少值的行数
for i in range(dataframe.shape[1]):
# 计算缺少值的行数
n_miss = dataframe[[i]].isnull().sum()
perc = n_miss / dataframe.shape[0] * 100
print('> %d, Missing: %d (%.1f%%)' % (i, n_miss, perc))
运行示例首先加载数据集并汇总前五行。
我们可以看到用“?“字符已替换为NaN值。
0 1 2 3 4 5 6 ... 21 22 23 24 25 26 27
0 2.0 1 530101 38.5 66.0 28.0 3.0 ... NaN 2.0 2 11300 0 0 2
1 1.0 1 534817 39.2 88.0 20.0 NaN ... 2.0 3.0 2 2208 0 0 2
2 2.0 1 530334 38.3 40.0 24.0 1.0 ... NaN 1.0 2 0 0 0 1
3 1.0 9 5290409 39.1 164.0 84.0 4.0 ... 5.3 2.0 1 2208 0 0 1
4 2.0 1 530255 37.3 104.0 35.0 NaN ... NaN 2.0 2 4300 0 0 2
[5 rows x 28 columns]
接下来,我们可以看到数据集中所有列的列表以及丢失值的数量和百分比。
我们可以看到一些列(例如列索引1和2)没有缺失的值,而其他列(例如列索引15和21)有许多甚至大部分缺失的值。
> 0, Missing: 1 (0.3%)
> 1, Missing: 0 (0.0%)
> 2, Missing: 0 (0.0%)
> 3, Missing: 60 (20.0%)
> 4, Missing: 24 (8.0%)
> 5, Missing: 58 (19.3%)
> 6, Missing: 56 (18.7%)
> 7, Missing: 69 (23.0%)
> 8, Missing: 47 (15.7%)
> 9, Missing: 32 (10.7%)
> 10, Missing: 55 (18.3%)
> 11, Missing: 44 (14.7%)
> 12, Missing: 56 (18.7%)
> 13, Missing: 104 (34.7%)
> 14, Missing: 106 (35.3%)
> 15, Missing: 247 (82.3%)
> 16, Missing: 102 (34.0%)
> 17, Missing: 118 (39.3%)
> 18, Missing: 29 (9.7%)
> 19, Missing: 33 (11.0%)
> 20, Missing: 165 (55.0%)
> 21, Missing: 198 (66.0%)
> 22, Missing: 1 (0.3%)
> 23, Missing: 0 (0.0%)
> 24, Missing: 0 (0.0%)
> 25, Missing: 0 (0.0%)
> 26, Missing: 0 (0.0%)
> 27, Missing: 0 (0.0%)
现在我们已经熟悉了缺少值的horse colic数据集,让我们看看如何进行迭代插补。
IterativeImputer类的迭代插补
scikit-learn 机器学习库提供了支持迭代插补的 IterativeImputer 类。
在本节中,我们将探讨如何有效地使用 IterativeImputer 类。
1、IterativeImputer类数据转换
它是一个数据转换,首先根据用于估计缺失值的方法进行配置。默认情况下,使用BayesianRidge模型,该模型使用所有其他输入特征的函数。特征按升序填充,从缺失值最少的特征到缺失值最多的特征。
...
# 定义imputer
imputer = IterativeImputer(estimator=BayesianRidge(), n_nearest_features=None, imputation_order='ascending')
然后,将imputer拟合到数据集。
...
# 适配数据集
imputer.fit(X)
然后,将imputer应用于数据集中,用于创建数据集的副本,用估计值替换每个列的所有缺失值。
...
# 转换数据集
Xtrans = imputer.transform(X)
IterativeImputer 类不能直接使用,因为它是实验性的。
如果你直接进行使用,会得到如下错误:
ImportError: cannot import name 'IterativeImputer'
相反,您必须添加一个额外的import语句,来添加对IterativeImputer类的支持,如下所示:
...
from sklearn.experimental import enable_iterative_imputer
我们可以在horse colic数据集上演示它的用法,并通过汇总转换前后数据集中丢失的值的总数来确认它的作用。
以下为完整的代码示例:
# horse colic数据集的迭代插补变换
from numpy import isnan
from pandas import read_csv
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
# 加载数据集
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# 分成输入和输出元素
data = dataframe.values
X, y = data[:, :-1], data[:, -1]
# 输出缺失值
print('Missing: %d' % sum(isnan(X).flatten()))
# 定义imputer
imputer = IterativeImputer()
# 适配数据集
imputer.fit(X)
# 转换数据集
Xtrans = imputer.transform(X)
# 输出全部缺失值
print('Missing: %d' % sum(isnan(Xtrans).flatten()))
运行该示例,在加载数据集后,我们发现数据集中丢失的值的总数报告为1,605。
通过配置、调整并执行转换,生成新的数据集没有缺少的值。
把每个缺失的值都替换成模型预估的值。
Missing: 1605
Missing: 0
2、IterativeImputer类与模型评估
使用k-fold交叉验证在数据集上评估机器学习模型是一个很好的办法。
为了正确地应用迭代缺失数据插补,避免数据泄漏,要求每一列的模型仅在训练数据集上计算,然后应用到数据集中每一个折叠的训练和测试集上。
这可以通过创建一个建模通道来实现,第一步是迭代插补,第二步是模型。这可以通过使用Pipeline类来实现。
例如,下面的通道使用具有默认策略的迭代输入,然后是随机林模型。
...
# 定义建模通道
model = RandomForestClassifier()
imputer = IterativeImputer()
pipeline = Pipeline(steps=[('i', imputer), ('m', model)])
通过重复10次交叉验证,我们可以对horse colic数据集的输入数据集和随机森林建模通道进行评估。
以下为完整的代码示例:
# horse colic数据集的迭代插补和随机森林评估
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import Pipeline
# 加载数据集
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# 分成输入和输出元素
data = dataframe.values
X, y = data[:, :-1], data[:, -1]
# 定义建模通道
model = RandomForestClassifier()
imputer = IterativeImputer()
pipeline = Pipeline(steps=[('i', imputer), ('m', model)])
# 定义模型评估
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# 评估模型
scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))
正确运行该示例,将数据插补应用于交叉验证过程的各个方面。
使用三次重复的10倍交叉验证对通道进行评估,并得出数据集上的平均分类精度约为81.4%,这是一个不错的分数。
Mean Accuracy: 0.814 (0.063)
我们如何知道使用默认的迭代策略对这个数据集是好还是差?
答案是我们没有。
3、IterativeImputer类与不同的插补顺序
默认情况下,插补按从缺失值最少的特征到缺失值最多的特征的升序进行。
这是有意义的,因为我们希望在估计大多数值丢失的列的丢失值时有更完整的数据。
然而,我们可以尝试不同的归责顺序策略,如降序、从右向左(阿拉伯语)、从左向右(罗马语)和随机。
下面的示例评估并比较每个可用的估算顺序配置。
# horse colic数据集迭代插补策略的比较
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# 加载数据集
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# 分成输入和输出元素
data = dataframe.values
X, y = data[:, :-1], data[:, -1]
# 在数据集上评估每个策略
results = list()
strategies = ['ascending', 'descending', 'roman', 'arabic', 'random']
for s in strategies:
# 创建建模通道
pipeline = Pipeline(steps=[('i', IterativeImputer(imputation_order=s)), ('m', RandomForestClassifier())])
# 评估模型
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# 存储结果
results.append(scores)
print('>%s %.3f (%.3f)' % (s, mean(scores), std(scores)))
# 用于比较的绘图模型性能
pyplot.boxplot(results, labels=strategies, showmeans=True)
pyplot.xticks(rotation=45)
pyplot.show()
通过运行该示例,我们用重复的交叉验证来评估horse colic数据集上的估算顺序。
考虑到学习算法的随机性,你得到的具体结果可能会有所不同,记得多运行几次。
每种策略得到的平均精度相差不大。结果表明,大多数方法之间的差别不大,降序(与默认相反)效果最好。从右到左(阿拉伯语)顺序对该数据集可能更好,准确率约为80.4%。
>ascending 0.801 (0.071)
>descending 0.797 (0.059)
>roman 0.802 (0.060)
>arabic 0.804 (0.068)
>random 0.802 (0.061)
在运行结束后,将为每个结果集创建一个框线图,比较结果如下图所示。
4、IterativeImputer类与不同的迭代次数
默认情况下, IterativeImputer类需要重复迭代10次。
有可能大量的迭代可能开始偏向或倾斜估计,并且可能优选很少的迭代。过程的迭代次数可以通过“max_iter”参数指定。
评估不同数量的迭代可能很有趣。下面的示例比较“max_iter”从1到20的不同值。
# 比较horse colic数据集的迭代插补次数
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# 加载数据集
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# 分成输入和输出元素
data = dataframe.values
X, y = data[:, :-1], data[:, -1]
# 在数据集上评估每个策略
results = list()
strategies = [str(i) for i in range(1, 21)]
for s in strategies:
# 创建建模通道
pipeline = Pipeline(steps=[('i', IterativeImputer(max_iter=int(s))), ('m', RandomForestClassifier())])
# 评估模型
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
# 储存结果
results.append(scores)
print('>%s %.3f (%.3f)' % (s, mean(scores), std(scores)))
# 用于比较的绘图模型性能
pyplot.boxplot(results, labels=strategies, showmeans=True)
pyplot.xticks(rotation=45)
pyplot.show()
通过运行该示例,使用重复的交叉验证来评估 horse colic数据集上的每个迭代次数。
考虑到学习算法的随机性,得出的具体结果可能会有所不同,记得多运行几次。
结果表明,在这个数据集上,9-12次迭代更有效。
>1 0.820 (0.072)
>2 0.813 (0.078)
>3 0.801 (0.066)
>4 0.817 (0.067)
>5 0.808 (0.071)
>6 0.799 (0.059)
>7 0.804 (0.058)
>8 0.809 (0.070)
>9 0.812 (0.068)
>10 0.800 (0.058)
>11 0.818 (0.064)
>12 0.810 (0.073)
>13 0.808 (0.073)
>14 0.799 (0.067)
>15 0.812 (0.075)
>16 0.814 (0.057)
>17 0.812 (0.060)
>18 0.810 (0.069)
>19 0.810 (0.057)
>20 0.802 (0.067)
在运行结束时,将为每个结果集创建一个框线图,查看比较的结果。
5、预测时的IterativeImputer变换
我们希望使用迭代插补和随机森林算法创建最终的建模通道,然后对新数据进行预测。
这可以通过定义通道并在所有可用数据上进行拟合,然后调用predict()函数,将新数据作为参数传入来实现。
新数据行必须使用NaN值标记任何缺少的值。
...
# 定义新数据
row = [2,1,530101,38.50,66,28,3,3,nan,2,5,4,4,nan,nan,nan,3,5,45.00,8.40,nan,nan,2,2,11300,00000,00000]
以下为完整的代码示例:
# hose-colic数据集的迭代插补策略与预测
from numpy import nan
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
from sklearn.pipeline import Pipeline
# 加载数据集
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# 分成输入和输出元素
data = dataframe.values
X, y = data[:, :-1], data[:, -1]
# create the modeling pipeline
pipeline = Pipeline(steps=[('i', IterativeImputer()), ('m', RandomForestClassifier())])
# 适配模型
pipeline.fit(X, y)
# 定义新数据
row = [2,1,530101,38.50,66,28,3,3,nan,2,5,4,4,nan,nan,nan,3,5,45.00,8.40,nan,nan,2,2,11300,00000,00000]
# 作出预测
yhat = pipeline.predict([row])
# 总结预测
print('Predicted Class: %d' % yhat[0])
运行所示代码,可以让建模通道适配所有可用数据。
定义了一个新的数据行,该行的缺失值用NaNs标记,并进行了分类预测。
Predicted Class: 2
总结
通过学习本文,你将学会如何在机器学习中对丢失的数据使用迭代插补策略。
具体来说,你学到了:
- 缺少的值必须用NaN值标记,并且可以用迭代估计值替换。
- 如何加载缺少值的CSV值,并用NaN值标记缺少的值,并报告每列缺少值的数量和百分比。
- 在评估模型和拟合最终模型对新数据进行预测时,如何用迭代模型估算缺失值作为数据准备方法。
在机器学习的模型中,数据是最关键的一环,任何一个数据缺失,最终我们辛辛苦苦做出来的模型,可能得到的结论也会发生天翻地覆的变化,希望以上内容能帮助因为数据问题而烦恼脱发的你!
参考链接:https://machinelearningmastery.com/iterative-imputation-for-missing-values-in-machine-learning/
--END--
喜欢本文的同学,记得转发+收藏哦~
也欢迎大家关注我们的公众号:为AI呐喊(weainahan),学习更多AI知识!