Machine Learning Mastery 数据准备教程(八)
机器学习中缺失值的统计插补
最后更新于 2020 年 8 月 18 日
数据集可能会有缺失值,这可能会给许多机器学习算法带来问题。
因此,在对预测任务建模之前,识别并替换输入数据中每一列的缺失值是一种很好的做法。这被称为缺失数据插补,简称为插补。
数据插补的一种流行方法是计算每一列的统计值(如平均值),并用统计值替换该列的所有缺失值。这是一种流行的方法,因为使用训练数据集很容易计算统计数据,并且通常会产生良好的表现。
在本教程中,您将发现如何在机器学习中对缺失数据使用统计插补策略。
完成本教程后,您将知道:
- 缺少的值必须用 NaN 值标记,并且可以用统计度量值替换以计算值列。
- 如何加载缺失值的 CSV 值并用 NaN 值标记缺失值,并报告每列缺失值的数量和百分比。
- 在评估模型和拟合最终模型以对新数据进行预测时,如何用统计学作为数据准备方法来估计缺失值。
用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
- 更新 6 月/2020 :更改了示例中用于预测的列。
机器学习中缺失值的统计插补 图片由伯纳·萨沃里奥提供,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 统计插补
- 马结肠数据集
- 用简单估计器进行统计估计
- simpleinputer 数据转换
- 简单输入器和模型评估
- 比较不同的估计统计
- 进行预测时的 simpleinputer 转换
统计插补
数据集可能缺少值。
这些数据行中的一个或多个值或列不存在。这些值可能完全丢失,或者用特殊字符或值标记,如问号“?”。
这些价值可以用许多方式来表达。我看到它们显示为完全没有[…],一个空字符串[…],显式字符串 NULL 或 undefined 或 N/A 或 NaN,以及数字 0 等等。无论它们如何出现在您的数据集中,当您开始使用这些数据时,知道期望什么并检查以确保数据与期望相匹配将会减少问题。
—第 10 页,不良数据手册,2012 年。
值可能由于许多原因而丢失,通常是特定于问题域的,并且可能包括损坏的测量或数据不可用等原因。
它们的出现可能有多种原因,例如测量设备故障、数据收集过程中实验设计的变化以及几个相似但不完全相同的数据集的整理。
—第 63 页,数据挖掘:实用机器学习工具与技术,2016。
大多数机器学习算法需要数字输入值,并且数据集中的每一行和每一列都需要一个值。因此,缺失值会给机器学习算法带来问题。
因此,识别数据集中缺失的值并用数值替换它们是很常见的。这被称为数据插补,或缺失数据插补。
数据插补的一种简单而流行的方法是使用统计方法从现有的值中估计一个列的值,然后用计算出的统计值替换该列中所有缺失的值。
这很简单,因为统计数据计算速度快,而且它很受欢迎,因为它经常被证明非常有效。
计算出的常见统计数据包括:
- 列平均值。
- 列中值。
- 列模式值。
- 常数值。
现在我们已经熟悉了缺失值插补的统计方法,让我们来看看一个缺失值的数据集。
马结肠数据集
马绞痛数据集描述了患有绞痛的马的医学特征以及它们是活的还是死的。
有 300 行 26 个输入变量和一个输出变量。这是一个二分类预测任务,包括预测 1 如果马活了,2 如果马死了。
在这个数据集中,我们可以选择许多字段进行预测。在这种情况下,我们将预测问题是否是外科手术(列索引 23),使其成为二分类问题。
数据集的许多列都有许多缺失值,每个缺失值都用问号字符(“?”).
下面提供了数据集中带有标记缺失值的行的示例。
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
...
您可以在此了解有关数据集的更多信息:
不需要下载数据集,因为我们将在工作示例中自动下载它。
使用 Python 在加载的数据集中用 NaN(而不是数字)值标记缺失值是最佳实践。
我们可以使用 read_csv() Pandas 函数加载数据集,并指定“ na_values 来加载“的值?'为缺失,标有 NaN 值。
...
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
加载后,我们可以查看加载的数据以确认“?”值被标记为 NaN。
...
# summarize the first few rows
print(dataframe.head())
然后,我们可以枚举每一列,并报告该列缺少值的行数。
...
# summarize the number of rows with missing values for each column
for i in range(dataframe.shape[1]):
# count number of rows with missing values
n_miss = dataframe[[i]].isnull().sum()
perc = n_miss / dataframe.shape[0] * 100
print('> %d, Missing: %d (%.1f%%)' % (i, n_miss, perc))
将这些联系在一起,下面列出了加载和汇总数据集的完整示例。
# summarize the horse colic dataset
from pandas import read_csv
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# summarize the first few rows
print(dataframe.head())
# summarize the number of rows with missing values for each column
for i in range(dataframe.shape[1]):
# count number of rows with missing values
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%)
现在我们已经熟悉了丢失值的马绞痛数据集,让我们看看如何使用统计插补。
用简单估计器进行统计估计
Sklearn 机器学习库提供了支持统计插补的simple 插补器类。
在本节中,我们将探索如何有效地使用 simple Current 类。
simpleinputer 数据转换
简单估计器是一种数据转换,首先根据要为每列计算的统计类型进行配置,例如平均值。
...
# define imputer
imputer = SimpleImputer(strategy='mean')
然后将估计值拟合到数据集上,以计算每一列的统计数据。
...
# fit on the dataset
imputer.fit(X)
然后将拟合估计应用于数据集,以创建数据集的副本,用统计值替换每列的所有缺失值。
...
# transform the dataset
Xtrans = imputer.transform(X)
我们可以在 horse colic 数据集上演示它的用法,并通过总结转换前后数据集中缺失值的总数来确认它的工作。
下面列出了完整的示例。
# statistical imputation transform for the horse colic dataset
from numpy import isnan
from pandas import read_csv
from sklearn.impute import SimpleImputer
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# split into input and output elements
data = dataframe.values
ix = [i for i in range(data.shape[1]) if i != 23]
X, y = data[:, ix], data[:, 23]
# print total missing
print('Missing: %d' % sum(isnan(X).flatten()))
# define imputer
imputer = SimpleImputer(strategy='mean')
# fit on the dataset
imputer.fit(X)
# transform the dataset
Xtrans = imputer.transform(X)
# print total missing
print('Missing: %d' % sum(isnan(Xtrans).flatten()))
运行该示例首先加载数据集,并报告数据集中缺失值的总数为 1,605。
转换被配置、调整和执行,生成的新数据集没有缺失值,这证实了它是按照我们的预期执行的。
每个缺失的值都被替换为其列的平均值。
Missing: 1605
Missing: 0
简单输入器和模型评估
使用 k 倍交叉验证在数据集上评估机器学习模型是一个很好的实践。
为了正确应用统计缺失数据插补,避免数据泄露,要求只在训练数据集中计算每一列的统计量,然后应用于数据集中每个折叠的训练集和测试集。
如果我们使用重采样来选择调谐参数值或估计表现,插补应该包含在重采样中。
—第 42 页,应用预测建模,2013 年。
这可以通过创建建模管道来实现,其中第一步是统计插补,然后第二步是模型。这可以使用管道类来实现。
例如,下面的管道使用了一个简单估计器,带有一个“的意思是策略,后面是一个随机森林模型。
...
# define modeling pipeline
model = RandomForestClassifier()
imputer = SimpleImputer(strategy='mean')
pipeline = Pipeline(steps=[('i', imputer), ('m', model)])
我们可以使用重复的 10 倍交叉验证来评估马结肠数据集的平均估计数据集和随机森林建模管道。
下面列出了完整的示例。
# evaluate mean imputation and random forest for the horse colic dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import SimpleImputer
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import Pipeline
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# split into input and output elements
data = dataframe.values
ix = [i for i in range(data.shape[1]) if i != 23]
X, y = data[:, ix], data[:, 23]
# define modeling pipeline
model = RandomForestClassifier()
imputer = SimpleImputer(strategy='mean')
pipeline = Pipeline(steps=[('i', imputer), ('m', model)])
# define model evaluation
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
print('Mean Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))
正确运行该示例将数据插补应用于交叉验证程序的每个折叠。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
使用 10 倍交叉验证的三次重复对管道进行评估,并报告数据集上的平均分类准确率约为 86.3%,这是一个不错的分数。
Mean Accuracy: 0.863 (0.054)
比较不同的估计统计
我们如何知道使用“表示”统计策略对这个数据集是好的还是最好的?
答案是我们没有,它是被任意选择的。
我们可以设计一个实验来测试每个统计策略,并通过比较均值、中位数、模式(最频繁)和常数(0)策略来发现什么最适合这个数据集。然后可以比较每种方法的平均准确率。
下面列出了完整的示例。
# compare statistical imputation strategies for the horse colic dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import SimpleImputer
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# split into input and output elements
data = dataframe.values
ix = [i for i in range(data.shape[1]) if i != 23]
X, y = data[:, ix], data[:, 23]
# evaluate each strategy on the dataset
results = list()
strategies = ['mean', 'median', 'most_frequent', 'constant']
for s in strategies:
# create the modeling pipeline
pipeline = Pipeline(steps=[('i', SimpleImputer(strategy=s)), ('m', RandomForestClassifier())])
# evaluate the 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)
# store results
results.append(scores)
print('>%s %.3f (%.3f)' % (s, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=strategies, showmeans=True)
pyplot.show()
运行该示例使用重复交叉验证来评估马结肠数据集上的每个统计插补策略。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
每种策略的平均精确度都是一路上报告的。结果表明,使用一个恒定值,例如 0,会产生大约 88.1%的最佳表现,这是一个出色的结果。
>mean 0.860 (0.054)
>median 0.862 (0.065)
>most_frequent 0.872 (0.052)
>constant 0.881 (0.047)
在运行结束时,为每组结果创建一个方框图和须图,以便比较结果的分布。
我们可以清楚地看到,恒定策略的准确性分数分布优于其他策略。
应用于马结肠数据集的统计插补策略的盒须图
进行预测时的 simpleinputer 转换
我们可能希望使用恒定插补策略和随机森林算法创建最终建模管道,然后对新数据进行预测。
这可以通过定义管道并将其拟合到所有可用数据上来实现,然后调用 predict() 函数,将新数据作为参数传入。
重要的是,新数据行必须使用 NaN 值标记任何缺失的值。
...
# define new data
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, 11300, 00000, 00000, 2]
下面列出了完整的示例。
# constant imputation strategy and prediction for the hose colic dataset
from numpy import nan
from pandas import read_csv
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
# load dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/horse-colic.csv'
dataframe = read_csv(url, header=None, na_values='?')
# split into input and output elements
data = dataframe.values
ix = [i for i in range(data.shape[1]) if i != 23]
X, y = data[:, ix], data[:, 23]
# create the modeling pipeline
pipeline = Pipeline(steps=[('i', SimpleImputer(strategy='constant')), ('m', RandomForestClassifier())])
# fit the model
pipeline.fit(X, y)
# define new data
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, 11300, 00000, 00000, 2]
# make a prediction
yhat = pipeline.predict([row])
# summarize prediction
print('Predicted Class: %d' % yhat[0])
运行该示例适合所有可用数据的建模管道。
定义一个新的数据行,其缺失值用 NaNs 标记,并进行分类预测。
Predicted Class: 2
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
相关教程
书
- 不良数据手册,2012 年。
- 数据挖掘:实用机器学习工具与技术,2016。
- 应用预测建模,2013。
蜜蜂
资料组
摘要
在本教程中,您发现了如何在机器学习中对缺失数据使用统计插补策略。
具体来说,您了解到:
- 缺少的值必须用 NaN 值标记,并且可以用统计度量值替换以计算值列。
- 如何加载缺失值的 CSV 值并用 NaN 值标记缺失值,并报告每列缺失值的数量和百分比。
- 在评估模型和拟合最终模型以对新数据进行预测时,如何用统计学作为数据准备方法来估计缺失值。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
使用 Sklearn 的表格数据测试时间增强
最后更新于 2020 年 8 月 18 日
测试时间扩充,简称 TTA,是一种提高预测模型技能的技术。
它通常用于提高深度学习模型在图像数据集上的预测表现,其中预测在测试数据集中每个图像的多个增强版本之间进行平均。
尽管在图像数据集和神经网络模型中很受欢迎,但是测试时间扩充可以与表格数据集上的任何机器学习算法一起使用,例如在回归和分类预测建模问题中经常看到的算法。
在本教程中,您将发现如何在 Sklearn 中对表格数据使用测试时间扩充。
完成本教程后,您将知道:
- 测试时间扩充是一种提高模型表现的技术,通常用于图像数据集上的深度学习模型。
- 如何用 Sklearn 在 Python 中实现回归和分类表格数据集的测试时间扩充。
- 如何调整测试时间扩充中使用的合成样本数量和统计噪声量?
用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
用 Scikit 增加测试时间-学习 图片由 barnimages 提供,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 测试时间扩充
- 标准模型评估
- 测试时间扩充示例
测试时间扩充
测试时间扩充,简称 TTA,是一种提高预测模型技能的技术。
这是在使用拟合模型进行预测时实现的过程,例如在测试数据集或新数据上。该过程包括为数据集中的每个示例创建多个稍加修改的副本。对每个修改的示例进行预测,并且对预测进行平均,以给出对原始示例的更准确的预测。
TTA 常用于图像分类,其中图像数据扩充用于创建每个图像的多个修改版本,例如裁剪、缩放、旋转和其他特定于图像的修改。因此,该技术提高了图像分类算法在标准数据集上的表现。
在他们 2015 年发表的题为“用于大规模图像识别的非常深卷积网络”的论文中,作者使用了水平翻转测试时间扩充:
我们还通过水平翻转图像来增加测试集;原始图像和翻转图像的软最大类后验值被平均以获得图像的最终分数。
——用于大规模图像识别的超深度卷积网络,2015。
有关使用图像数据进行测试时增强的更多信息,请参见教程:
虽然经常用于图像数据,但是测试时间扩充也可以用于其他数据类型,例如表格数据(例如数字的行和列)。
有许多方法可以将 TTA 用于表格数据。一种简单的方法是创建添加了小高斯噪声的数据行的副本。然后可以对来自复制行的预测进行平均,以产生用于回归或分类的改进预测。
我们将探索如何使用 Sklearn Python 机器学习库来实现这一点。
首先,让我们定义一个评估模型的标准方法。
标准模型评估
在这一节中,我们将在下一节介绍测试时间扩充之前,探索评估机器学习模型的典型方法。
首先,让我们定义一个综合类别数据集。
我们将使用 make_classification()函数创建一个包含 100 个示例的数据集,每个示例有 20 个输入变量。
该示例创建并汇总数据集。
# test classification dataset
from sklearn.datasets import make_classification
# define dataset
X, y = make_classification(n_samples=100, n_features=20, n_informative=15, n_redundant=5, random_state=1)
# summarize the dataset
print(X.shape, y.shape)
运行该示例将创建数据集,并确认数据集的行数和列数。
(100, 20) (100,)
这是一个二分类任务,我们将拟合和评估一个线性模型,特别是逻辑回归模型。
在评估机器学习模型时,一个好的实践是使用重复的 k-fold 交叉验证。当数据集存在分类问题时,确保使用 k-fold 交叉验证的分层版本非常重要。因此,我们将使用 10 倍和 5 倍重复的重复分层 k 倍交叉验证。
...
# prepare the cross-validation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=5, random_state=1)
我们将手动枚举折叠和重复,以便稍后我们可以执行测试时增强。
每个循环,我们必须定义和拟合模型,然后使用拟合模型进行预测,评估预测,并存储结果。
...
scores = list()
for train_ix, test_ix in cv.split(X, y):
# split the data
X_train, X_test = X[train_ix], X[test_ix]
y_train, y_test = y[train_ix], y[test_ix]
# fit model
model = LogisticRegression()
model.fit(X_train, y_train)
# evaluate model
y_hat = model.predict(X_test)
acc = accuracy_score(y_test, y_hat)
scores.append(acc)
最后,我们可以报告所有折叠和重复的平均分类准确率。
...
# report performance
print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))
将这些联系在一起,下面列出了在综合二元类别数据集上评估逻辑回归模型的完整示例。
# evaluate logistic regression using repeated stratified k-fold cross-validation
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# create dataset
X, y = make_classification(n_samples=100, n_features=20, n_informative=15, n_redundant=5, random_state=1)
# prepare the cross-validation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=5, random_state=1)
scores = list()
for train_ix, test_ix in cv.split(X, y):
# split the data
X_train, X_test = X[train_ix], X[test_ix]
y_train, y_test = y[train_ix], y[test_ix]
# fit model
model = LogisticRegression()
model.fit(X_train, y_train)
# evaluate model
y_hat = model.predict(X_test)
acc = accuracy_score(y_test, y_hat)
scores.append(acc)
# report performance
print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))
运行该示例使用重复的分层 k 倍交叉验证来评估逻辑回归。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到该模型实现了 79.8%的平均分类准确率。
Accuracy: 0.798 (0.110)
接下来,让我们探索如何更新这个例子来使用测试时间扩充。
测试时间扩充示例
实现测试时间扩充包括两个步骤。
第一步是选择一种方法来创建测试集中每一行的修改版本。
在本教程中,我们将为每个特征添加高斯随机噪声。另一种方法可能是添加均匀的随机噪声,甚至从测试数据集中的示例中复制特征值。
normal() NumPy 函数将用于创建均值为零、标准差较小的随机高斯值向量。标准偏差应该与训练数据集中每个变量的分布成比例。在这种情况下,我们将保持示例简单,并使用 0.02 的值。
...
# create vector of random gaussians
gauss = normal(loc=0.0, scale=feature_scale, size=len(row))
# add to test case
new_row = row + gauss
给定测试集中的一行数据,我们可以创建给定数量的修改副本。使用奇数个副本是一个好主意,例如 3、5 或 7 个副本,因为当我们稍后平均分配给每个副本的标签时,我们希望自动断开联系。
下面的 create_test_set() 函数实现了这一点;给定一行数据,它将返回包含该行以及“ n_cases ”修改副本的测试集,默认为 3(因此测试集大小为 4)。
# create a test set for a row of real data with an unknown label
def create_test_set(row, n_cases=3, feature_scale=0.2):
test_set = list()
test_set.append(row)
# make copies of row
for _ in range(n_cases):
# create vector of random gaussians
gauss = normal(loc=0.0, scale=feature_scale, size=len(row))
# add to test case
new_row = row + gauss
# store in test set
test_set.append(new_row)
return test_set
这种方法的一个改进是对每个循环的训练和测试数据集进行标准化或规范化,然后使用标准偏差 normal() ,该标准偏差在对标准 normal 有意义的特征之间是一致的。这是留给读者的练习。
第二种设置是对测试集中的每个示例使用 create_test_set() ,对构建的测试集进行预测,并使用预测中的汇总统计记录预测的标签。假设预测是绝对的,通过模式()scipy 函数,统计模式将是合适的。如果数据集是回归的,或者我们在预测概率,那么平均值或中值会更合适。
...
# create the test set
test_set = create_test_set(row)
# make a prediction for all examples in the test set
labels = model.predict(test_set)
# select the label as the mode of the distribution
label, _ = mode(labels)
下面的*test _ time _ employment()*函数实现了这一点;给定一个模型和一个测试集,它返回一个预测数组,其中每个预测都是使用测试时间扩充进行的。
# make predictions using test-time augmentation
def test_time_augmentation(model, X_test):
# evaluate model
y_hat = list()
for i in range(X_test.shape[0]):
# retrieve the row
row = X_test[i]
# create the test set
test_set = create_test_set(row)
# make a prediction for all examples in the test set
labels = model.predict(test_set)
# select the label as the mode of the distribution
label, _ = mode(labels)
# store the prediction
y_hat.append(label)
return y_hat
将所有这些联系在一起,下面列出了使用测试时间扩充在数据集上评估逻辑回归模型的完整示例。
# evaluate logistic regression using test-time augmentation
from numpy.random import seed
from numpy.random import normal
from numpy import mean
from numpy import std
from scipy.stats import mode
from sklearn.datasets import make_classification
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# create a test set for a row of real data with an unknown label
def create_test_set(row, n_cases=3, feature_scale=0.2):
test_set = list()
test_set.append(row)
# make copies of row
for _ in range(n_cases):
# create vector of random gaussians
gauss = normal(loc=0.0, scale=feature_scale, size=len(row))
# add to test case
new_row = row + gauss
# store in test set
test_set.append(new_row)
return test_set
# make predictions using test-time augmentation
def test_time_augmentation(model, X_test):
# evaluate model
y_hat = list()
for i in range(X_test.shape[0]):
# retrieve the row
row = X_test[i]
# create the test set
test_set = create_test_set(row)
# make a prediction for all examples in the test set
labels = model.predict(test_set)
# select the label as the mode of the distribution
label, _ = mode(labels)
# store the prediction
y_hat.append(label)
return y_hat
# initialize numpy random number generator
seed(1)
# create dataset
X, y = make_classification(n_samples=100, n_features=20, n_informative=15, n_redundant=5, random_state=1)
# prepare the cross-validation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=5, random_state=1)
scores = list()
for train_ix, test_ix in cv.split(X, y):
# split the data
X_train, X_test = X[train_ix], X[test_ix]
y_train, y_test = y[train_ix], y[test_ix]
# fit model
model = LogisticRegression()
model.fit(X_train, y_train)
# make predictions using test-time augmentation
y_hat = test_time_augmentation(model, X_test)
# calculate the accuracy for this iteration
acc = accuracy_score(y_test, y_hat)
# store the result
scores.append(acc)
# report performance
print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))
运行该示例使用重复的分层 k 倍交叉验证和测试时间扩充来评估逻辑回归。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到该模型实现了 81.0%的平均分类准确率,这优于没有使用测试时间扩充的测试工具,后者实现了 79.8%的准确率。
Accuracy: 0.810 (0.114)
网格搜索每次在测试时间扩充期间进行预测时创建的合成示例的数量可能会很有趣。
下面的示例探索 1 到 20 之间的值,并绘制结果。
# compare the number of synthetic examples created during the test-time augmentation
from numpy.random import seed
from numpy.random import normal
from numpy import mean
from numpy import std
from scipy.stats import mode
from sklearn.datasets import make_classification
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from matplotlib import pyplot
# create a test set for a row of real data with an unknown label
def create_test_set(row, n_cases=3, feature_scale=0.2):
test_set = list()
test_set.append(row)
# make copies of row
for _ in range(n_cases):
# create vector of random gaussians
gauss = normal(loc=0.0, scale=feature_scale, size=len(row))
# add to test case
new_row = row + gauss
# store in test set
test_set.append(new_row)
return test_set
# make predictions using test-time augmentation
def test_time_augmentation(model, X_test, cases):
# evaluate model
y_hat = list()
for i in range(X_test.shape[0]):
# retrieve the row
row = X_test[i]
# create the test set
test_set = create_test_set(row, n_cases=cases)
# make a prediction for all examples in the test set
labels = model.predict(test_set)
# select the label as the mode of the distribution
label, _ = mode(labels)
# store the prediction
y_hat.append(label)
return y_hat
# evaluate different number of synthetic examples created at test time
examples = range(1, 21)
results = list()
for e in examples:
# initialize numpy random number generator
seed(1)
# create dataset
X, y = make_classification(n_samples=100, n_features=20, n_informative=15, n_redundant=5, random_state=1)
# prepare the cross-validation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=5, random_state=1)
scores = list()
for train_ix, test_ix in cv.split(X, y):
# split the data
X_train, X_test = X[train_ix], X[test_ix]
y_train, y_test = y[train_ix], y[test_ix]
# fit model
model = LogisticRegression()
model.fit(X_train, y_train)
# make predictions using test-time augmentation
y_hat = test_time_augmentation(model, X_test, e)
# calculate the accuracy for this iteration
acc = accuracy_score(y_test, y_hat)
# store the result
scores.append(acc)
# report performance
print('>%d, acc: %.3f (%.3f)' % (e, mean(scores), std(scores)))
results.append(mean(scores))
# plot the results
pyplot.plot(examples, results)
pyplot.show()
运行该示例报告了在测试时间扩充期间创建的不同数量的合成示例的准确性。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
回想一下,我们在前面的例子中使用了三个例子。
在这种情况下,看起来值 3 可能是这个测试工具的最佳值,因为所有其他值似乎都会导致较低的表现。
>1, acc: 0.800 (0.118)
>2, acc: 0.806 (0.114)
>3, acc: 0.810 (0.114)
>4, acc: 0.798 (0.105)
>5, acc: 0.802 (0.109)
>6, acc: 0.798 (0.107)
>7, acc: 0.800 (0.111)
>8, acc: 0.802 (0.110)
>9, acc: 0.806 (0.105)
>10, acc: 0.802 (0.110)
>11, acc: 0.798 (0.112)
>12, acc: 0.806 (0.110)
>13, acc: 0.802 (0.110)
>14, acc: 0.802 (0.109)
>15, acc: 0.798 (0.110)
>16, acc: 0.796 (0.111)
>17, acc: 0.806 (0.112)
>18, acc: 0.796 (0.111)
>19, acc: 0.800 (0.113)
>20, acc: 0.804 (0.109)
创建了示例数量与分类准确率的线图,显示奇数个示例通常比偶数个示例具有更好的表现。
这可能是意料之中的,因为他们在使用预测模式时有能力打破联系。
TTA 合成样本数与分类准确率的线图
在测试时间扩充期间,我们也可以用添加到测试集中的示例中的随机噪声量来执行相同的灵敏度分析。
下面的示例演示了这一点,噪声值介于 0.01 和 0.3 之间,网格为 0.01。
# compare amount of noise added to examples created during the test-time augmentation
from numpy.random import seed
from numpy.random import normal
from numpy import arange
from numpy import mean
from numpy import std
from scipy.stats import mode
from sklearn.datasets import make_classification
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from matplotlib import pyplot
# create a test set for a row of real data with an unknown label
def create_test_set(row, n_cases=3, feature_scale=0.2):
test_set = list()
test_set.append(row)
# make copies of row
for _ in range(n_cases):
# create vector of random gaussians
gauss = normal(loc=0.0, scale=feature_scale, size=len(row))
# add to test case
new_row = row + gauss
# store in test set
test_set.append(new_row)
return test_set
# make predictions using test-time augmentation
def test_time_augmentation(model, X_test, noise):
# evaluate model
y_hat = list()
for i in range(X_test.shape[0]):
# retrieve the row
row = X_test[i]
# create the test set
test_set = create_test_set(row, feature_scale=noise)
# make a prediction for all examples in the test set
labels = model.predict(test_set)
# select the label as the mode of the distribution
label, _ = mode(labels)
# store the prediction
y_hat.append(label)
return y_hat
# evaluate different number of synthetic examples created at test time
noise = arange(0.01, 0.31, 0.01)
results = list()
for n in noise:
# initialize numpy random number generator
seed(1)
# create dataset
X, y = make_classification(n_samples=100, n_features=20, n_informative=15, n_redundant=5, random_state=1)
# prepare the cross-validation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=5, random_state=1)
scores = list()
for train_ix, test_ix in cv.split(X, y):
# split the data
X_train, X_test = X[train_ix], X[test_ix]
y_train, y_test = y[train_ix], y[test_ix]
# fit model
model = LogisticRegression()
model.fit(X_train, y_train)
# make predictions using test-time augmentation
y_hat = test_time_augmentation(model, X_test, n)
# calculate the accuracy for this iteration
acc = accuracy_score(y_test, y_hat)
# store the result
scores.append(acc)
# report performance
print('>noise=%.3f, acc: %.3f (%.3f)' % (n, mean(scores), std(scores)))
results.append(mean(scores))
# plot the results
pyplot.plot(noise, results)
pyplot.show()
运行该示例报告了在测试时间扩充期间添加到创建的示例中的不同统计噪声量的准确性。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
回想一下,我们在第一个示例中使用了 0.02 的标准偏差。
在这种情况下,看起来大约 0.230 的值可能是该测试线束的最佳值,导致 81.2%的稍高准确率。
>noise=0.010, acc: 0.798 (0.110)
>noise=0.020, acc: 0.798 (0.110)
>noise=0.030, acc: 0.798 (0.110)
>noise=0.040, acc: 0.800 (0.113)
>noise=0.050, acc: 0.802 (0.112)
>noise=0.060, acc: 0.804 (0.111)
>noise=0.070, acc: 0.806 (0.108)
>noise=0.080, acc: 0.806 (0.108)
>noise=0.090, acc: 0.806 (0.108)
>noise=0.100, acc: 0.806 (0.108)
>noise=0.110, acc: 0.806 (0.108)
>noise=0.120, acc: 0.806 (0.108)
>noise=0.130, acc: 0.806 (0.108)
>noise=0.140, acc: 0.806 (0.108)
>noise=0.150, acc: 0.808 (0.111)
>noise=0.160, acc: 0.808 (0.111)
>noise=0.170, acc: 0.808 (0.111)
>noise=0.180, acc: 0.810 (0.114)
>noise=0.190, acc: 0.810 (0.114)
>noise=0.200, acc: 0.810 (0.114)
>noise=0.210, acc: 0.810 (0.114)
>noise=0.220, acc: 0.810 (0.114)
>noise=0.230, acc: 0.812 (0.114)
>noise=0.240, acc: 0.812 (0.114)
>noise=0.250, acc: 0.812 (0.114)
>noise=0.260, acc: 0.812 (0.114)
>noise=0.270, acc: 0.810 (0.114)
>noise=0.280, acc: 0.808 (0.116)
>noise=0.290, acc: 0.808 (0.116)
>noise=0.300, acc: 0.808 (0.116)
创建了添加到示例中的噪声量与分类准确率之间的线图,显示了在标准偏差为 0.250 左右的小范围噪声可能是该测试线束的最佳值。
添加到 TTA 示例中的统计噪声的线图与分类准确率的关系
为什么不用 SMOTE 这样的过采样方法?
SMOTE 是一种流行的过采样方法,用于重新平衡训练数据集中每个类别的观测值。它可以创建合成的例子,但是需要类标签的知识,这使得它不容易在测试时间扩充中使用。
一种方法可能是举一个需要预测的给定例子,并假设它属于一个给定的类。然后使用新示例作为合成的焦点,从训练数据集中生成合成样本,并对它们进行分类。然后对每个类别标签重复这一过程。可以统计每个班级组的总的或平均的分类反应(可能是概率),反应最大的组可以作为预测。
这只是即兴创作,我实际上并没有尝试过这种方法。试一试,让我知道它是否有效。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
教程
蜜蜂
- sklearn . datasets . make _ classification API。
- sklearn.model_selection。重复的策略应用编程接口。
- numpy.random.normal API 。
- scipy . stat . mode API的缩写形式。
摘要
在本教程中,您发现了如何在 Sklearn 中对表格数据使用测试时间扩充。
具体来说,您了解到:
- 测试时间扩充是一种提高模型表现的技术,通常用于图像数据集上的深度学习模型。
- 如何用 Sklearn 在 Python 中实现回归和分类表格数据集的测试时间扩充。
- 如何调整测试时间扩充中使用的合成样本数量和统计噪声量?
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
如何在机器学习中训练测试集
对测试集的训练是一种过拟合,即准备一个模型,以增加泛化误差为代价,有意在给定的测试集上获得良好的表现。
这是一种在机器学习竞赛中常见的过拟合类型,其中提供了完整的训练数据集,并且只提供了测试集的输入部分。对测试集进行训练的一种方法是构建一个与测试集最相似的训练集,然后将其用作训练模型的基础。该模型在测试集上的表现预计会更好,但在训练数据集和未来的任何新数据上的表现很可能会更差。
虽然过拟合测试集是不可取的,但作为一个思维实验进行探索,并提供更多关于机器学习竞赛和避免过拟合的见解,可能会很有趣。
在本教程中,您将发现如何针对分类和回归问题有意识地训练测试集。
完成本教程后,您将知道:
- 对测试集的训练是机器学习竞赛中可能出现的一种数据泄露。
- 对测试集进行训练的一种方法是创建一个与所提供的测试集最相似的训练数据集。
- 如何使用 KNN 模型构建训练数据集,并用真实数据集训练测试集。
用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
如何训练到机器学习中的测试集 图片由 ND Strupler 提供,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 训练到测试集
- 训练到测试集进行分类
- 训练回归测试集
训练到测试集
在应用机器学习中,我们寻求一种使用训练数据集学习输入和输出变量之间关系的模型。
我们的希望和目标是学习一种关系,这种关系可以推广到训练数据集之外的新例子。这个目标促使我们在对训练期间未使用的数据进行预测时,使用像 k 倍交叉验证这样的重采样技术来估计模型的表现。
在机器学习竞赛的情况下,就像 Kaggle 上的竞赛一样,我们可以访问完整的训练数据集和测试数据集的输入,并且需要对测试数据集进行预测。
这导致了一种可能的情况,即我们可能会意外地或选择将模型训练到测试集。也就是说,调整模型行为以在测试数据集上获得最佳表现,而不是使用类似 k-fold 交叉验证的技术开发一个总体表现良好的模型。
另一种更明显的信息泄露途径,有时可以在机器学习比赛中看到,在比赛中训练和测试集数据同时给出。
—第 56 页,特征工程和选择:预测模型的实用方法,2019 年。
训练到测试集往往是个坏主意。
这是一种显式的数据泄露。然而,这是一个有趣的思想实验。
对测试集进行训练的一种方法是设计一个与测试集最相似的训练数据集。例如,我们可以丢弃训练集中与测试集差异太大的所有行,只在训练集中与测试集最相似的行上进行训练。
虽然测试集数据通常会使结果数据不可见,但只使用与测试集数据最相似的训练集样本就可以“训练测试”。这可能会很好地提高该特定测试集的模型表现分数,但可能会破坏在更广泛的数据集上进行预测的模型。
—第 56 页,特征工程和选择:预测模型的实用方法,2019 年。
我们会期望模型超过测试集,但这是这个思想实验的全部意义。
让我们探索这种方法来训练本教程中的测试集。
我们可以使用 k 近邻模型来选择那些与测试集最相似的训练集实例。kneighgboresgressor和kneighgborsclassifier都提供了kneighgbors()函数,该函数会将与给定数据(如测试集)最相似的行的索引返回到训练数据集中。
...
# get the most similar neighbor for each point in the test set
neighbor_ix = knn.kneighbors(X_test, 2, return_distance=False)
ix = neighbor_ix[:,0]
我们可能需要尝试从选定的行索引中删除重复项。
...
# remove duplicate rows
ix = unique(ix)
然后,我们可以使用这些行索引来构建定制的训练数据集并拟合模型。
...
# create a training dataset from selected instances
X_train_neigh, y_train_neigh = X_train[ix], y_train[ix]
假设我们使用 KNN 模型从测试集构建训练集,我们也将使用相同类型的模型对测试集进行预测。这不是必需的,但它使示例更简单。
使用这种方法,我们现在可以对分类和回归数据集的测试集进行训练实验。
训练到测试集进行分类
我们将使用糖尿病数据集作为探索分类问题测试集训练的基础。
每份记录都描述了女性的医疗细节,预测是未来五年内糖尿病的发作。
数据集有 8 个输入变量和 768 行数据;输入变量都是数字,目标有两个类标签,例如,它是一个二进制分类任务。
下面提供了数据集前五行的示例。
6,148,72,35,0,33.6,0.627,50,1
1,85,66,29,0,26.6,0.351,31,0
8,183,64,0,0,23.3,0.672,32,1
1,89,66,23,94,28.1,0.167,21,0
0,137,40,35,168,43.1,2.288,33,1
...
首先,我们可以直接从网址加载数据集,将其分成输入和输出元素,然后将数据集分成训练集和测试集,为测试集保留 30%的空间。然后,我们可以通过在训练集上训练 KNN 模型并在测试集上进行预测来评估具有默认模型超参数的模型。
下面列出了完整的示例。
# example of evaluating a knn model on the diabetes classification dataset
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.neighbors import KNeighborsClassifier
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.csv'
df = read_csv(url, header=None)
data = df.values
X, y = data[:, :-1], data[:, -1]
print(X.shape, y.shape)
# split dataset
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
# define model
model = KNeighborsClassifier()
# fit model
model.fit(X_train, y_train)
# make predictions
yhat = model.predict(X_test)
# evaluate predictions
accuracy = accuracy_score(y_test, yhat)
print('Accuracy: %.3f' % (accuracy * 100))
运行该示例首先加载数据集并总结行数和列数,符合我们的预期。然后报告列车和测试集的形状,显示测试集中大约有 230 行。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
最后,该模型的分类准确率约为 77.056%。
(768, 8) (768,)
(537, 8) (231, 8) (537,) (231,)
Accuracy: 77.056
现在,让我们看看通过准备一个直接为其训练的模型,我们是否能在测试集上获得更好的表现。
首先,我们将使用训练集中更简单的示例为测试集中的每一行构建一个训练数据集。
...
# select examples that are most similar to the test set
knn = KNeighborsClassifier()
knn.fit(X_train, y_train)
# get the most similar neighbor for each point in the test set
neighbor_ix = knn.kneighbors(X_test, 1, return_distance=False)
ix = neighbor_ix[:,0]
# create a training dataset from selected instances
X_train_neigh, y_train_neigh = X_train[ix], y_train[ix]
print(X_train_neigh.shape, y_train_neigh.shape)
接下来,我们将在这个新的数据集上训练模型,并像以前一样在测试集上评估它。
...
# define model
model = KNeighborsClassifier()
# fit model
model.fit(X_train_neigh, y_train_neigh)
下面列出了完整的示例。
# example of training to the test set for the diabetes dataset
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.neighbors import KNeighborsClassifier
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.csv'
df = read_csv(url, header=None)
data = df.values
X, y = data[:, :-1], data[:, -1]
print(X.shape, y.shape)
# split dataset
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
# select examples that are most similar to the test set
knn = KNeighborsClassifier()
knn.fit(X_train, y_train)
# get the most similar neighbor for each point in the test set
neighbor_ix = knn.kneighbors(X_test, 1, return_distance=False)
ix = neighbor_ix[:,0]
# create a training dataset from selected instances
X_train_neigh, y_train_neigh = X_train[ix], y_train[ix]
print(X_train_neigh.shape, y_train_neigh.shape)
# define model
model = KNeighborsClassifier()
# fit model
model.fit(X_train_neigh, y_train_neigh)
# make predictions
yhat = model.predict(X_test)
# evaluate predictions
accuracy = accuracy_score(y_test, yhat)
print('Accuracy: %.3f' % (accuracy * 100))
运行该示例,我们可以看到新训练数据集的报告大小与测试集的大小相同,正如我们预期的那样。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
我们可以看到,与在整个训练数据集上训练模型相比,通过训练测试集,我们已经实现了表现的提升。在这种情况下,我们实现了大约 79.654%的分类准确率,而在使用整个训练数据集时,分类准确率为 77.056%。
(768, 8) (768,)
(537, 8) (231, 8) (537,) (231,)
(231, 8) (231,)
Accuracy: 79.654
您可能希望尝试从训练集中为测试集中的每个示例选择不同数量的邻居,看看是否可以获得更好的表现。
此外,您可能想尝试在训练集中保留唯一的行索引,看看这是否有所不同。
最后,保留最终验证数据集并比较不同的“训练到测试集”技术如何影响保持数据集的表现可能会很有趣。例如,查看对测试集的训练如何影响泛化错误。
在下面的评论中报告你的发现。
现在我们知道如何训练测试集进行分类,让我们看一个回归的例子。
训练回归测试集
我们将使用房屋数据集作为探索回归问题测试集训练的基础。
房屋数据集涉及房屋及其附近地区的详细信息,以千美元为单位预测房价。
这是一个回归问题,意味着我们预测的是一个数值。有 506 个观测值,有 13 个输入变量和一个输出变量。
下面列出了前五行的示例。
0.00632,18.00,2.310,0,0.5380,6.5750,65.20,4.0900,1,296.0,15.30,396.90,4.98,24.00
0.02731,0.00,7.070,0,0.4690,6.4210,78.90,4.9671,2,242.0,17.80,396.90,9.14,21.60
0.02729,0.00,7.070,0,0.4690,7.1850,61.10,4.9671,2,242.0,17.80,392.83,4.03,34.70
0.03237,0.00,2.180,0,0.4580,6.9980,45.80,6.0622,3,222.0,18.70,394.63,2.94,33.40
0.06905,0.00,2.180,0,0.4580,7.1470,54.20,6.0622,3,222.0,18.70,396.90,5.33,36.20
...
首先,我们可以加载数据集,分割它,并使用整个训练数据集直接在其上评估 KNN 模型。我们将使用平均绝对误差(MAE)报告这个回归类的表现。
下面列出了完整的示例。
# example of evaluating a knn model on the housing regression dataset
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error
from sklearn.neighbors import KNeighborsRegressor
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv'
df = read_csv(url, header=None)
data = df.values
X, y = data[:, :-1], data[:, -1]
print(X.shape, y.shape)
# split dataset
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
# define model
model = KNeighborsRegressor()
# fit model
model.fit(X_train, y_train)
# make predictions
yhat = model.predict(X_test)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)
运行该示例首先加载数据集并总结行数和列数,符合我们的预期。然后报告列车和测试集的形状,显示测试集中大约有 150 行。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
最后,模型的 MAE 据报道约为 4.488。
(506, 13) (506,)
(354, 13) (152, 13) (354,) (152,)
MAE: 4.488
现在,让我们看看我们是否可以通过准备一个经过训练的模型来在测试集上获得更好的表现。
首先,我们将使用训练集中更简单的示例为测试集中的每一行构建一个训练数据集。
...
# select examples that are most similar to the test set
knn = KNeighborsClassifier()
knn.fit(X_train, y_train)
# get the most similar neighbor for each point in the test set
neighbor_ix = knn.kneighbors(X_test, 1, return_distance=False)
ix = neighbor_ix[:,0]
# create a training dataset from selected instances
X_train_neigh, y_train_neigh = X_train[ix], y_train[ix]
print(X_train_neigh.shape, y_train_neigh.shape)
接下来,我们将在这个新的数据集上训练模型,并像以前一样在测试集上评估它。
...
# define model
model = KNeighborsClassifier()
# fit model
model.fit(X_train_neigh, y_train_neigh)
下面列出了完整的示例。
# example of training to the test set for the housing dataset
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error
from sklearn.neighbors import KNeighborsRegressor
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/housing.csv'
df = read_csv(url, header=None)
data = df.values
X, y = data[:, :-1], data[:, -1]
print(X.shape, y.shape)
# split dataset
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
# select examples that are most similar to the test set
knn = KNeighborsRegressor()
knn.fit(X_train, y_train)
# get the most similar neighbor for each point in the test set
neighbor_ix = knn.kneighbors(X_test, 1, return_distance=False)
ix = neighbor_ix[:,0]
# create a training dataset from selected instances
X_train_neigh, y_train_neigh = X_train[ix], y_train[ix]
print(X_train_neigh.shape, y_train_neigh.shape)
# define model
model = KNeighborsRegressor()
# fit model
model.fit(X_train_neigh, y_train_neigh)
# make predictions
yhat = model.predict(X_test)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)
运行该示例,我们可以看到新训练数据集的报告大小与测试集的大小相同,正如我们预期的那样。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
我们可以看到,与在整个训练数据集上训练模型相比,通过训练测试集,我们已经实现了表现的提升。在这种情况下,与使用整个训练数据集时的 4.488 相比,我们获得了大约 4.433 的 MAE。
同样,在构建新的训练集时,您可能希望探索使用不同数量的邻居,看看在训练数据集中保留唯一的行是否有所不同。在下面的评论中报告你的发现。
(506, 13) (506,)
(354, 13) (152, 13) (354,) (152,)
(152, 13) (152,)
MAE: 4.433
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
书
- 特征工程和选择:预测模型的实用方法,2019。
蜜蜂
摘要
在本教程中,您发现了如何针对分类和回归问题有意识地训练测试集。
具体来说,您了解到:
- 对测试集的训练是机器学习竞赛中可能出现的一种数据泄露。
- 对测试集进行训练的一种方法是创建一个与所提供的测试集最相似的训练数据集。
- 如何使用 KNN 模型构建训练数据集,并用真实数据集训练测试集。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
什么是机器学习项目中的数据准备
最后更新于 2020 年 6 月 30 日
数据准备可能是任何机器学习项目中最困难的步骤之一。
原因是每个数据集都是不同的,并且高度特定于项目。然而,跨预测建模项目有足够多的共性,我们可以定义您可能执行的一系列松散的步骤和子任务。
这个过程提供了一个背景,我们可以在其中考虑项目所需的数据准备,由数据准备之前执行的项目定义和之后执行的机器学习算法的评估来提供信息。
在本教程中,您将发现如何将数据准备视为更广泛的预测建模机器学习项目的一个步骤。
完成本教程后,您将知道:
- 每个带有机器学习的预测建模项目都是不同的,但是每个项目都有共同的步骤。
- 数据准备包括最好地将问题的未知底层结构暴露给学习算法。
- 项目中数据准备之前和之后的步骤可以告知应用或者至少探索哪些数据准备方法。
用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
什么是机器学习项目中的数据准备 图片由 dashll 提供,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 应用机器学习过程
- 什么是数据准备
- 如何选择数据准备技术
应用机器学习过程
每个机器学习项目都是不同的,因为项目核心的具体数据是不同的。
你可能是第一个人(有史以来!)来处理特定的预测建模问题。这并不意味着其他人没有从事过类似的预测任务,甚至可能没有从事过相同的高级任务,但是您是第一个使用您收集的特定数据的人(除非您正在使用标准数据集进行练习)。
……正确的特征只能在模型和数据的上下文中定义;因为数据和模型是如此的多样化,所以很难在项目间推广特性工程的实践。
—第七页,机器学习的特征工程,2018。
这使得每个机器学习项目都是独一无二的。没有人能告诉你最好的结果是什么或可能是什么,或者用什么算法来实现它们。您必须建立一个表现基线作为比较所有模型的参考点,并且您必须发现什么算法最适合您的特定数据集。
你并不孤单,之前关于应用机器学习的大量文献可以告诉你如何使用技术来稳健地评估你的模型和算法。
即使你的项目是独一无二的,通往好的甚至最好的结果的道路上的步骤在不同的项目中通常是相同的。这有时被称为“应用机器学习过程”、“数据科学过程”,或更老的名称“数据库中的知识发现”(KDD)。
应用机器学习的过程由一系列步骤组成。步骤是相同的,但是执行的步骤和任务的名称可能因描述而异。
此外,这些步骤是按顺序编写的,但是对于任何给定的项目,我们将在这些步骤之间来回跳转。
我喜欢使用四个高级步骤来定义流程:
- 第一步:定义问题。
- 第二步:准备数据。
- 第三步:评估模型。
- 第四步:定型。
让我们仔细看看这些步骤。
步骤 1:定义问题
这一步涉及对项目的足够了解,以选择预测任务的框架或框架。比如是分类还是回归,或者其他一些高阶问题类型?
它包括收集被认为有助于做出预测的数据,并明确定义预测将采取的形式。它还可能涉及到与项目涉众和其他在该领域具有深厚专业知识的人交谈。
这一步还包括仔细查看数据,以及可能使用汇总统计和数据可视化来探索数据。
第二步:准备数据
这一步涉及将收集的原始数据转换成可用于建模的形式。
数据预处理技术通常指训练集数据的添加、删除或转换。
—第 27 页,应用预测建模,2013 年。
我们将在下一节中更详细地了解这一步骤。
步骤 3:评估模型
这一步涉及评估数据集上的机器学习模型。
它要求您设计一个健壮的测试工具来评估您的模型,以便您得到的结果可以被信任,并用于在您已经评估的模型中进行选择。
这包括选择评估模型技能的表现指标、建立所有模型评估可与之比较的表现基线或下限,以及将数据拆分为训练集和测试集以模拟如何使用最终模型的重采样技术等任务。
对于模型表现的快速和肮脏的估计,或者对于非常大的数据集,可以执行数据的单个训练测试分割。更常见的是使用 k 倍交叉验证作为数据重采样技术,通常重复该过程以提高结果的鲁棒性。
这一步还包括从表现良好的模型中获得最大收益的任务,如超参数调整和模型集成。
步骤 4:最终确定模型
这一步涉及选择和使用最终模型。
一旦评估了一套模型,您必须选择一个代表项目“解决方案”的模型。这被称为模型选择,可能涉及在等待验证数据集上进一步评估候选模型,或者通过其他特定于项目的标准(如模型复杂性)进行选择。
它还可能包括以标准的方式为项目涉众总结模型的表现,这是一个重要的步骤。
最后,可能会有与模型的产品化相关的任务,例如将其集成到软件项目或生产系统中,并为模型设计监控和维护计划。
现在我们已经熟悉了应用机器学习的过程,以及数据准备在该过程中的位置,让我们更仔细地看看可能执行的任务类型。
什么是数据准备
在预测建模项目中,例如分类或回归,原始数据通常不能直接使用。
这是因为以下原因:
- 机器学习算法要求数据是数字。
- 一些机器学习算法对数据提出了要求。
- 数据中的统计噪声和误差可能需要纠正。
- 复杂的非线性关系可以从数据中梳理出来。
因此,原始数据必须在用于拟合和评估机器学习模型之前进行预处理。预测建模项目中的这一步被称为“数据准备,尽管它还有许多其他名称,如“数据扯皮”、“数据清理”、“数据预处理”和“特征工程”。其中一些名称可能更适合作为更广泛的数据准备过程的子任务。
我们可以将数据准备定义为将原始数据转换为更适合建模的形式。
数据扯皮,也就是通常所说的数据蒙骗、转换、操纵、看门人工作等。,可能是一个煞费苦心费力的过程。
—第五页,与 R 的数据角力,2016。
这对于您的数据、项目的目标以及用于建模数据的算法来说是非常具体的。我们将在下一节中更多地讨论这些关系。
然而,在机器学习项目的数据准备步骤中,您可能会使用或探索一些常见或标准的任务。
这些任务包括:
- 数据清理:识别并纠正数据中的错误或差错。
- 特征选择:识别那些与任务最相关的输入变量。
- 数据转换:改变变量的规模或分布。
- 特征工程:从可用数据中导出新变量。
- 降维:创建数据的紧凑投影。
这些任务中的每一项都是具有专门算法的整个研究领域。
数据准备不是盲目进行的。
在某些情况下,在我们应用机器学习算法之前,必须对变量进行编码或转换,例如将字符串转换为数字。在其他情况下,就不那么清楚了,比如缩放变量对算法可能有用,也可能没用。
数据准备的更广泛的哲学是发现如何最好地将问题的底层结构暴露给学习算法。这是引导光。
我们不知道问题的潜在结构;如果我们这样做了,我们就不需要学习算法来发现它,并学习如何做出巧妙的预测。因此,揭示问题的未知底层结构是一个发现的过程,同时发现项目中表现良好或最好的学习算法。
然而,我们经常不知道改善模型表现的预测因子的最佳再现。相反,预测器的重新工作更像是一门艺术,需要正确的工具和经验来找到更好的预测器表示。此外,我们可能需要搜索许多替代的预测器表示来提高模型表现。
—第十二页,特征工程与选择,2019 年。
它可能比乍看起来更复杂。例如,不同的输入变量可能需要不同的数据准备方法。此外,不同的变量或输入变量子集可能需要不同的数据准备方法序列。
考虑到大量的方法,每种方法可能都有自己的配置和要求,这可能会让人感到难以承受。尽管如此,数据准备前后的机器学习过程步骤可以帮助告知需要考虑哪些技术。
如何选择数据准备技术
我们如何知道在数据中使用什么数据准备技术?
如同许多统计学问题一样,“哪个特征工程方法是最好的?”视情况而定。具体来说,这取决于所使用的模型以及与结果的真实关系。
—第 28 页,应用预测建模,2013 年。
从表面上看,这是一个具有挑战性的问题,但如果我们在整个项目的背景下看数据准备步骤,它会变得更加简单。预测建模项目中数据准备步骤前后的步骤通知可能需要的数据准备。
数据准备之前的步骤包括定义问题。
作为定义问题的一部分,这可能涉及许多子任务,例如:
- 从问题领域收集数据。
- 与主题专家讨论项目。
- 选择这些变量作为预测模型的输入和输出。
- 查看已收集的数据。
- 使用统计方法总结收集的数据。
- 使用图表将收集的数据可视化。
关于数据的已知信息可用于选择和配置数据准备方法。
例如,数据图可以帮助识别变量是否有异常值。这有助于数据清理操作。它还可以提供对数据背后的概率分布的洞察。这可能有助于确定改变变量概率分布的数据转换是否合适。
统计方法(如描述性统计)可用于确定是否需要缩放操作。统计假设检验可以用来确定一个变量是否符合给定的概率分布。
成对图和统计数据可用于确定变量是否相关,如果相关,则确定多少,从而提供一个或多个变量是否冗余或与目标变量无关的洞察。
因此,问题的定义和数据的准备之间可能有很多相互作用。
数据准备步骤和模型评估之间也可能存在相互作用。
模型评估可能涉及子任务,例如:
- 选择评估模型预测技能的表现指标。
- 选择模型评估程序。
- 选择要评估的算法。
- 调整算法超参数。
- 将预测模型组合成整体。
关于算法选择和发现表现良好的算法的已知信息也可以为数据准备方法的选择和配置提供信息。
例如,算法的选择可能会对数据中输入变量的类型和形式提出要求和期望。这可能需要变量具有特定的概率分布,移除相关的输入变量,和/或移除与目标变量没有强相关性的变量。
表现度量的选择也可能需要仔细准备目标变量以满足预期,例如使用特定的度量单位基于预测误差对回归模型进行评分,需要对应用于该变量的任何缩放变换进行反演以进行建模。
这些例子以及更多的例子强调,尽管数据准备是预测建模项目中的一个重要步骤,但它并不是孤立的。相反,它受到数据准备前后执行的任务的强烈影响。这突出了任何预测建模项目的高度迭代性。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
教程
书
- 特征工程和选择:预测模型的实用方法,2019。
- 机器学习的特征工程,2018。
- 应用预测建模,2013。
- 数据挖掘:实用机器学习工具与技术,第 4 版,2016。
文章
- 数据准备,维基百科。
- 数据清理,维基百科。
- 数据预处理,维基百科。
摘要
在本教程中,您发现了如何将数据准备视为更广泛的预测建模机器学习项目中的一个步骤。
具体来说,您了解到:
- 每个带有机器学习的预测建模项目都是不同的,但是每个项目都有共同的步骤。
- 数据准备包括最好地将问题的未知底层结构暴露给学习算法。
- 项目中数据准备之前和之后的步骤可以告知应用或者至少探索哪些数据准备方法。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。