Machine Learning Mastery 数据准备教程(四)
如何对数值输入数据执行特征选择
最后更新于 2020 年 8 月 18 日
特征选择是识别和选择与目标变量最相关的输入特征子集的过程。
在处理实值输入和输出数据时,例如使用皮尔逊相关系数,特征选择通常很简单,但在处理数值输入数据和分类目标变量时,特征选择可能很有挑战性。
当目标变量是分类的(例如分类预测建模)时,数值输入数据最常用的两种特征选择方法是方差分析 f 检验统计量和互信息统计量。
在本教程中,您将了解如何使用数字输入数据执行特征选择以进行分类。
完成本教程后,您将知道:
- 具有数值输入和二分类目标变量的糖尿病预测建模问题。
- 如何使用方差分析 f-检验和互信息统计评估数字特征的重要性。
- 在拟合和评估分类模型时,如何对数值数据进行特征选择。
用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
如何使用数值输入数据进行特征选择 图片由苏珊·尼尔森提供,保留部分权利。
教程概述
本教程分为四个部分;它们是:
- 糖尿病数值数据集
- 数字特征选择
- 方差分析 f 检验特征选择
- 互信息特征选择
- 使用选定特征建模
- 使用所有功能构建的模型
- 使用方差分析 f 检验特征建立的模型
- 利用互信息特征建立的模型
- 调整选定特征的数量
糖尿病数值数据集
作为本教程的基础,我们将使用自 1990 年以来作为机器学习数据集被广泛研究的所谓的“糖尿病”数据集。
该数据集将患者数据分为五年内糖尿病发作和非糖尿病发作。共有 768 个例子和 8 个输入变量。这是一个二分类问题。
一个简单的模型在这个数据集上可以达到大约 65%的准确率。好的分数大约是 77%+/-5%。我们将针对该地区,但请注意,本教程中的模型没有优化;它们旨在演示特征选择方案。
可以下载数据集,将文件保存为当前工作目录下的“pima-Indians-diabetes . CSV”。
查看数据,我们可以看到所有九个输入变量都是数值。
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
...
我们可以使用熊猫库将这个数据集加载到内存中。
...
# load the dataset as a pandas DataFrame
data = read_csv(filename, header=None)
# retrieve numpy array
dataset = data.values
加载后,我们可以将列拆分为输入(X)和输出(y)进行建模。
...
# split into input (X) and output (y) variables
X = dataset[:, :-1]
y = dataset[:,-1]
我们可以将所有这些结合到一个有用的函数中,以便以后重用。
# load the dataset
def load_dataset(filename):
# load the dataset as a pandas DataFrame
data = read_csv(filename, header=None)
# retrieve numpy array
dataset = data.values
# split into input (X) and output (y) variables
X = dataset[:, :-1]
y = dataset[:,-1]
return X, y
加载后,我们可以将数据分成训练集和测试集,这样我们就可以拟合和评估学习模型。
我们将使用 train_test_split()函数形成 Sklearn,并将 67%的数据用于训练,33%的数据用于测试。
...
# load the dataset
X, y = load_dataset('pima-indians-diabetes.csv')
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
将所有这些元素结合在一起,下面列出了加载、拆分和汇总原始类别数据集的完整示例。
# load and summarize the dataset
from pandas import read_csv
from sklearn.model_selection import train_test_split
# load the dataset
def load_dataset(filename):
# load the dataset as a pandas DataFrame
data = read_csv(filename, header=None)
# retrieve numpy array
dataset = data.values
# split into input (X) and output (y) variables
X = dataset[:, :-1]
y = dataset[:,-1]
return X, y
# load the dataset
X, y = load_dataset('pima-indians-diabetes.csv')
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# summarize
print('Train', X_train.shape, y_train.shape)
print('Test', X_test.shape, y_test.shape)
运行该示例会报告训练集和测试集的输入和输出元素的大小。
我们可以看到,我们有 514 个示例用于培训,254 个示例用于测试。
Train (514, 8) (514, 1)
Test (254, 8) (254, 1)
现在我们已经加载并准备了糖尿病数据集,我们可以探索特征选择。
数字特征选择
有两种流行的特征选择技术可用于数字输入数据和分类(类)目标变量。
它们是:
- 方差分析-f 统计量。
- 相互信息统计。
让我们依次仔细看看每一个。
方差分析 f 检验特征选择
方差分析是方差分析的首字母缩略词,是一种参数统计假设检验,用于确定两个或更多数据样本(通常是三个或更多)的平均值是否来自同一分布。
一个 F 统计,或 f 检验,是一类统计检验,计算方差值之间的比率,如两个不同样本的方差或通过统计检验解释和解释的方差,如方差分析。方差分析方法是一种 f 统计,这里称为方差分析 f 检验。
重要的是,当一个变量是数字的,一个是分类的,如数字输入变量和分类任务中的分类目标变量时,使用方差分析。
该测试的结果可用于特征选择,其中那些独立于目标变量的特征可从数据集中移除。
当结果是数字的,并且[…]预测因子有两个以上的水平时,可以计算传统的方差分析 f 统计量。
—第 242 页,特征工程与选择,2019。
Sklearn 机器库提供了 f_classif()函数中方差分析 f-检验的实现。该功能可用于特征选择策略,例如通过选择最相关的特征(最大值)选择最相关的 k 类。
例如,我们可以定义 SelectKBest 类来使用 f_classif() 功能并选择所有特征,然后转换列车和测试集。
...
# configure to select all features
fs = SelectKBest(score_func=f_classif, k='all')
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
然后,我们可以打印每个变量的分数(越大越好),并将每个变量的分数绘制成条形图,以了解我们应该选择多少特征。
...
# what are scores for the features
for i in range(len(fs.scores_)):
print('Feature %d: %f' % (i, fs.scores_[i]))
# plot the scores
pyplot.bar([i for i in range(len(fs.scores_))], fs.scores_)
pyplot.show()
将此与上一节中糖尿病数据集的数据准备结合起来,下面列出了完整的示例。
# example of anova f-test feature selection for numerical data
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif
from matplotlib import pyplot
# load the dataset
def load_dataset(filename):
# load the dataset as a pandas DataFrame
data = read_csv(filename, header=None)
# retrieve numpy array
dataset = data.values
# split into input (X) and output (y) variables
X = dataset[:, :-1]
y = dataset[:,-1]
return X, y
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select all features
fs = SelectKBest(score_func=f_classif, k='all')
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
# load the dataset
X, y = load_dataset('pima-indians-diabetes.csv')
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# feature selection
X_train_fs, X_test_fs, fs = select_features(X_train, y_train, X_test)
# what are scores for the features
for i in range(len(fs.scores_)):
print('Feature %d: %f' % (i, fs.scores_[i]))
# plot the scores
pyplot.bar([i for i in range(len(fs.scores_))], fs.scores_)
pyplot.show()
运行该示例首先打印为每个输入要素和目标变量计算的分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到一些特性可能比其他特性更相关,具有更大的测试统计值。
也许特性 1、5 和 7 最相关。
Feature 0: 16.527385
Feature 1: 131.325562
Feature 2: 0.042371
Feature 3: 1.415216
Feature 4: 12.778966
Feature 5: 49.209523
Feature 6: 13.377142
Feature 7: 25.126440
创建每个输入要素的要素重要性得分的条形图。
这清楚地表明,特征 1 可能是最相关的(根据测试),八个输入特征中可能有六个更相关。
我们可以在配置选择测试时设置 k=6 来选择这四个最重要的特性。
输入特征条形图(x)与方差分析 f 检验特征重要性(y)
互信息特征选择
信息论领域的互信息是信息增益(通常用于构造决策树)在特征选择中的应用。
计算两个变量之间的互信息,并在已知另一个变量的值的情况下,测量一个变量不确定性的减少。
您可以在下面的教程中了解更多关于相互信息的信息。
当考虑两个离散(分类或序数)变量的分布时,如分类输入和分类输出数据,互信息是直接的。然而,它可以适用于数字输入和分类输出。
有关如何实现这一点的技术细节,请参见 2014 年发表的题为“离散数据集和连续数据集之间的相互信息”的论文
Sklearn 机器学习库通过 mutual_info_classif() 函数,为特征选择提供了数字输入和分类输出变量的互信息实现。
和 f_classif() 一样,可以在 SelectKBest 特征选择策略(和其他策略)中使用。
...
# configure to select all features
fs = SelectKBest(score_func=mutual_info_classif, k='all')
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
我们可以使用糖尿病数据集的互信息进行特征选择,并打印和绘制分数(越大越好),就像我们在上一节中所做的那样。
下面列出了使用互信息进行数字特征选择的完整示例。
# example of mutual information feature selection for numerical input data
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_classif
from matplotlib import pyplot
# load the dataset
def load_dataset(filename):
# load the dataset as a pandas DataFrame
data = read_csv(filename, header=None)
# retrieve numpy array
dataset = data.values
# split into input (X) and output (y) variables
X = dataset[:, :-1]
y = dataset[:,-1]
return X, y
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select all features
fs = SelectKBest(score_func=mutual_info_classif, k='all')
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
# load the dataset
X, y = load_dataset('pima-indians-diabetes.csv')
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# feature selection
X_train_fs, X_test_fs, fs = select_features(X_train, y_train, X_test)
# what are scores for the features
for i in range(len(fs.scores_)):
print('Feature %d: %f' % (i, fs.scores_[i]))
# plot the scores
pyplot.bar([i for i in range(len(fs.scores_))], fs.scores_)
pyplot.show()
运行该示例首先打印为每个输入要素和目标变量计算的分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到一些功能的得分较低,这表明它们可能可以被删除。
也许特性 1 和 5 最相关。
Feature 1: 0.118431
Feature 2: 0.019966
Feature 3: 0.041791
Feature 4: 0.019858
Feature 5: 0.084719
Feature 6: 0.018079
Feature 7: 0.033098
创建每个输入要素的要素重要性得分的条形图。
重要的是,促进了不同功能的混合。
输入特征条形图(x)与互信息特征重要性条形图(y)
既然我们知道了如何对分类预测建模问题的数值输入数据执行特征选择,我们可以尝试使用所选特征开发模型并比较结果。
使用选定特征建模
有许多不同的技术用于对特征进行评分和基于评分选择特征;你怎么知道用哪个?
一种稳健的方法是使用不同的特征选择方法(和特征数量)来评估模型,并选择产生具有最佳表现的模型的方法。
在本节中,我们将评估一个逻辑回归模型,将所有特征与通过方差分析 f 检验选择的特征和通过互信息选择的特征构建的模型进行比较。
逻辑回归是测试特征选择方法的一个很好的模型,因为如果从模型中去除不相关的特征,它可以表现得更好。
使用所有功能构建的模型
作为第一步,我们将使用所有可用的特性来评估一个物流配送模型。
该模型适合训练数据集,并在测试数据集上进行评估。
下面列出了完整的示例。
# evaluation of a model using all input features
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# load the dataset
def load_dataset(filename):
# load the dataset as a pandas DataFrame
data = read_csv(filename, header=None)
# retrieve numpy array
dataset = data.values
# split into input (X) and output (y) variables
X = dataset[:, :-1]
y = dataset[:,-1]
return X, y
# load the dataset
X, y = load_dataset('pima-indians-diabetes.csv')
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# fit the model
model = LogisticRegression(solver='liblinear')
model.fit(X_train, y_train)
# evaluate the model
yhat = model.predict(X_test)
# evaluate predictions
accuracy = accuracy_score(y_test, yhat)
print('Accuracy: %.2f' % (accuracy*100))
运行该示例将打印训练数据集中模型的准确性。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到该模型实现了大约 77%的分类准确率。
我们更喜欢使用达到与此相同或更好的分类准确率的特征子集。
Accuracy: 77.56
使用方差分析 f 检验特征建立的模型
我们可以使用方差分析 f-检验对特征进行评分,并选择四个最相关的特征。
为此,更新了下面的 select_features()函数。
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select a subset of features
fs = SelectKBest(score_func=f_classif, k=4)
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
下面列出了使用此特征选择方法评估逻辑回归模型拟合和评估数据的完整示例。
# evaluation of a model using 4 features chosen with anova f-test
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# load the dataset
def load_dataset(filename):
# load the dataset as a pandas DataFrame
data = read_csv(filename, header=None)
# retrieve numpy array
dataset = data.values
# split into input (X) and output (y) variables
X = dataset[:, :-1]
y = dataset[:,-1]
return X, y
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select a subset of features
fs = SelectKBest(score_func=f_classif, k=4)
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
# load the dataset
X, y = load_dataset('pima-indians-diabetes.csv')
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# feature selection
X_train_fs, X_test_fs, fs = select_features(X_train, y_train, X_test)
# fit the model
model = LogisticRegression(solver='liblinear')
model.fit(X_train_fs, y_train)
# evaluate the model
yhat = model.predict(X_test_fs)
# evaluate predictions
accuracy = accuracy_score(y_test, yhat)
print('Accuracy: %.2f' % (accuracy*100))
运行该示例报告了模型在使用方差分析 f-检验统计选择的八个输入特征中的四个特征上的表现。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们看到模型达到了大约 78.74%的准确率,与达到 77.56%的基线相比,表现有所提升。
Accuracy: 78.74
利用互信息特征建立的模型
我们可以重复实验,并使用互信息统计选择前四个特征。
下面列出了实现此功能的 select_features() 功能的更新版本。
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select a subset of features
fs = SelectKBest(score_func=mutual_info_classif, k=4)
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
下面列出了使用互信息进行特征选择以拟合逻辑回归模型的完整示例。
# evaluation of a model using 4 features chosen with mutual information
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_classif
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# load the dataset
def load_dataset(filename):
# load the dataset as a pandas DataFrame
data = read_csv(filename, header=None)
# retrieve numpy array
dataset = data.values
# split into input (X) and output (y) variables
X = dataset[:, :-1]
y = dataset[:,-1]
return X, y
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select a subset of features
fs = SelectKBest(score_func=mutual_info_classif, k=4)
# learn relationship from training data
fs.fit(X_train, y_train)
# transform train input data
X_train_fs = fs.transform(X_train)
# transform test input data
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
# load the dataset
X, y = load_dataset('pima-indians-diabetes.csv')
# split into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
# feature selection
X_train_fs, X_test_fs, fs = select_features(X_train, y_train, X_test)
# fit the model
model = LogisticRegression(solver='liblinear')
model.fit(X_train_fs, y_train)
# evaluate the model
yhat = model.predict(X_test_fs)
# evaluate predictions
accuracy = accuracy_score(y_test, yhat)
print('Accuracy: %.2f' % (accuracy*100))
运行该示例使模型适合使用互信息选择的四个顶级选定要素。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,与基线模型相比,我们没有什么不同。这很有趣,因为我们知道该方法与之前的方法相比选择了不同的四个特征。
Accuracy: 77.56
调整选定特征的数量
在前面的例子中,我们选择了四个特征,但是我们如何知道选择哪个特征是好的或者最好的数量呢?
代替猜测,我们可以系统地测试一系列不同数量的所选特征,并发现哪一个导致最佳表现的模型。这被称为网格搜索,其中可以调整 SelectKBest 类的 k 参数。
使用重复分层 K 折交叉验证来评估分类任务的模型配置是一种良好的做法。我们将通过repeated stratifiedfold 类使用三次重复的 10 倍交叉验证。
...
# define the evaluation method
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
我们可以定义一个管道,它可以在训练集上正确准备特征选择变换,并将其应用于交叉验证的每个折叠的训练集和测试集。
在这种情况下,我们将使用方差分析 f-检验统计方法来选择特征。
...
# define the pipeline to evaluate
model = LogisticRegression(solver='liblinear')
fs = SelectKBest(score_func=f_classif)
pipeline = Pipeline(steps=[('anova',fs), ('lr', model)])
然后,我们可以将评估值的网格定义为 1 到 8。
请注意,网格是一个参数到要搜索的值的字典,假设我们使用的是一个管道,我们可以通过我们给它起的名字来访问 SelectKBest 对象,' anova ',然后是参数名' k ',用两个下划线分隔,或' anova__k '。
...
# define the grid
grid = dict()
grid['anova__k'] = [i+1 for i in range(X.shape[1])]
然后,我们可以定义并运行搜索。
...
# define the grid search
search = GridSearchCV(pipeline, grid, scoring='accuracy', n_jobs=-1, cv=cv)
# perform the search
results = search.fit(X, y)
将这些联系在一起,完整的示例如下所示。
# compare different numbers of features selected using anova f-test
from pandas import read_csv
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
from matplotlib import pyplot
# load the dataset
def load_dataset(filename):
# load the dataset as a pandas DataFrame
data = read_csv(filename, header=None)
# retrieve numpy array
dataset = data.values
# split into input (X) and output (y) variables
X = dataset[:, :-1]
y = dataset[:,-1]
return X, y
# define dataset
X, y = load_dataset('pima-indians-diabetes.csv')
# define the evaluation method
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# define the pipeline to evaluate
model = LogisticRegression(solver='liblinear')
fs = SelectKBest(score_func=f_classif)
pipeline = Pipeline(steps=[('anova',fs), ('lr', model)])
# define the grid
grid = dict()
grid['anova__k'] = [i+1 for i in range(X.shape[1])]
# define the grid search
search = GridSearchCV(pipeline, grid, scoring='accuracy', n_jobs=-1, cv=cv)
# perform the search
results = search.fit(X, y)
# summarize best
print('Best Mean Accuracy: %.3f' % results.best_score_)
print('Best Config: %s' % results.best_params_)
运行示例网格使用 ANOVA f-test 搜索不同数量的选定要素,其中使用重复交叉验证评估每个建模管道。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到所选特征的最佳数量是七个;达到了 77%的准确率。
Best Mean Accuracy: 0.770
Best Config: {'anova__k': 7}
我们可能希望看到所选特征的数量和分类准确率之间的关系。在这种关系中,我们可能期望更多的特性在某种程度上导致更好的表现。
这种关系可以通过从 1 到 8 手动评估选择测试的 k 的每个配置,收集准确度分数的样本,并使用方框图和触须图并排绘制结果来探索。这些箱线图的分布和平均值预计将显示所选要素的数量和管道分类准确率之间的任何有趣关系。
下面列出了实现这一点的完整示例。
# compare different numbers of features selected using anova f-test
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# load the dataset
def load_dataset(filename):
# load the dataset as a pandas DataFrame
data = read_csv(filename, header=None)
# retrieve numpy array
dataset = data.values
# split into input (X) and output (y) variables
X = dataset[:, :-1]
y = dataset[:,-1]
return X, y
# evaluate a give model using cross-validation
def evaluate_model(model, X, y):
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
return scores
# define dataset
X, y = load_dataset('pima-indians-diabetes.csv')
# define number of features to evaluate
num_features = [i+1 for i in range(X.shape[1])]
# enumerate each number of features
results = list()
for k in num_features:
# create pipeline
model = LogisticRegression(solver='liblinear')
fs = SelectKBest(score_func=f_classif, k=k)
pipeline = Pipeline(steps=[('anova',fs), ('lr', model)])
# evaluate the model
scores = evaluate_model(pipeline, X, y)
results.append(scores)
# summarize the results
print('>%d %.3f (%.3f)' % (k, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=num_features, showmeans=True)
pyplot.show()
运行该示例首先报告每个选定特征数量的平均值和标准偏差准确率。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,选择五个和七个要素的准确度大致相同。
>1 0.748 (0.048)
>2 0.756 (0.042)
>3 0.761 (0.044)
>4 0.759 (0.042)
>5 0.770 (0.041)
>6 0.766 (0.042)
>7 0.770 (0.042)
>8 0.768 (0.040)
并排创建方框图和触须图,显示平均准确率随着所选要素的数量增加到五个要素而增加的趋势,之后可能会变得不太稳定。
在这种情况下,选择五个功能可能是合适的配置。
使用方差分析 f-检验对每个选定特征数的分类准确度的方框图和须图
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
教程
书
- 特征工程与选择,2019。
报纸
- 离散和连续数据集之间的互信息,2014。
蜜蜂
- 功能选择,sci kit-学习用户指南。
- 硬化. feature _ selection . f _ classic API。
- sklearn . feature _ selection . mutual _ info _ class if API。
- 硬化. feature_selection。SelectKBest API 。
文章
资料组
摘要
在本教程中,您发现了如何使用用于分类的数字输入数据执行要素选择。
具体来说,您了解到:
- 具有数值输入和二分类目标变量的糖尿病预测建模问题。
- 如何使用方差分析 f-检验和互信息统计评估数字特征的重要性。
- 在拟合和评估分类模型时,如何对数值数据进行特征选择。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
如何选择机器学习的特征选择方法
最后更新于 2020 年 8 月 20 日
特征选择是开发预测模型时减少输入变量数量的过程。
希望减少输入变量的数量,以降低建模的计算成本,并在某些情况下提高模型的表现。
基于统计的特征选择方法包括使用统计评估每个输入变量和目标变量之间的关系,并选择那些与目标变量具有最强关系的输入变量。这些方法可以快速有效,尽管统计方法的选择取决于输入和输出变量的数据类型。
因此,对于机器学习从业者来说,在执行基于过滤器的特征选择时,为数据集选择适当的统计度量是具有挑战性的。
在这篇文章中,您将发现如何使用数字和类别数据为基于过滤器的特征选择选择统计度量。
看完这篇文章,你会知道:
- 特征选择技术主要有两种类型:有监督和无监督,有监督的方法可以分为包装器、过滤器和内在的。
- 基于过滤器的特征选择方法使用统计测量来对输入变量之间的相关性或依赖性进行评分,这些输入变量可以被过滤以选择最相关的特征。
- 必须根据输入变量和输出或响应变量的数据类型仔细选择特征选择的统计度量。
用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
- 2019 年 11 月更新:增加了一些分类回归的工作示例。
- 2020 年 5 月更新:扩展增加参考文献。添加了图片。
如何开发乳腺癌患者存活概率模型 图片由 Tanja-Milfoil 提供,保留部分权利。
概观
本教程分为 4 个部分;它们是:
- 特征选择方法
- 过滤器特征选择方法的统计信息
- 数字输入,数字输出
- 数字输入,分类输出
- 分类输入,数字输出
- 分类输入,分类输出
- 功能选择的提示和技巧
- 相关统计
- 选择方法
- 转换变量
- 什么是最好的方法?
- 工作示例
- 回归特征选择
- 分类特征选择
1.特征选择方法
特征选择方法旨在将输入变量的数量减少到被认为对模型最有用的数量,以便预测目标变量。
特征选择主要集中于从模型中去除无信息或冗余的预测因子。
—第 488 页,应用预测建模,2013 年。
一些预测建模问题具有大量的变量,这会减慢模型的开发和训练,并且需要大量的系统内存。此外,当包含与目标变量无关的输入变量时,某些模型的表现可能会下降。
许多模型,尤其是那些基于回归斜率和截距的模型,将为模型中的每个项估计参数。因此,非信息变量的存在会增加预测的不确定性,降低模型的整体有效性。
—第 488 页,应用预测建模,2013 年。
思考特征选择方法的一种方式是根据有监督的和无监督的方法。
特征选择的一个重要区别是有监督和无监督的方法。当在排除预测因子的过程中忽略结果时,该技术是无监督的。
—第 488 页,应用预测建模,2013 年。
区别在于是否基于目标变量选择特征。无监督特征选择技术忽略目标变量,例如使用相关性去除冗余变量的方法。监督特征选择技术使用目标变量,例如去除无关变量的方法..
考虑用于选择特征的机制的另一种方式可以分为包装和过滤方法。这些方法几乎总是受监督的,并且是基于结果模型在等待数据集上的表现来评估的。
包装器特征选择方法创建许多具有不同输入特征子集的模型,并根据表现度量选择那些导致最佳表现模型的特征。这些方法与变量类型无关,尽管它们在计算上很昂贵。 RFE 是包装器特征选择方法的一个很好的例子。
包装器方法使用添加和/或移除预测器的过程来评估多个模型,以找到最大化模型表现的最佳组合。
—第 490 页,应用预测建模,2013 年。
过滤器特征选择方法使用统计技术来评估每个输入变量和目标变量之间的关系,并且这些分数被用作选择(过滤)将在模型中使用的那些输入变量的基础。
过滤方法评估预测模型之外的预测因子的相关性,随后只对通过某些标准的预测因子建模。
—第 490 页,应用预测建模,2013 年。
最后,有一些机器学习算法自动执行特征选择,作为学习模型的一部分。我们可以将这些技术称为内在特征选择方法。
……有些模型包含内置的特征选择,这意味着模型将只包含有助于最大限度提高准确率的预测器。在这些情况下,模型可以挑选数据的最佳表示。
—第 28 页,应用预测建模,2013 年。
这包括像套索和决策树这样的惩罚回归模型的算法,包括像随机森林这样的决策树的集合。
一些模型对非信息预测因子有天然的抵抗力。基于树和规则的模型,例如 MARS 和套索,本质上进行特征选择。
—第 487 页,应用预测建模,2013 年。
特征选择也与降维技术相关,因为这两种方法都为预测模型寻找较少的输入变量。不同之处在于,特征选择选择要保留或从数据集中移除的特征,而降维创建数据的投影,从而产生全新的输入特征。因此,降维是特征选择的替代,而不是一种特征选择。
我们可以将特征选择总结如下。
- 特征选择:从数据集中选择输入特征的子集。
- 无监督:不要使用目标变量(如去掉冗余变量)。
- 相互关系
- 有监督的:使用目标变量(如去掉无关变量)。
- 包装器:搜索表现良好的特征子集。
- RFE
- 过滤:根据特征与目标的关系选择特征子集。
- 统计方法
- 特征重要性方法
- 内在:在训练过程中执行自动特征选择的算法。
- 决策树
- 包装器:搜索表现良好的特征子集。
- 无监督:不要使用目标变量(如去掉冗余变量)。
- 降维:将输入数据投影到低维特征空间。
下图提供了这种层次特征选择技术的概要。
特征选择技术综述
在下一节中,我们将回顾一些统计度量,这些度量可用于不同输入和输出变量数据类型的基于过滤器的特征选择。
2.基于过滤器的特征选择方法的统计
通常使用输入和输出变量之间的相关性类型统计度量作为过滤器特征选择的基础。
因此,统计测量的选择高度依赖于可变数据类型。
常见的数据类型包括数值型(如高度)和分类型(如标签),尽管每种类型都可以进一步细分,如数值变量的整数和浮点型,分类变量的布尔型、序数型或标称型。
常见的输入变量数据类型:
- 数值变量
- 整数变量。
- 浮点变量。
- 分类变量。
- 布尔变量(二分)。
- 序数变量。
- 名义变量。
数据变量类型概述
对变量的数据类型了解越多,就越容易为基于过滤器的特征选择方法选择合适的统计度量。
在本节中,我们将考虑两大类变量类型:数值型和分类型;还有,要考虑的两组主要变量:投入和产出。
输入变量是作为模型输入提供的变量。在特征选择中,我们希望减少的是这组变量。输出变量是模型要预测的变量,通常称为响应变量。
响应变量的类型通常指示正在执行的预测建模问题的类型。例如,数字输出变量表示回归预测建模问题,分类输出变量表示分类预测建模问题。
- 数值输出:回归预测建模问题。
- 分类输出:分类预测建模问题。
基于过滤器的特征选择中使用的统计度量通常是一次用目标变量计算一个输入变量。因此,它们被称为单变量统计测量。这可能意味着在过滤过程中不考虑输入变量之间的任何交互。
这些技术中的大多数都是单变量的,这意味着它们单独评估每个预测因子。在这种情况下,相关预测因子的存在使得选择重要但冗余的预测因子成为可能。这个问题的明显后果是选择了太多的预测因子,结果出现了共线性问题。
—第 499 页,应用预测建模,2013 年。
有了这个框架,让我们回顾一些可以用于基于过滤器的特征选择的单变量统计度量。
如何选择机器学习的特征选择方法
数字输入,数字输出
这是一个带有数值输入变量的回归预测建模问题。
最常见的技术是使用相关系数,例如线性相关使用皮尔逊系数,非线性相关使用基于秩的方法。
- 皮尔逊相关系数(线性)。
- 斯皮尔曼秩系数(非线性)
数字输入,分类输出
这是一个带有数值输入变量的分类预测建模问题。
这可能是分类问题最常见的例子,
同样,最常见的技术是基于相关性的,尽管在这种情况下,它们必须考虑分类目标。
- 方差分析相关系数(线性)。
- 肯德尔秩系数(非线性)。
肯德尔确实假设分类变量是序数。
分类输入,数字输出
这是一个带有分类输入变量的回归预测建模问题。
这是一个回归问题的奇怪例子(例如,你不会经常遇到它)。
尽管如此,您可以使用相同的“数值输入,分类输出”方法(如上所述),但方向相反。
分类输入,分类输出
这是一个带有分类输入变量的分类预测建模问题。
类别数据最常见的相关测量是卡方检验。也可以用信息论领域的互信息(信息增益)。
- 卡方检验(列联表)。
- 相互信息。
事实上,互信息是一种强大的方法,可能对分类和数字数据都有用,例如,它对数据类型是不可知的。
3.功能选择的提示和技巧
本节提供了使用基于过滤器的功能选择时的一些附加注意事项。
相关统计
Sklearn 库提供了大多数有用的统计方法的实现。
例如:
- 皮尔逊相关系数:f _ 回归()
- 注释:f _ classic()
- 卡方: chi2()
- 相互信息:相互信息类()和相互信息回归()
此外,SciPy 库还提供了更多统计信息的实现,例如肯德尔τ(肯德尔τ)和斯皮尔曼等级相关性(斯皮尔曼)。
选择方法
一旦为目标的每个输入变量计算了统计数据,Sklearn 库还提供了许多不同的过滤方法。
两种比较流行的方法包括:
我自己经常使用 SelectKBest 。
转换变量
考虑转换变量,以便访问不同的统计方法。
例如,您可以将一个分类变量转换为序数,即使它不是,并看看是否有任何有趣的结果出来。
您也可以将数值变量离散化(例如,箱);尝试基于分类的测量。
一些统计测量假设变量的属性,例如皮尔逊假设观测值的高斯概率分布和线性关系。您可以转换数据以满足测试的期望,并尝试测试而不考虑期望并比较结果。
什么是最好的方法?
没有最佳的特征选择方法。
就像没有最好的输入变量集或最好的机器学习算法一样。至少不是普遍的。
相反,你必须通过仔细系统的实验来发现什么最适合你的具体问题。
尝试一系列不同的模型,适合通过不同的统计方法选择的不同特征子集,并发现什么最适合您的特定问题。
4.功能选择的工作示例
有一些可以复制粘贴并适合自己项目的工作示例可能会很有帮助。
本节提供了可用作起点的功能选择案例的工作示例。
回归特征选择:
( 数值输入,数值输出
本节演示了作为数字输入和数字输出的回归问题的特征选择。
使用make _ revolution()函数准备一个测试回归问题。
# pearson's correlation feature selection for numeric input and numeric output
from sklearn.datasets import make_regression
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_regression
# generate dataset
X, y = make_regression(n_samples=100, n_features=100, n_informative=10)
# define feature selection
fs = SelectKBest(score_func=f_regression, k=10)
# apply feature selection
X_selected = fs.fit_transform(X, y)
print(X_selected.shape)
运行该示例首先创建回归数据集,然后定义要素选择并将要素选择过程应用于数据集,返回所选输入要素的子集。
(100, 10)
分类特征选择:
( 数值输入,分类输出
本节演示了作为数字输入和分类输出的分类问题的特征选择。
使用 make_classification() 函数准备一个测试回归问题。
通过 f_classif() 功能,使用方差分析 F 测量进行特征选择。
# ANOVA feature selection for numeric input and categorical output
from sklearn.datasets import make_classification
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif
# generate dataset
X, y = make_classification(n_samples=100, n_features=20, n_informative=2)
# define feature selection
fs = SelectKBest(score_func=f_classif, k=2)
# apply feature selection
X_selected = fs.fit_transform(X, y)
print(X_selected.shape)
运行该示例首先创建类别数据集,然后定义要素选择并将要素选择过程应用于数据集,返回所选输入要素的子集。
(100, 2)
分类特征选择:
( 分类输入,分类输出
有关分类输入和分类输出的特征选择示例,请参见教程:
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
教程
书
文章
摘要
在这篇文章中,您发现了如何使用数字和类别数据为基于过滤器的特征选择选择统计度量。
具体来说,您了解到:
- 特征选择技术主要有两种类型:有监督和无监督,有监督的方法可以分为包装器、过滤器和内在的。
- 基于过滤器的特征选择方法使用统计测量来对输入变量之间的相关性或依赖性进行评分,这些输入变量可以被过滤以选择最相关的特征。
- 必须根据输入变量和输出或响应变量的数据类型仔细选择特征选择的统计度量。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
机器学习中数据准备技术的框架
最后更新于 2020 年 7 月 17 日
有大量不同类型的数据准备技术可用于预测建模项目。
在某些情况下,数据的分布或机器学习模型的要求可能暗示了所需的数据准备,尽管考虑到数据的复杂性和高维性、不断增加的新机器学习算法以及从业者有限的(尽管是人为的)限制,这种情况很少发生。
相反,数据准备可以被视为另一个超参数,作为建模管道的一部分进行调整。这就提出了一个问题,如何知道在搜索中要考虑哪些数据准备方法,这可能会让专家和初学者都感到不知所措。
解决方案是以结构化的方式思考数据准备的广阔领域,并根据数据准备技术对原始数据的影响系统地评估数据准备技术。
在本教程中,您将发现一个框架,该框架为使用结构化数据进行预测建模的数据准备技术的思考和分组提供了一种结构化的方法。
完成本教程后,您将知道:
- 框架数据准备的挑战和压倒性进展是机器学习建模管道中另一个需要调整的超参数。
- 定义了五组要考虑的数据准备技术的框架。
- 属于每个组的数据准备技术的示例,可以在您的预测建模项目中进行评估。
用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
机器学习中的数据准备技术框架 图片由菲尔杜比提供,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 数据准备的挑战
- 数据准备框架
- 数据准备技术
数据准备的挑战
数据准备是指将原始数据转换成更适合预测建模的形式。
这可能是必需的,因为数据本身包含错误。这也可能是因为所选择的算法对数据的类型和分布有所期望。
为了使数据准备的任务更具挑战性,从预测模型中获得最佳表现所需的数据准备可能并不明显,并且可能会偏离或违反正在使用的模型的预期,这也是很常见的。
因此,通常将应用于原始数据的数据准备的选择和配置视为要调整的建模管道的另一个超参数。
这种数据准备框架在实践中非常有效,因为它允许您使用自动搜索技术(如网格搜索和随机搜索)来发现非直观的数据准备步骤,从而产生熟练的预测模型。
鉴于数据准备技术的数量和种类繁多,这种数据准备框架对初学者来说也是势不可挡的。
解决这个问题的办法是系统地思考数据准备技术。
数据准备框架
有效的数据准备要求以结构化和系统的方式组织和考虑可用的数据准备技术。
这允许您确保为数据集探索方法技术,并且不会跳过或忽略潜在的有效技术。
这可以通过使用一个框架来组织数据准备技术来实现,这些技术考虑了它们对原始数据集的影响。
例如,结构化的机器学习数据,例如我们可能存储在 CSV 文件中用于分类和回归的数据,由行、列和值组成。我们可以考虑在这些级别上运行的数据准备技术。
- 行的数据准备
- 列的数据准备
- 价值观的数据准备
行的数据准备可以是从数据集中添加或移除数据行的技术。类似地,列的数据准备可以是从数据集中添加或移除列(要素或变量)的技术。而值的数据准备可能是改变数据集中的值的技术,通常是针对给定的列。
还有一种类型的数据准备不适合这种结构,那就是降维技术。这些技术同时改变列和值,例如,将数据投影到低维空间。
- 列+值的数据准备
这就提出了可能同时应用于行和值的技术问题。这可能包括以某种方式合并数据行的数据准备。
- 行+值的数据准备
我们可以在下图中总结这个框架和一些高级别的数据准备方法。
机器学习数据准备框架
现在,我们已经有了一个基于数据对数据的影响来思考数据准备的框架,让我们来看看适合每个组的技术示例。
数据准备技术
本节探讨了前一节中定义的五组高级别数据准备技术,并提出了可能属于每组的具体技术。
我错过了你最喜欢或最喜欢的数据准备技巧之一吗? 在下面的评论里告诉我。
行的数据准备
该组用于添加或删除数据行的数据准备技术。
在机器学习中,行通常被称为样本、示例或实例。
这些技术通常用于扩充有限的训练数据集或消除数据集中的错误或歧义。
想到的主要技术类别是经常用于不平衡分类的数据准备技术。
这包括为表示不足的类创建合成训练数据行的 SMOTE 等技术,以及为表示过多的类移除示例的随机欠采样。
有关 SMOTE 数据采样的更多信息,请参见教程:
它还包括更高级的组合过采样和欠采样技术,这些技术试图沿着分类问题的决策边界识别和移除不明确的示例,并移除它们或改变它们的类标签。
有关这些类型的数据准备的更多信息,请参见教程:
这类数据准备技术还包括从数据中识别和移除异常值的算法。这些数据行可能远离数据集中的概率质量中心,因此可能不代表域中的数据。
有关异常值检测和移除方法的更多信息,请参见教程:
列的数据准备
该组用于添加或删除数据列的数据准备技术。
在机器学习中,列通常被称为变量或特征。
通常需要这些技术来降低预测问题的复杂性(维度),或者解包复合输入变量或特征之间的复杂交互。
想到的主要技术是特征选择技术。
这包括使用统计数据根据每个变量的数据类型对输入变量与目标变量的相关性进行评分的技术。
有关这些类型的数据准备技术的更多信息,请参见教程:
这也包括系统地测试输入变量的不同组合对机器学习模型的预测技能的影响的特征选择技术。
有关这些类型方法的更多信息,请参见教程:
相关的是使用模型基于预测模型对输入特征的使用来对输入特征的重要性进行评分的技术,称为特征重要性方法。这些方法通常用于数据解释,尽管它们也可以用于特征选择。
有关这些类型方法的更多信息,请参见教程:
这组方法还带来了创建或导出新的数据列和新特性的技术。这些通常被称为特征工程,尽管有时整个数据准备领域被称为特征工程。
例如,可以创建表示提升到指数的值的新要素或要素的乘法组合,并将其作为新列添加到数据集中。
有关这些类型的数据准备技术的更多信息,请参见教程:
这可能还包括改变变量类型的数据转换,例如为分类变量创建虚拟变量,通常称为一次性编码。
有关这些类型的数据准备技术的更多信息,请参见教程:
价值观的数据准备
该组用于改变数据中原始值的数据准备技术。
这些技术通常需要满足特定机器学习算法的期望或要求。
想到的主要技术类别是改变输入变量的规模或分布的数据转换。
例如标准化、归一化等数据变换,改变数值输入变量的尺度。像序数编码这样的数据转换改变了分类输入变量的类型。
还有许多用于改变输入变量分布的数据转换。
例如,离散化或宁滨将数字输入变量的分布改变为具有序数排序的分类变量。
有关此类数据转换的更多信息,请参见教程:
功率变换可用于改变数据的分布,以消除偏斜,并使分布更加正态(高斯)。
有关此方法的更多信息,请参见教程:
分位数转换是一种灵活的数据准备技术,可以将数字输入变量映射到不同类型的分布,如正态分布或高斯分布。
您可以在此处了解有关这种数据准备技术的更多信息:
属于这一组的另一种数据准备技术是系统地改变数据集中的值的方法。
这包括识别和替换缺失值的技术,通常称为缺失值插补。这可以使用统计方法或更先进的基于模型的方法来实现。
有关这些方法的更多信息,请参见教程:
如果转换的结果作为新的列被附加到原始数据,则所讨论的所有方法也可以被认为是特征工程方法(例如,适合于之前讨论的数据准备方法组)。
列+值的数据准备
该组用于更改数据中的列数和值的数据准备技术。
这让我想到的主要技术类别是降维技术,它专门减少列的数量以及数字输入变量的规模和分布。
这包括线性代数中使用的矩阵分解方法以及高维统计中使用的流形学习算法。
有关这些技术的更多信息,请参见教程:
虽然这些技术是为了在低维空间中创建行的投影而设计的,但这可能也为反过来的技术打开了大门。也就是说,使用输入变量的全部或一个子集来创建到更高维空间的投影,可能会分解复杂的非线性关系。
也许用多项式变换代替原始数据集的结果适合这类数据准备方法。
你知道适合这个群体的其他方法吗? 在下面的评论里告诉我。
行+值的数据准备
该组用于更改数据行数和值的数据准备技术。
我以前没有明确考虑过这种类型的数据转换,但是它超出了定义的框架。
想到的一组方法是聚类算法,其中数据集中的所有数据行或数据行的子集在聚类中心被替换为数据样本,称为聚类中心。
相关的可能是用取自特定机器学习算法的样本(行的集合)替换行,例如来自支持向量机的支持向量,或者来自学习向量量化的码本向量。
自然,这些聚合行只是简单地添加到数据集中,而不是替换行,然后它们自然会适合上述“行的数据准备”组。
你知道适合这个群体的其他方法吗? 在下面的评论里告诉我。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
书
摘要
在本教程中,您发现了一个框架,用于根据数据准备技术对原始数据的影响对数据准备技术进行系统分组。
具体来说,您了解到:
- 框架数据准备的挑战和压倒性进展是机器学习建模管道中另一个需要调整的超参数。
- 定义了五组要考虑的数据准备技术的框架。
- 属于每个组的数据准备技术的示例,可以在您的预测建模项目中进行评估。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
如何网格搜索数据准备技术
最后更新于 2020 年 8 月 17 日
机器学习预测建模表现只和你的数据一样好,你的数据只和你准备建模的方式一样好。
最常见的数据准备方法是研究数据集并回顾机器学习算法的期望,然后仔细选择最合适的数据准备技术来转换原始数据,以最好地满足算法的期望。这是缓慢的,昂贵的,需要大量的专业知识。
数据准备的另一种方法是对原始数据进行网格搜索,这是一套常见且常用的数据准备技术。这是数据准备的另一种理念,即将数据转换视为要搜索和调整的建模管道的另一个超参数。
与传统的手动数据准备方法相比,这种方法需要更少的专业知识,尽管计算成本很高。好处是,它可以帮助发现非直观的数据准备解决方案,这些解决方案可以为给定的预测建模问题实现良好或最佳的表现。
在本教程中,您将发现如何使用网格搜索方法来准备表格数据。
完成本教程后,您将知道:
- 网格搜索为表格数据的数据准备提供了一种替代方法,其中变换被尝试作为建模管道的超参数。
- 如何使用网格搜索方法进行数据准备,以提高标准类别数据集的模型表现。
- 如何网格搜索序列的数据准备方法,进一步提高模型表现。
用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
如何网格搜索数据准备技术 图片由墙船提供,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 用于数据准备的网格搜索技术
- 数据集和表现基线
- 葡萄酒类别数据集
- 基线模型表现
- 数据准备的网格搜索方法
用于数据准备的网格搜索技术
数据准备可能具有挑战性。
最常规定和遵循的方法是分析数据集,审查算法的要求,并转换原始数据以最好地满足算法的期望。
这可能是有效的,但也很慢,可能需要数据分析和机器学习算法方面的深厚专业知识。
另一种方法是将输入变量的准备视为建模管道的超参数,并随着算法和算法配置的选择对其进行调整。
这可能是一个数据转换,“不应该工作””或“不应该适合算法”但结果良好或伟大的表现。或者,对于被认为是“绝对必要的”的输入变量,可能缺少数据转换,但仍会产生良好或出色的表现。
*这可以通过设计数据准备技术的网格搜索和/或流水线中的数据准备技术序列来实现。这可能涉及在单个选择的机器学习算法或一套机器学习算法上评估每一个。
这种方法的好处是,它总是会产生建模管道的建议,从而给出良好的相对结果。最重要的是,它可以为从业者挖掘不明显和不直观的解决方案,而不需要深厚的专业知识。
我们可以通过一个工作示例来探索这种数据准备方法。
在深入研究一个工作示例之前,让我们首先选择一个标准数据集,并开发一个表现基线。
数据集和表现基线
在本节中,我们将首先选择一个标准的机器学习数据集,并在该数据集上建立表现基线。这将为下一节探索数据准备的网格搜索方法提供背景。
葡萄酒类别数据集
我们将使用葡萄酒类别数据集。
该数据集有 13 个输入变量,用于描述葡萄酒样品的化学成分,并要求将葡萄酒分为三种类型。
您可以在此了解有关数据集的更多信息:
不需要下载数据集,因为我们将自动下载它作为我们工作示例的一部分。
打开数据集并查看原始数据。下面列出了前几行数据。
我们可以看到,这是一个带有数值输入变量的多类分类预测建模问题,每个变量都有不同的尺度。
14.23,1.71,2.43,15.6,127,2.8,3.06,.28,2.29,5.64,1.04,3.92,1065,1
13.2,1.78,2.14,11.2,100,2.65,2.76,.26,1.28,4.38,1.05,3.4,1050,1
13.16,2.36,2.67,18.6,101,2.8,3.24,.3,2.81,5.68,1.03,3.17,1185,1
14.37,1.95,2.5,16.8,113,3.85,3.49,.24,2.18,7.8,.86,3.45,1480,1
13.24,2.59,2.87,21,118,2.8,2.69,.39,1.82,4.32,1.04,2.93,735,1
...
下面的示例加载数据集并将其拆分为输入和输出列,然后汇总数据数组。
# example of loading and summarizing the wine dataset
from pandas import read_csv
# define the location of the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/wine.csv'
# load the dataset as a data frame
df = read_csv(url, header=None)
# retrieve the numpy array
data = df.values
# split the columns into input and output variables
X, y = data[:, :-1], data[:, -1]
# summarize the shape of the loaded data
print(X.shape, y.shape)
运行该示例,我们可以看到数据集被正确加载,并且有 179 行数据,包含 13 个输入变量和一个目标变量。
(178, 13) (178,)
接下来,让我们在这个数据集上评估一个模型,并建立一个表现基线。
基线模型表现
我们可以通过评估原始输入数据的模型来建立葡萄酒分类任务的表现基线。
在这种情况下,我们将评估逻辑回归模型。
首先,我们可以定义一个函数来加载数据集,并执行一些最小的数据准备,以确保输入是数字的,目标是标签编码的。
# prepare the dataset
def load_dataset():
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/wine.csv'
df = read_csv(url, header=None)
data = df.values
X, y = data[:, :-1], data[:, -1]
# minimally prepare dataset
X = X.astype('float')
y = LabelEncoder().fit_transform(y.astype('str'))
return X, y
我们将使用重复分层 k 倍交叉验证的金标准对模型进行评估,重复 10 次,重复 3 次。
# evaluate a model
def evaluate_model(X, y, model):
# define the cross-validation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
return scores
然后,我们可以调用函数来加载数据集,定义我们的模型,然后对其进行评估,报告平均值和标准偏差准确率。
...
# get the dataset
X, y = load_dataset()
# define the model
model = LogisticRegression(solver='liblinear')
# evaluate the model
scores = evaluate_model(X, y, model)
# report performance
print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))
将这些联系在一起,下面列出了在原酒类别数据集上评估逻辑回归模型的完整示例。
# baseline model performance on the wine dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
# prepare the dataset
def load_dataset():
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/wine.csv'
df = read_csv(url, header=None)
data = df.values
X, y = data[:, :-1], data[:, -1]
# minimally prepare dataset
X = X.astype('float')
y = LabelEncoder().fit_transform(y.astype('str'))
return X, y
# evaluate a model
def evaluate_model(X, y, model):
# define the cross-validation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
return scores
# get the dataset
X, y = load_dataset()
# define the model
model = LogisticRegression(solver='liblinear')
# evaluate the model
scores = evaluate_model(X, y, model)
# report performance
print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))
运行该示例评估模型表现,并报告平均和标准偏差分类准确率。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到,适合原始输入数据的逻辑回归模型实现了大约 95.3%的平均分类准确率,提供了表现基线。
Accuracy: 0.953 (0.048)
接下来,让我们探索是否可以使用基于网格搜索的数据准备方法来提高表现。
数据准备的网格搜索方法
在本节中,我们可以探索是否可以使用网格搜索方法来提高数据准备的表现。
第一步是定义一系列要评估的建模管道,其中每个管道定义一种(或多种)数据准备技术,并以将转换后的数据作为输入的模型结束。
我们将定义一个函数,将这些管道创建为元组列表,其中每个元组定义管道和管道本身的简称。我们将评估一系列不同的数据缩放方法(例如最小最大缩放器和标准缩放器)、分布变换(量化变换器和kbins 离散化器)以及降维变换( PCA 和 SVD )。
# get modeling pipelines to evaluate
def get_pipelines(model):
pipelines = list()
# normalize
p = Pipeline([('s',MinMaxScaler()), ('m',model)])
pipelines.append(('norm', p))
# standardize
p = Pipeline([('s',StandardScaler()), ('m',model)])
pipelines.append(('std', p))
# quantile
p = Pipeline([('s',QuantileTransformer(n_quantiles=100, output_distribution='normal')), ('m',model)])
pipelines.append(('quan', p))
# discretize
p = Pipeline([('s',KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')), ('m',model)])
pipelines.append(('kbins', p))
# pca
p = Pipeline([('s',PCA(n_components=7)), ('m',model)])
pipelines.append(('pca', p))
# svd
p = Pipeline([('s',TruncatedSVD(n_components=7)), ('m',model)])
pipelines.append(('svd', p))
return pipelines
然后,我们可以调用这个函数来获取转换列表,然后枚举每个转换,对其进行评估并报告一路上的表现。
...
# get the modeling pipelines
pipelines = get_pipelines(model)
# evaluate each pipeline
results, names = list(), list()
for name, pipeline in pipelines:
# evaluate
scores = evaluate_model(X, y, pipeline)
# summarize
print('>%s: %.3f (%.3f)' % (name, mean(scores), std(scores)))
# store
results.append(scores)
names.append(name)
在运行结束时,我们可以为每组分数创建一个方框和触须图,并直观地比较结果的分布。
...
# plot the result
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()
将这些联系在一起,下面列出了葡萄酒类别数据集中网格搜索数据准备技术的完整示例。
# compare data preparation methods for the wine classification dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import QuantileTransformer
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.decomposition import PCA
from sklearn.decomposition import TruncatedSVD
from matplotlib import pyplot
# prepare the dataset
def load_dataset():
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/wine.csv'
df = read_csv(url, header=None)
data = df.values
X, y = data[:, :-1], data[:, -1]
# minimally prepare dataset
X = X.astype('float')
y = LabelEncoder().fit_transform(y.astype('str'))
return X, y
# evaluate a model
def evaluate_model(X, y, model):
# define the cross-validation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
return scores
# get modeling pipelines to evaluate
def get_pipelines(model):
pipelines = list()
# normalize
p = Pipeline([('s',MinMaxScaler()), ('m',model)])
pipelines.append(('norm', p))
# standardize
p = Pipeline([('s',StandardScaler()), ('m',model)])
pipelines.append(('std', p))
# quantile
p = Pipeline([('s',QuantileTransformer(n_quantiles=100, output_distribution='normal')), ('m',model)])
pipelines.append(('quan', p))
# discretize
p = Pipeline([('s',KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')), ('m',model)])
pipelines.append(('kbins', p))
# pca
p = Pipeline([('s',PCA(n_components=7)), ('m',model)])
pipelines.append(('pca', p))
# svd
p = Pipeline([('s',TruncatedSVD(n_components=7)), ('m',model)])
pipelines.append(('svd', p))
return pipelines
# get the dataset
X, y = load_dataset()
# define the model
model = LogisticRegression(solver='liblinear')
# get the modeling pipelines
pipelines = get_pipelines(model)
# evaluate each pipeline
results, names = list(), list()
for name, pipeline in pipelines:
# evaluate
scores = evaluate_model(X, y, pipeline)
# summarize
print('>%s: %.3f (%.3f)' % (name, mean(scores), std(scores)))
# store
results.append(scores)
names.append(name)
# plot the result
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()
运行该示例会评估每个管道的表现,并报告平均和标准偏差分类准确率。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到标准化输入变量和使用分位数变换都获得了最佳结果,分类准确率约为 98.7%,比没有数据准备的基线提高了 95.3%。
您可以将自己的建模管道添加到 get_pipelines() 函数中,并比较它们的结果。
能不能取得更好的表现? 在下面的评论里告诉我。
>norm: 0.976 (0.031)
>std: 0.987 (0.023)
>quan: 0.987 (0.023)
>kbins: 0.968 (0.045)
>pca: 0.963 (0.039)
>svd: 0.953 (0.048)
创建了一个图形,显示了方框图和须图,总结了每种数据准备技术的分类准确度分数的分布。我们可以看到标准化和分位数转换的分数分布是紧凑的,非常相似,并且具有异常值。我们可以看到,其他变换的分数分布更大,并且向下倾斜。
结果可能表明,标准化数据集可能是数据准备和相关转换(如分位数转换)中的一个重要步骤,如果通过使一个或多个输入变量更高斯化而与标准化相结合,甚至幂转换也可能带来好处。
葡萄酒类别数据集上不同数据转换的分类准确度的盒须图
我们还可以探索变换序列,看看它们是否能提升表现。
例如,我们可能希望在标准化变换后应用 RFE 特征选择,以查看是否可以用更少的输入变量(例如,更少的复杂性)使用相同或更好的结果。
我们可能还想看看在数据缩放变换之前的幂变换是否能在数据集上获得良好的表现,因为我们认为如果分位数变换成功的话,它可以。
下面提供了更新后的 get_pipelines() 函数的变换序列。
# get modeling pipelines to evaluate
def get_pipelines(model):
pipelines = list()
# standardize
p = Pipeline([('s',StandardScaler()), ('r', RFE(estimator=LogisticRegression(solver='liblinear'), n_features_to_select=10)), ('m',model)])
pipelines.append(('std', p))
# scale and power
p = Pipeline([('s',MinMaxScaler((1,2))), ('p', PowerTransformer()), ('m',model)])
pipelines.append(('power', p))
return pipelines
将这些联系在一起,完整的示例如下所示。
# compare sequences of data preparation methods for the wine classification dataset
from numpy import mean
from numpy import std
from pandas import read_csv
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import QuantileTransformer
from sklearn.preprocessing import PowerTransformer
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.decomposition import PCA
from sklearn.decomposition import TruncatedSVD
from sklearn.feature_selection import RFE
from matplotlib import pyplot
# prepare the dataset
def load_dataset():
# load the dataset
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/wine.csv'
df = read_csv(url, header=None)
data = df.values
X, y = data[:, :-1], data[:, -1]
# minimally prepare dataset
X = X.astype('float')
y = LabelEncoder().fit_transform(y.astype('str'))
return X, y
# evaluate a model
def evaluate_model(X, y, model):
# define the cross-validation procedure
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
# evaluate model
scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1)
return scores
# get modeling pipelines to evaluate
def get_pipelines(model):
pipelines = list()
# standardize
p = Pipeline([('s',StandardScaler()), ('r', RFE(estimator=LogisticRegression(solver='liblinear'), n_features_to_select=10)), ('m',model)])
pipelines.append(('std', p))
# scale and power
p = Pipeline([('s',MinMaxScaler((1,2))), ('p', PowerTransformer()), ('m',model)])
pipelines.append(('power', p))
return pipelines
# get the dataset
X, y = load_dataset()
# define the model
model = LogisticRegression(solver='liblinear')
# get the modeling pipelines
pipelines = get_pipelines(model)
# evaluate each pipeline
results, names = list(), list()
for name, pipeline in pipelines:
# evaluate
scores = evaluate_model(X, y, pipeline)
# summarize
print('>%s: %.3f (%.3f)' % (name, mean(scores), std(scores)))
# store
results.append(scores)
names.append(name)
# plot the result
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()
运行该示例会评估每个管道的表现,并报告平均和标准偏差分类准确率。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到,具有特征选择的标准化提供了从 98.7%到 98.9%的额外准确率提升,尽管数据缩放和功率变换没有提供任何超过分位数变换的额外好处。
>std: 0.989 (0.022)
>power: 0.987 (0.023)
创建了一个图形,显示了方框图和须图,总结了每种数据准备技术的分类准确度分数的分布。
我们可以看到,两个变换管道的结果分布是紧凑的,除了异常值之外,几乎没有扩展。
葡萄酒类别数据集中不同数据转换序列分类准确率的盒须图
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
书
蜜蜂
摘要
在本教程中,您发现了如何使用网格搜索方法来准备表格数据。
具体来说,您了解到:
- 网格搜索为表格数据的数据准备提供了一种替代方法,其中变换被尝试作为建模管道的超参数。
- 如何使用网格搜索方法进行数据准备,以提高标准类别数据集的模型表现。
- 如何网格搜索序列的数据准备方法,进一步提高模型表现。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。*
如何爬坡机器学习测试集
最后更新于 2020 年 9 月 27 日
爬坡测试集是一种在机器学习比赛中实现良好或完美预测的方法,无需接触训练集,甚至无需开发预测模型。
作为一种机器学习竞赛的方法,它理所当然地遭到了反对,大多数竞赛平台都施加了限制来阻止它,这很重要。
然而,爬坡测试集是一个机器学习实践者在参加比赛时偶然做的事情。通过开发一个显式的实现来爬上测试集,它有助于更好地理解过度使用测试数据集来评估建模管道是多么容易。
在本教程中,您将发现如何爬坡机器学习的测试集。
完成本教程后,您将知道:
- 通过爬坡测试集,甚至不用看训练数据集,就可以做出完美的预测。
- 如何爬坡分类和回归任务的测试集?
- 当我们过度使用测试集来评估我们的建模管道时,我们隐式地爬坡测试集。
用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
如何爬坡机器学习测试集 图片由斯蒂格·尼加德提供,版权所有。
教程概述
本教程分为五个部分;它们是:
- 爬坡测试装置
- 爬坡算法
- 如何实现爬坡
- 爬坡糖尿病类别数据集
- 爬坡住房回归数据集
爬坡测试装置
像 Kaggle 上的机器学习竞赛一样,机器学习竞赛提供了完整的训练数据集以及测试集的输入。
给定竞赛的目标是预测目标值,例如测试集的标签或数值。根据隐藏的测试集目标值评估解决方案,并适当评分。对测试集得分最高的提交作品将赢得比赛。
机器学习竞赛的挑战可以被定义为一个优化问题。传统上,竞赛参与者充当优化算法,探索导致不同预测集的不同建模管道,对预测进行评分,然后对管道进行更改,预计会提高评分。
这个过程也可以直接用优化算法建模,在优化算法中,候选预测被生成和评估,而不需要看训练集。
一般这被称为爬坡这个测试集,作为解决这个问题最简单的优化算法之一要实现的就是爬坡算法。
虽然爬坡测试集在实际的机器学习比赛中理所当然地遭到了的反对,但是为了了解该方法的局限性和过拟合测试集的危险,实现该方法可能是一个有趣的练习。此外,测试集可以在不接触训练数据集的情况下被完美预测,这一事实经常让许多机器学习初学者感到震惊。
最重要的是,当我们重复评估不同的建模管道时,我们隐式地爬上测试集。风险在于,在测试集上得分的提高是以泛化误差的增加为代价的,即在更广泛的问题上表现更差。
运行机器学习竞赛的人很清楚这个问题,并对预测评估施加限制来对抗它,例如每天将评估限制在一个或几个,并报告测试集的隐藏子集而不是整个测试集的分数。有关这方面的更多信息,请参阅后续阅读部分列出的论文。
接下来,让我们看看如何实现爬坡算法来优化测试集的预测。
爬坡算法
爬坡算法是一个非常简单的优化算法。
它包括生成候选解决方案并对其进行评估。这是一个起点,然后逐步改进,直到无法实现进一步的改进,或者我们没有时间、资源或兴趣。
从现有候选解决方案生成新的候选解决方案。通常,这包括对候选解决方案进行单次更改,对其进行评估,如果候选解决方案与先前的当前解决方案一样好或更好,则接受该候选解决方案作为新的“当前”解决方案。否则,将被丢弃。
我们可能认为只接受分数较高的候选人是个好主意。对于许多简单的问题来说,这是一种合理的方法,尽管在更复杂的问题上,为了帮助搜索过程缩放特征空间中的平坦区域(平台),需要接受具有相同分数的不同候选。
爬坡测试集时,候选解是一个预测列表。对于二进制分类任务,这是两个类的 0 和 1 值的列表。对于回归任务,这是目标变量范围内的数字列表。
对用于分类的候选解决方案的修改是选择一个预测,并将其从 0 翻转到 1 或从 1 翻转到 0。对回归的候选解决方案的修改是向列表中的一个值添加高斯噪声,或者用新值替换列表中的一个值。
解决方案的评分包括计算评分标准,例如分类任务的分类准确率或回归任务的平均绝对误差。
现在我们已经熟悉了算法,让我们实现它。
如何实现爬坡
我们将在综合分类任务上开发我们的爬坡算法。
首先,让我们创建一个包含许多输入变量和 5000 行示例的二进制分类任务。然后,我们可以将数据集分成训练集和测试集。
下面列出了完整的示例。
# example of a synthetic dataset.
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
# define dataset
X, y = make_classification(n_samples=5000, n_features=20, n_informative=15, n_redundant=5, random_state=1)
print(X.shape, y.shape)
# split dataset
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
运行该示例首先报告创建的数据集的形状,显示 5,000 行和 20 个输入变量。
然后将数据集分成训练集和测试集,约 3300 个用于训练,约 1600 个用于测试。
(5000, 20) (5000,)
(3350, 20) (1650, 20) (3350,) (1650,)
现在我们可以培养一名登山者。
首先,我们可以创建一个函数来加载,或者在这种情况下,定义数据集。我们可以在以后想要更改数据集时更新这个函数。
# load or prepare the classification dataset
def load_dataset():
return make_classification(n_samples=5000, n_features=20, n_informative=15, n_redundant=5, random_state=1)
接下来,我们需要一个函数来评估候选解决方案——也就是预测列表。
我们将使用分类准确率,其中对于最差的可能解决方案,得分在 0 到 1 之间,对于一组完美的预测。
# evaluate a set of predictions
def evaluate_predictions(y_test, yhat):
return accuracy_score(y_test, yhat)
接下来,我们需要一个函数来创建一个初始候选解决方案。
这是 0 和 1 类标签的预测列表,足够长以匹配测试集中的示例数,在本例中为 1650 个。
我们可以使用 randint()函数生成 0 和 1 的随机值。
# create a random set of predictions
def random_predictions(n_examples):
return [randint(0, 1) for _ in range(n_examples)]
接下来,我们需要一个函数来创建候选解决方案的修改版本。
在这种情况下,这包括在解决方案中选择一个值,并将其从 0 翻转到 1 或从 1 翻转到 0。
通常,在爬坡过程中,我们会对每个新的候选解决方案进行一次更改,但是我已经对该函数进行了参数化,因此如果您愿意,您可以尝试进行多次更改。
# modify the current set of predictions
def modify_predictions(current, n_changes=1):
# copy current solution
updated = current.copy()
for i in range(n_changes):
# select a point to change
ix = randint(0, len(updated)-1)
# flip the class label
updated[ix] = 1 - updated[ix]
return updated
目前为止,一切顺利。
接下来,我们可以开发执行搜索的功能。
首先,通过调用 random_predictions() 函数,然后调用 evaluate_predictions() 函数来创建和评估初始解。
然后我们循环固定次数的迭代,通过调用 modify_predictions() 生成一个新的候选,对其进行评估,如果得分和当前解一样好或者比当前解更好,则进行替换。
当我们完成预设的迭代次数(任意选择)或获得满分时,循环结束,在这种情况下,我们知道的是 1.0(100%)的准确率。
下面的函数*hill _ climp _ testset()*实现了这一点,将测试集作为输入,并返回在爬坡过程中找到的最佳预测集。
# run a hill climb for a set of predictions
def hill_climb_testset(X_test, y_test, max_iterations):
scores = list()
# generate the initial solution
solution = random_predictions(X_test.shape[0])
# evaluate the initial solution
score = evaluate_predictions(y_test, solution)
scores.append(score)
# hill climb to a solution
for i in range(max_iterations):
# record scores
scores.append(score)
# stop once we achieve the best score
if score == 1.0:
break
# generate new candidate
candidate = modify_predictions(solution)
# evaluate candidate
value = evaluate_predictions(y_test, candidate)
# check if it is as good or better
if value >= score:
solution, score = candidate, value
print('>%d, score=%.3f' % (i, score))
return solution, scores
么事儿啦在那里。
下面列出了爬坡测试集的完整示例。
# example of hill climbing the test set for a classification task
from random import randint
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from matplotlib import pyplot
# load or prepare the classification dataset
def load_dataset():
return make_classification(n_samples=5000, n_features=20, n_informative=15, n_redundant=5, random_state=1)
# evaluate a set of predictions
def evaluate_predictions(y_test, yhat):
return accuracy_score(y_test, yhat)
# create a random set of predictions
def random_predictions(n_examples):
return [randint(0, 1) for _ in range(n_examples)]
# modify the current set of predictions
def modify_predictions(current, n_changes=1):
# copy current solution
updated = current.copy()
for i in range(n_changes):
# select a point to change
ix = randint(0, len(updated)-1)
# flip the class label
updated[ix] = 1 - updated[ix]
return updated
# run a hill climb for a set of predictions
def hill_climb_testset(X_test, y_test, max_iterations):
scores = list()
# generate the initial solution
solution = random_predictions(X_test.shape[0])
# evaluate the initial solution
score = evaluate_predictions(y_test, solution)
scores.append(score)
# hill climb to a solution
for i in range(max_iterations):
# record scores
scores.append(score)
# stop once we achieve the best score
if score == 1.0:
break
# generate new candidate
candidate = modify_predictions(solution)
# evaluate candidate
value = evaluate_predictions(y_test, candidate)
# check if it is as good or better
if value >= score:
solution, score = candidate, value
print('>%d, score=%.3f' % (i, score))
return solution, scores
# load the dataset
X, y = load_dataset()
print(X.shape, y.shape)
# split dataset into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
# run hill climb
yhat, scores = hill_climb_testset(X_test, y_test, 20000)
# plot the scores vs iterations
pyplot.plot(scores)
pyplot.show()
运行该示例将运行 20,000 次迭代的搜索,如果达到完美的准确率,则停止搜索。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们在大约 12,900 次迭代中为测试集找到了一组完美的预测。
回想一下,这是在不接触训练数据集和不通过查看测试集目标值作弊的情况下实现的。相反,我们只是优化了一组数字。
这里的教训是,针对测试集重复评估建模管道会做同样的事情,使用你作为爬坡优化算法。解决方案将会被测试集覆盖。
...
>8092, score=0.996
>8886, score=0.997
>9202, score=0.998
>9322, score=0.998
>9521, score=0.999
>11046, score=0.999
>12932, score=1.000
还会创建一个优化进度图。
这有助于了解优化算法的变化如何影响搜索的收敛性,例如选择要改变什么以及在爬坡过程中如何改变。
分类任务的准确率与爬坡优化迭代的线图
现在我们已经熟悉了爬坡测试集,让我们在真实数据集上尝试这种方法。
爬坡糖尿病类别数据集
我们将使用糖尿病数据集作为基础来探索爬坡分类问题的测试集。
每份记录都描述了女性的医疗细节,预测是未来五年内糖尿病的发作。
数据集有 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
...
我们可以直接使用 Pandas 加载数据集,如下所示。
# load or prepare the classification dataset
def load_dataset():
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.csv'
df = read_csv(url, header=None)
data = df.values
return data[:, :-1], data[:, -1]
代码的其余部分保持不变。
这是这样创建的,以便您可以加入自己的二进制分类任务并尝试它。
下面列出了完整的示例。
# example of hill climbing the test set for the diabetes dataset
from random import randint
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from matplotlib import pyplot
# load or prepare the classification dataset
def load_dataset():
url = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.csv'
df = read_csv(url, header=None)
data = df.values
return data[:, :-1], data[:, -1]
# evaluate a set of predictions
def evaluate_predictions(y_test, yhat):
return accuracy_score(y_test, yhat)
# create a random set of predictions
def random_predictions(n_examples):
return [randint(0, 1) for _ in range(n_examples)]
# modify the current set of predictions
def modify_predictions(current, n_changes=1):
# copy current solution
updated = current.copy()
for i in range(n_changes):
# select a point to change
ix = randint(0, len(updated)-1)
# flip the class label
updated[ix] = 1 - updated[ix]
return updated
# run a hill climb for a set of predictions
def hill_climb_testset(X_test, y_test, max_iterations):
scores = list()
# generate the initial solution
solution = random_predictions(X_test.shape[0])
# evaluate the initial solution
score = evaluate_predictions(y_test, solution)
scores.append(score)
# hill climb to a solution
for i in range(max_iterations):
# record scores
scores.append(score)
# stop once we achieve the best score
if score == 1.0:
break
# generate new candidate
candidate = modify_predictions(solution)
# evaluate candidate
value = evaluate_predictions(y_test, candidate)
# check if it is as good or better
if value >= score:
solution, score = candidate, value
print('>%d, score=%.3f' % (i, score))
return solution, scores
# load the dataset
X, y = load_dataset()
print(X.shape, y.shape)
# split dataset into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
# run hill climb
yhat, scores = hill_climb_testset(X_test, y_test, 5000)
# plot the scores vs iterations
pyplot.plot(scores)
pyplot.show()
每次在搜索过程中看到改进时,运行该示例都会报告迭代次数和准确性。
在这种情况下,我们使用更少的迭代,因为这是一个更简单的优化问题,因为我们要做的预测更少。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到我们在大约 1500 次迭代中达到了完美的准确率。
...
>617, score=0.961
>627, score=0.965
>650, score=0.969
>683, score=0.972
>743, score=0.976
>803, score=0.980
>817, score=0.984
>945, score=0.988
>1350, score=0.992
>1387, score=0.996
>1565, score=1.000
还创建了搜索进度的线图,显示收敛速度很快。
糖尿病数据集的准确率线图与爬坡优化迭代
爬坡住房回归数据集
我们将使用房屋数据集作为基础来探索爬坡测试集回归问题。
房屋数据集涉及房屋及其附近地区的详细信息,以千美元为单位预测房价。
这是一个回归问题,意味着我们预测的是一个数值。有 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
...
首先,我们可以更新 load_dataset() 函数来加载房屋数据集。
作为加载数据集的一部分,我们将标准化目标值。这将使爬坡预测更简单,因为我们可以将浮点值限制在 0 到 1 的范围内。
这通常不是必需的,只是这里为简化搜索算法而采取的方法。
# load or prepare the classification dataset
def load_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]
# normalize the target
scaler = MinMaxScaler()
y = y.reshape((len(y), 1))
y = scaler.fit_transform(y)
return X, y
接下来,我们可以更新评分函数,以使用期望值和预测值之间的平均绝对误差。
# evaluate a set of predictions
def evaluate_predictions(y_test, yhat):
return mean_absolute_error(y_test, yhat)
我们还必须将解决方案的表示从 0 和 1 标签更新为 0 和 1 之间的浮点值。
必须更改初始候选解的生成,以创建随机浮动列表。
# create a random set of predictions
def random_predictions(n_examples):
return [random() for _ in range(n_examples)]
在这种情况下,为了创建新的候选解决方案,对解决方案所做的单个更改只需要用新的随机浮点数替换列表中随机选择的预测。
我选择这个是因为它很简单。
# modify the current set of predictions
def modify_predictions(current, n_changes=1):
# copy current solution
updated = current.copy()
for i in range(n_changes):
# select a point to change
ix = randint(0, len(updated)-1)
# flip the class label
updated[ix] = random()
return updated
更好的方法是将高斯噪声添加到现有值中,我将此作为扩展留给您。如果你尝试了,请在下面的评论中告诉我。
例如:
...
# add gaussian noise
updated[ix] += gauss(0, 0.1)
最后,搜索必须更新。
最佳值现在是 0.0,用于在找到时停止搜索。
...
# stop once we achieve the best score
if score == 0.0:
break
我们还需要将搜索从最大化分数改为现在最小化分数。
...
# check if it is as good or better
if value <= score:
solution, score = candidate, value
print('>%d, score=%.3f' % (i, score))
下面列出了这两项更改的更新搜索功能。
# run a hill climb for a set of predictions
def hill_climb_testset(X_test, y_test, max_iterations):
scores = list()
# generate the initial solution
solution = random_predictions(X_test.shape[0])
# evaluate the initial solution
score = evaluate_predictions(y_test, solution)
print('>%.3f' % score)
# hill climb to a solution
for i in range(max_iterations):
# record scores
scores.append(score)
# stop once we achieve the best score
if score == 0.0:
break
# generate new candidate
candidate = modify_predictions(solution)
# evaluate candidate
value = evaluate_predictions(y_test, candidate)
# check if it is as good or better
if value <= score:
solution, score = candidate, value
print('>%d, score=%.3f' % (i, score))
return solution, scores
将这些联系在一起,下面列出了爬坡回归任务测试集的完整示例。
# example of hill climbing the test set for the housing dataset
from random import random
from random import randint
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error
from sklearn.preprocessing import MinMaxScaler
from matplotlib import pyplot
# load or prepare the classification dataset
def load_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]
# normalize the target
scaler = MinMaxScaler()
y = y.reshape((len(y), 1))
y = scaler.fit_transform(y)
return X, y
# evaluate a set of predictions
def evaluate_predictions(y_test, yhat):
return mean_absolute_error(y_test, yhat)
# create a random set of predictions
def random_predictions(n_examples):
return [random() for _ in range(n_examples)]
# modify the current set of predictions
def modify_predictions(current, n_changes=1):
# copy current solution
updated = current.copy()
for i in range(n_changes):
# select a point to change
ix = randint(0, len(updated)-1)
# flip the class label
updated[ix] = random()
return updated
# run a hill climb for a set of predictions
def hill_climb_testset(X_test, y_test, max_iterations):
scores = list()
# generate the initial solution
solution = random_predictions(X_test.shape[0])
# evaluate the initial solution
score = evaluate_predictions(y_test, solution)
print('>%.3f' % score)
# hill climb to a solution
for i in range(max_iterations):
# record scores
scores.append(score)
# stop once we achieve the best score
if score == 0.0:
break
# generate new candidate
candidate = modify_predictions(solution)
# evaluate candidate
value = evaluate_predictions(y_test, candidate)
# check if it is as good or better
if value <= score:
solution, score = candidate, value
print('>%d, score=%.3f' % (i, score))
return solution, scores
# load the dataset
X, y = load_dataset()
print(X.shape, y.shape)
# split dataset into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=1)
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)
# run hill climb
yhat, scores = hill_climb_testset(X_test, y_test, 100000)
# plot the scores vs iterations
pyplot.plot(scores)
pyplot.show()
运行该示例会报告每次在搜索过程中看到改进时的迭代次数和 MAE。
在这种情况下,我们使用更多的迭代,因为这是一个更复杂的优化问题。所选择的创建候选解决方案的方法也使它变得更慢,并且我们不太可能实现完美的错误。
事实上,我们不会实现完美的错误;相反,如果错误达到低于最小值的值,如 1e-7 或对目标域有意义的值,则最好停止。这也是留给读者的练习。
例如:
...
# stop once we achieve a good enough
if score <= 1e-7:
break
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到,在运行结束时,我们实现了一个很好的错误。
...
>95991, score=0.001
>96011, score=0.001
>96295, score=0.001
>96366, score=0.001
>96585, score=0.001
>97575, score=0.001
>98828, score=0.001
>98947, score=0.001
>99712, score=0.001
>99913, score=0.001
还创建了搜索进度的线图,显示收敛速度很快,并且在大多数迭代中保持平稳。
房屋数据集的准确率线图与爬坡优化迭代
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
报纸
- 利用日志丢失神谕攀登卡格尔排行榜,2018。
- 走向更好理解排行榜,2017 年。
- 阶梯:机器学习竞赛的可靠排行榜,2015。
文章
摘要
在本教程中,您发现了如何爬上机器学习的测试集。
具体来说,您了解到:
- 通过爬坡测试集,甚至不用看训练数据集,就可以做出完美的预测。
- 如何爬坡分类和回归任务的测试集?
- 当我们过度使用测试集来评估我们的建模管道时,我们隐式地爬坡测试集。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。