Machine Learning Mastery 数据准备教程(三)
机器学习降维介绍
最后更新于 2020 年 6 月 30 日
数据集的输入变量或特征的数量称为其维数。
降维是指减少数据集中输入变量数量的技术。
更多的输入特征通常会使预测建模任务更具挑战性,更一般地说,这被称为维数灾难。
高维统计和降维技术常用于数据可视化。然而,这些技术可以用于应用机器学习,以简化分类或回归数据集,从而更好地拟合预测模型。
在这篇文章中,你会发现一个关于机器学习降维的温和介绍
看完这篇文章,你会知道:
- 大量的输入特征会导致机器学习算法表现不佳。
- 降维是与减少输入特征的数量有关的一般研究领域。
- 降维方法包括特征选择、线性代数方法、投影方法和自动编码器。
用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
- 2020 年 5 月更新:更改章节标题更准确。
机器学习降维的温和介绍 凯文·贾勒特摄,版权所有。
概观
本教程分为三个部分;它们是:
- 多输入变量问题
- 降维
- 降维技术
- 特征选择方法
- 矩阵分解
- 流形学习
- 自动编码器方法
- 降维技巧
多输入变量问题
当输入变量过多时,机器学习算法的表现会下降。
如果您的数据是用行和列来表示的,例如在电子表格中,那么输入变量就是作为输入提供给模型以预测目标变量的列。输入变量也称为特征。
我们可以将 n 维特征空间上表示维度的数据列和数据行视为该空间中的点。这是数据集的一种有用的几何解释。
特征空间中有大量的维度可能意味着该空间的体积非常大,反过来,我们在该空间中的点(数据行)通常代表一个小的且不具有代表性的样本。
这可能会极大地影响机器学习算法在具有许多输入特征的数据上的表现,通常被称为“维度诅咒””
因此,通常希望减少输入特征的数量。
这减少了特征空间的维数,因此得名“降维”
降维
降维是指减少训练数据中输入变量数量的技术。
当处理高维数据时,通过将数据投影到捕捉数据“本质”的低维子空间来降低维数通常是有用的。这叫做降维。
—第 11 页,机器学习:概率视角,2012。
高维可能意味着数百、数千甚至数百万个输入变量。
更少的输入维数通常意味着机器学习模型中相应更少的参数或更简单的结构,称为自由度。具有太多自由度的模型可能会过度训练数据集,因此在新数据上可能表现不佳。
希望有简单的模型能够很好地概括,进而输入数据中的输入变量很少。对于输入数量和模型自由度通常密切相关的线性模型尤其如此。
维数灾难的根本原因是高维函数可能比低维函数复杂得多,而且这些复杂性更难辨别。打破诅咒的唯一方法是整合关于正确数据的知识。
—第 15 页,图案分类,2000 年。
降维是在建模之前对数据执行的数据准备技术。它可以在数据清理和数据缩放之后、训练预测模型之前执行。
…降维产生了目标概念的更紧凑、更容易解释的表示,将用户的注意力集中在最相关的变量上。
—第 289 页,数据挖掘:实用机器学习工具与技术,2016 年第 4 版。
因此,在使用最终模型进行预测时,对训练数据执行的任何降维也必须对新数据执行,例如测试数据集、验证数据集和数据。
降维技术
有许多技术可以用于降维。
在本节中,我们将回顾主要的技术。
特征选择方法
也许最常见的是所谓的特征选择技术,它使用评分或统计方法来选择保留哪些特征和删除哪些特征。
……执行特征选择,以删除对分类问题帮助不大的“无关”特征。
—第 86 页,机器学习:概率视角,2012。
两类主要的特征选择技术包括包装方法和过滤方法。
有关一般特征选择的更多信息,请参见教程:
顾名思义,包装器方法包装一个机器学习模型,用输入特征的不同子集拟合和评估该模型,并选择导致最佳模型表现的子集。RFE 是包装特征选择方法的一个例子。
过滤方法使用评分方法,如特征和目标变量之间的相关性,来选择最具预测性的输入特征子集。例子包括皮尔逊相关和卡方检验。
有关基于过滤器的特征选择方法的更多信息,请参见教程:
矩阵分解
线性代数的技术可以用于降维。
具体来说,矩阵分解方法可用于将数据集矩阵简化为其组成部分。
例子包括特征分解和奇异值分解。
有关矩阵分解的更多信息,请参见教程:
然后,可以对这些部分进行排序,并且可以选择这些部分的子集,该子集最好地捕捉可用于表示数据集的矩阵的显著结构。
最常用的成分排序方法是主成分分析,简称 PCA。
最常见的降维方法叫做主成分分析。
—第 11 页,机器学习:概率视角,2012。
有关主成分分析的更多信息,请参见教程:
流形学习
来自高维统计的技术也可以用于降维。
在数学中,投影是一种以某种方式转换数据的函数或映射。
—第 304 页,数据挖掘:实用机器学习工具与技术,2016 年第 4 版。
这些技术有时被称为“流形学习”,用于创建高维数据的低维投影,通常用于数据可视化的目的。
投影被设计成既创建数据集的低维表示,同时最好地保留数据中的显著结构或关系。
多种学习技术的例子包括:
- 科霍宁自组织映射(SOM) 。
- 萨蒙斯地图
- 多维标度(MDS)
- 分布式随机邻居嵌入(t-SNE)。
投影中的特征通常与原始列关系不大,例如它们没有列名,这可能会使初学者感到困惑。
自动编码器方法
可以构建深度学习神经网络来执行降维。
一种流行的方法叫做自动编码器。这包括构建一个自我监督的学习问题,其中模型必须正确地再现输入。
有关自我监督学习的更多信息,请参见教程:
使用网络模型,试图将数据流压缩到比原始输入数据维度少得多的瓶颈层。模型中位于瓶颈之前并包含瓶颈的部分称为编码器,模型中读取瓶颈输出并重构输入的部分称为解码器。
自动编码器是一种用于降维和特征发现的无监督神经网络。更准确地说,自动编码器是一个被训练来预测输入本身的前馈神经网络。
—第 1000 页,机器学习:概率视角,2012。
训练后,解码器被丢弃,瓶颈的输出被直接用作输入的降维。然后,由该编码器转换的输入可以被馈送到另一个模型,不一定是神经网络模型。
深度自动编码器是非线性降维的有效框架。一旦这样的网络已经建立,编码器的最顶层,代码层 hc,可以被输入到监督分类过程。
—第 448 页,数据挖掘:实用机器学习工具与技术,2016 年第 4 版。
编码器的输出是一种投影类型,与其他投影方法一样,瓶颈输出与原始输入变量之间没有直接关系,这使得它们难以解释。
有关自动编码器的示例,请参见教程:
降维技巧
没有最好的降维技术,也没有技术到问题的映射。
相反,最好的方法是使用系统的受控实验来发现什么样的降维技术,当与您选择的模型配对时,会在您的数据集上产生最佳表现。
典型地,线性代数和流形学习方法假设所有输入特征具有相同的规模或分布。这表明,如果输入变量具有不同的比例或单位,那么在使用这些方法之前对数据进行规范化或标准化是一种良好的做法。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
教程
书
- 机器学习:概率视角,2012。
- 数据挖掘:实用机器学习工具与技术,第 4 版,2016。
- 图案分类,2000。
应用程序接口
文章
摘要
在这篇文章中,你发现了一个关于机器学习降维的温和介绍。
具体来说,您了解到:
- 大量的输入特征会导致机器学习算法表现不佳。
- 降维是与减少输入特征的数量有关的一般研究领域。
- 降维方法包括特征选择、线性代数方法、投影方法和自动编码器。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
如何为机器学习使用离散化变换
最后更新于 2020 年 8 月 28 日
数值输入变量可能具有高度偏斜或非标准分布。
这可能是由数据中的异常值、多模态分布、高度指数分布等引起的。
当数值输入变量具有标准概率分布时,许多机器学习算法更喜欢或表现得更好。
离散化转换提供了一种自动方式来更改数字输入变量,使其具有不同的数据分布,进而可以将其用作预测模型的输入。
在本教程中,您将发现如何使用离散化变换将数值映射到机器学习的离散类别
完成本教程后,您将知道:
- 当非标准概率分布的数值被离散化时,许多机器学习算法更喜欢或表现得更好。
- 离散化转换是一种将数字输入或输出变量转换为具有离散序数标签的技术。
- 如何使用 kbins 离散化器改变数值变量的结构和分布来提高预测模型的表现。
用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
如何使用离散化变换进行机器学习 图片由凯特·拉塞尔提供,版权所有。
教程概述
本教程分为六个部分;它们是:
- 更改数据分布
- 离散化变换
- 声纳数据集
- 均匀离散化变换
- k-均值离散化变换
- 分位数离散化变换
更改数据分布
一些机器学习算法可能更喜欢或需要分类或顺序输入变量,例如一些决策树和基于规则的算法。
一些分类和聚类算法只处理名义属性,而不能处理数字尺度上测量的属性。
—第 296 页,数据挖掘:实用机器学习工具与技术,2016 年第 4 版。
此外,对于具有非标准概率分布的变量,许多机器学习算法的表现会降低。
这既适用于分类和回归任务中的实值输入变量,也适用于回归任务中的实值目标变量。
一些输入变量可能具有高度偏斜的分布,例如指数分布,其中最常见的观测值聚集在一起。一些输入变量可能有异常值,导致分布高度分散。
这些问题和其他问题,如非标准分布和多模态分布,会使数据集难以用一系列机器学习模型建模。
因此,通常希望将每个输入变量转换为具有标准概率分布。
一种方法是使用数值变量的变换来具有离散的概率分布,其中每个数值被分配一个标签,并且标签具有有序(序数)关系。
这被称为宁滨或离散化变换,并且可以通过使数值输入变量的概率分布离散化来提高一些机器学习模型对于数据集的表现。
离散化变换
一个离散化变换将数值变量映射到离散值上。
宁滨,也称为分类或离散化,是将一个定量变量转化为一组两个或多个定性桶(即类别)的过程。
—第 129 页,特征工程与选择,2019 年。
变量的值被分组到离散的容器中,并且每个容器被分配一个唯一的整数,使得容器之间的序数关系被保留。
箱的使用通常被称为宁滨或k-箱,其中 k 是指一个数值变量映射到的组的数量。
该映射提供了值的高阶排序,可以平滑观察值之间的关系。该变换可以应用于训练数据集中的每个数字输入变量,然后作为输入提供给机器学习模型,以学习预测建模任务。
箱的确定必须包含在重采样过程中。
—第 132 页,特征工程与选择,2019。
可以使用不同的方法将这些值分组到 k 个离散仓中;常见的技术包括:
- 统一:每个仓在变量可能值的跨度内具有相同的宽度。
- 分位数:每个仓都有相同数量的值,根据百分位数进行拆分。
- 聚类:识别聚类,并为每个组分配示例。
离散化转换可通过KBinsDistrictzer 类在 Sklearn Python 机器学习库中获得。
“策略”参数控制输入变量的划分方式,如“统一”、“分位数”或“kman”
“n _ bin”参数控制将要创建的 bin 的数量,并且必须基于策略的选择进行设置,例如“统一”是灵活的,“分位数”必须有一个小于观测值或可感知百分位数的“n _ bin”,以及“ kmeans ”必须使用一个可以合理找到的聚类数量值。
“编码”参数通过设置“序数或单热编码”单热来控制转换是否将每个值映射为整数值序数编码几乎总是优选的,尽管单热编码可以允许模型学习组之间的非序数关系,例如在 k 的情况下-意味着聚类策略。
我们可以用一个小的工作示例来演示kbins 离散化器。我们可以生成一个随机高斯数的样本。然后,可以使用 kbins 离散化器将浮动值转换为固定数量的离散类别,这些类别具有有序的顺序关系。
下面列出了完整的示例。
# demonstration of the discretization transform
from numpy.random import randn
from sklearn.preprocessing import KBinsDiscretizer
from matplotlib import pyplot
# generate gaussian data sample
data = randn(1000)
# histogram of the raw data
pyplot.hist(data, bins=25)
pyplot.show()
# reshape data to have rows and columns
data = data.reshape((len(data),1))
# discretization transform the raw data
kbins = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')
data_trans = kbins.fit_transform(data)
# summarize first few rows
print(data_trans[:10, :])
# histogram of the transformed data
pyplot.hist(data_trans, bins=10)
pyplot.show()
运行该示例首先创建 1,000 个随机高斯浮点值的样本,并将数据绘制为直方图。
高斯分布的数据直方图
接下来,使用 kbins 离散化器将数值映射到分类值。我们将转换配置为创建 10 个类别(0 到 9),以序数格式(整数)输出结果,并统一划分输入数据的范围。
打印转换数据的样本,清楚地显示数据的整数格式。
[[5.]
[3.]
[2.]
[6.]
[7.]
[5.]
[3.]
[4.]
[4.]
[2.]]
最后,创建一个直方图,显示 10 个离散类别以及观察值如何分布在这些组中,遵循与原始数据相同的高斯形状模式。
具有离散类别的转换数据直方图
在接下来的几节中,我们将详细了解如何在真实数据集上使用离散化转换。
接下来,让我们介绍数据集。
声纳数据集
声纳数据集是用于二进制分类的标准机器学习数据集。
它涉及 60 个实值输入和一个两类目标变量。数据集中有 208 个示例,类别相当均衡。
使用重复的分层 10 倍交叉验证,基线分类算法可以达到大约 53.4%的分类准确率。使用重复的分层 10 倍交叉验证,该数据集的最高表现约为 88%。
该数据集描述了岩石或模拟地雷的雷达回波。
您可以从这里了解有关数据集的更多信息:
不需要下载数据集;我们将从我们的工作示例中自动下载它。
首先,让我们加载并总结数据集。下面列出了完整的示例。
# load and summarize the sonar dataset
from pandas import read_csv
from pandas.plotting import scatter_matrix
from matplotlib import pyplot
# Load dataset
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/sonar.csv"
dataset = read_csv(url, header=None)
# summarize the shape of the dataset
print(dataset.shape)
# summarize each variable
print(dataset.describe())
# histograms of the variables
dataset.hist()
pyplot.show()
运行该示例首先总结加载数据集的形状。
这确认了 60 个输入变量、一个输出变量和 208 行数据。
提供了输入变量的统计摘要,显示值是数值,范围大约从 0 到 1。
(208, 61)
0 1 2 ... 57 58 59
count 208.000000 208.000000 208.000000 ... 208.000000 208.000000 208.000000
mean 0.029164 0.038437 0.043832 ... 0.007949 0.007941 0.006507
std 0.022991 0.032960 0.038428 ... 0.006470 0.006181 0.005031
min 0.001500 0.000600 0.001500 ... 0.000300 0.000100 0.000600
25% 0.013350 0.016450 0.018950 ... 0.003600 0.003675 0.003100
50% 0.022800 0.030800 0.034300 ... 0.005800 0.006400 0.005300
75% 0.035550 0.047950 0.057950 ... 0.010350 0.010325 0.008525
max 0.137100 0.233900 0.305900 ... 0.044000 0.036400 0.043900
[8 rows x 60 columns]
最后,为每个输入变量创建一个直方图。
如果我们忽略图中杂乱的东西,专注于直方图本身,我们可以看到许多变量都有一个偏斜的分布。
声纳二进制类别数据集输入变量的直方图
接下来,让我们在原始数据集上拟合和评估一个机器学习模型。
我们将使用带有默认超参数的 k 最近邻算法,并使用重复分层 K 折交叉验证对其进行评估。
下面列出了完整的示例。
# evaluate knn on the raw sonar dataset
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.neighbors import KNeighborsClassifier
from sklearn.preprocessing import LabelEncoder
from matplotlib import pyplot
# load dataset
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/sonar.csv"
dataset = read_csv(url, header=None)
data = dataset.values
# separate into input and output columns
X, y = data[:, :-1], data[:, -1]
# ensure inputs are floats and output is an integer label
X = X.astype('float32')
y = LabelEncoder().fit_transform(y.astype('str'))
# define and configure the model
model = KNeighborsClassifier()
# evaluate the model
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
# report model performance
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
运行该示例会评估原始声纳数据集上的 KNN 模型。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
我们可以看到,该模型实现了大约 79.7%的平均分类准确率,表明它具有技巧性(优于 53.4%),并且处于良好表现的球园区(88%)。
Accuracy: 0.797 (0.073)
接下来,让我们探索数据集的统一离散化转换。
均匀离散化变换
一个统一的离散化变换将保留每个输入变量的概率分布,但是将使用指定数量的序数组或标签使其离散。
我们可以使用kbins 离散化器类应用统一离散化变换,并将“策略参数设置为“统一”我们还必须通过“n _ bin参数设置所需的箱数;在这种情况下,我们将使用 10。
一旦定义,我们就可以调用 fit_transform() 函数,并将其传递给我们的数据集,以创建数据集的分位数转换版本。
...
# perform a uniform discretization transform of the dataset
trans = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')
data = trans.fit_transform(data)
让我们在声纳数据集上试试。
下面列出了创建声纳数据集的统一离散化变换并绘制结果直方图的完整示例。
# visualize a uniform ordinal discretization transform of the sonar dataset
from pandas import read_csv
from pandas import DataFrame
from pandas.plotting import scatter_matrix
from sklearn.preprocessing import KBinsDiscretizer
from matplotlib import pyplot
# load dataset
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/sonar.csv"
dataset = read_csv(url, header=None)
# retrieve just the numeric input values
data = dataset.values[:, :-1]
# perform a uniform discretization transform of the dataset
trans = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')
data = trans.fit_transform(data)
# convert the array back to a dataframe
dataset = DataFrame(data)
# histograms of the variables
dataset.hist()
pyplot.show()
运行该示例会转换数据集并绘制每个输入变量的直方图。
我们可以看到直方图的形状通常与原始数据集的形状相匹配,尽管在这种情况下,每个变量都有固定数量的 10 个值或序数组。
声纳数据集均匀离散化变换输入变量的直方图
接下来,让我们评估与上一节相同的 KNN 模型,但在这种情况下是基于数据集的统一离散化变换。
下面列出了完整的示例。
# evaluate knn on the sonar dataset with uniform ordinal discretization transform
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.neighbors import KNeighborsClassifier
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# load dataset
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/sonar.csv"
dataset = read_csv(url, header=None)
data = dataset.values
# separate into input and output columns
X, y = data[:, :-1], data[:, -1]
# ensure inputs are floats and output is an integer label
X = X.astype('float32')
y = LabelEncoder().fit_transform(y.astype('str'))
# define the pipeline
trans = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')
model = KNeighborsClassifier()
pipeline = Pipeline(steps=[('t', trans), ('m', model)])
# evaluate the pipeline
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
# report pipeline performance
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
运行该示例,我们可以看到均匀离散化变换将表现从没有变换时的 79.7%提升到有变换时的 82.7%。
Accuracy: 0.827 (0.082)
接下来,让我们仔细看看 k-means 离散化变换。
k-均值离散化变换
K 均值离散化变换将尝试为每个输入变量拟合 K 个聚类,然后将每个观察值分配给一个聚类。
除非变量的经验分布比较复杂,否则集群的数量很可能很少,比如 3 到 5 个。
我们可以使用kbins 离散化器类应用 K-means 离散化变换,并将“策略参数设置为“kmean我们还必须通过“n _ bin参数设置所需的箱数;在这种情况下,我们将使用三个。
一旦定义,我们就可以调用 fit_transform() 函数,并将其传递给我们的数据集,以创建数据集的分位数转换版本。
...
# perform a k-means discretization transform of the dataset
trans = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='kmeans')
data = trans.fit_transform(data)
让我们在声纳数据集上试试。
下面列出了创建声纳数据集的 K 均值离散化变换并绘制结果直方图的完整示例。
# visualize a k-means ordinal discretization transform of the sonar dataset
from pandas import read_csv
from pandas import DataFrame
from pandas.plotting import scatter_matrix
from sklearn.preprocessing import KBinsDiscretizer
from matplotlib import pyplot
# load dataset
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/sonar.csv"
dataset = read_csv(url, header=None)
# retrieve just the numeric input values
data = dataset.values[:, :-1]
# perform a k-means discretization transform of the dataset
trans = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='kmeans')
data = trans.fit_transform(data)
# convert the array back to a dataframe
dataset = DataFrame(data)
# histograms of the variables
dataset.hist()
pyplot.show()
运行该示例会转换数据集并绘制每个输入变量的直方图。
我们可以看到,每个输入变量的观测值被组织成三组中的一组,其中一些在观测值方面看起来相当均匀,而另一些则不太均匀。
声纳数据集 K 均值离散化变换输入变量的直方图
接下来,让我们评估与上一节相同的 KNN 模型,但在这种情况下是基于数据集的 K 均值离散化变换。
下面列出了完整的示例。
# evaluate knn on the sonar dataset with k-means ordinal discretization transform
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.neighbors import KNeighborsClassifier
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# load dataset
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/sonar.csv"
dataset = read_csv(url, header=None)
data = dataset.values
# separate into input and output columns
X, y = data[:, :-1], data[:, -1]
# ensure inputs are floats and output is an integer label
X = X.astype('float32')
y = LabelEncoder().fit_transform(y.astype('str'))
# define the pipeline
trans = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='kmeans')
model = KNeighborsClassifier()
pipeline = Pipeline(steps=[('t', trans), ('m', model)])
# evaluate the pipeline
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
# report pipeline performance
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
运行该示例,我们可以看到 K-means 离散化变换将表现从没有变换时的 79.7%提升到有变换时的 81.4%,尽管略低于上一节中的均匀分布。
Accuracy: 0.814 (0.088)
接下来,让我们仔细看看分位数离散化变换。
分位数离散化变换
分位数离散化变换将尝试将每个输入变量的观测值分成 k 个组,其中分配给每个组的观测值数量大致相等。
除非有大量的观测值或复杂的经验分布,否则必须保持小的箱数,例如 5-10 个。
我们可以使用kbins 离散化器类应用分位数离散化变换,并将“策略参数设置为“分位数”我们还必须通过“n _ bin参数设置所需的箱数;在这种情况下,我们将使用 10。
...
# perform a quantile discretization transform of the dataset
trans = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='quantile')
data = trans.fit_transform(data)
下面的示例应用分位数离散化变换,并创建每个变换变量的直方图。
# visualize a quantile ordinal discretization transform of the sonar dataset
from pandas import read_csv
from pandas import DataFrame
from pandas.plotting import scatter_matrix
from sklearn.preprocessing import KBinsDiscretizer
from matplotlib import pyplot
# load dataset
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/sonar.csv"
dataset = read_csv(url, header=None)
# retrieve just the numeric input values
data = dataset.values[:, :-1]
# perform a quantile discretization transform of the dataset
trans = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='quantile')
data = trans.fit_transform(data)
# convert the array back to a dataframe
dataset = DataFrame(data)
# histograms of the variables
dataset.hist()
pyplot.show()
运行该示例会转换数据集并绘制每个输入变量的直方图。
我们可以看到,直方图都显示了每个输入变量的均匀概率分布,其中 10 组中的每一组都有相同数量的观察值。
声纳数据集分位数离散化变换输入变量的直方图
接下来,让我们评估与上一节相同的 KNN 模型,但在这种情况下,基于原始数据集的分位数离散化变换。
下面列出了完整的示例。
# evaluate knn on the sonar dataset with quantile ordinal discretization transform
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.neighbors import KNeighborsClassifier
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# load dataset
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/sonar.csv"
dataset = read_csv(url, header=None)
data = dataset.values
# separate into input and output columns
X, y = data[:, :-1], data[:, -1]
# ensure inputs are floats and output is an integer label
X = X.astype('float32')
y = LabelEncoder().fit_transform(y.astype('str'))
# define the pipeline
trans = KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='quantile')
model = KNeighborsClassifier()
pipeline = Pipeline(steps=[('t', trans), ('m', model)])
# evaluate the pipeline
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(pipeline, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
# report pipeline performance
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
运行该示例,我们可以看到均匀变换将表现从没有变换时的 79.7%提升到有变换时的 84.0%,优于前面部分的均匀和 K-means 方法。
Accuracy: 0.840 (0.072)
我们选择箱的数量作为任意数量;在这种情况下,是 10。
这个超参数可以被调整来探索变换的分辨率对模型的最终技能的影响。
下面的示例执行了该实验,并绘制了从 2 到 10 的不同“n _ bin”值的平均准确率。
# explore number of discrete bins on classification accuracy
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.neighbors import KNeighborsClassifier
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.preprocessing import LabelEncoder
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# get the dataset
def get_dataset():
# load dataset
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/sonar.csv"
dataset = read_csv(url, header=None)
data = dataset.values
# separate into input and output columns
X, y = data[:, :-1], data[:, -1]
# ensure inputs are floats and output is an integer label
X = X.astype('float32')
y = LabelEncoder().fit_transform(y.astype('str'))
return X, y
# get a list of models to evaluate
def get_models():
models = dict()
for i in range(2,11):
# define the pipeline
trans = KBinsDiscretizer(n_bins=i, encode='ordinal', strategy='quantile')
model = KNeighborsClassifier()
models[str(i)] = Pipeline(steps=[('t', trans), ('m', model)])
return models
# 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
# get the dataset
X, y = get_dataset()
# get the models to evaluate
models = get_models()
# evaluate the models and store results
results, names = list(), list()
for name, model in models.items():
scores = evaluate_model(model, X, y)
results.append(scores)
names.append(name)
print('>%s %.3f (%.3f)' % (name, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()
运行该示例会报告“n _ bin”参数的每个值的平均分类准确率。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
我们可以看到,令人惊讶的是,较小的值导致了更好的准确性,例如三个值达到了大约 86.7%的准确性。
>2 0.806 (0.080)
>3 0.867 (0.070)
>4 0.835 (0.083)
>5 0.838 (0.070)
>6 0.836 (0.071)
>7 0.854 (0.071)
>8 0.837 (0.077)
>9 0.841 (0.069)
>10 0.840 (0.072)
创建方框图和触须图来总结数据集上每个离散面元数的分类准确率分数。
我们可以在三个面元处看到准确率的小幅提升,对于更大的值,分数会下降并保持不变。
结果强调,对于所选择的方法,探索不同数量的离散箱可能会有一些好处,以查看是否可以实现更好的表现。
声纳数据集中离散面元数量与 KNN 分类准确率的箱线图
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
教程
书
- 数据挖掘:实用机器学习工具与技术,第 4 版,2016。
- 特征工程与选择,2019。
资料组
蜜蜂
文章
摘要
在本教程中,您发现了如何使用离散化转换将数值映射到机器学习的离散类别。
具体来说,您了解到:
- 当非标准概率分布的数值被离散化时,许多机器学习算法更喜欢或表现得更好。
- 离散化转换是一种将数字输入或输出变量转换为具有离散序数标签的技术。
- 如何使用 kbins 离散化器改变数值变量的结构和分布来提高预测模型的表现。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
特征工程与选择(书评)
最后更新于 2020 年 6 月 30 日
数据准备是将原始数据转化为学习算法的过程。
在某些情况下,为了以所需的输入格式向算法提供数据,数据准备是必需的步骤。在其他情况下,输入数据的最合适表示是未知的,必须以试错的方式进行探索,以便发现什么最适合给定的模型和数据集。
马克斯·库恩(Max Kuhn)和凯尔·约翰逊(Kjell Johnson)写了一本新书,重点介绍了数据准备这一重要主题,以及如何利用机器学习算法在预测建模项目中最大限度地利用您的数据。这本书的标题是“特征工程和选择:预测模型的实用方法”,于 2019 年发布。
在这篇文章中,你会发现我对《特征工程与选择》一书的回顾和分解,该书的主题是机器学习的数据准备。
让我们开始吧!
特征工程与选择(书评)
概观
本教程分为三个部分;它们是:
- 特征工程与选择
- 书的分解
- 对这本书的最后思考
特征工程与选择
“特征工程与选择:预测模型的实用方法”是由马克斯·库恩和谢尔·约翰逊撰写并于 2019 年出版的一本书。
库恩和约翰逊是我最喜欢的一本关于实用机器学习的书的作者,该书名为《应用预测建模》,于 2013 年出版。而库恩也是机器学习的热门脱字号 R 包的作者。因此,他们出版的任何一本书,我都会立即购买并吞食。
这本新书的重点是机器学习的数据准备问题。
作者强调,尽管拟合和评估模型是例行公事,但预测建模问题能否取得良好的表现在很大程度上取决于数据是如何准备的。
尽管我们试图遵循这些良好的实践,但我们有时会沮丧地发现,最佳模型的有用预测表现不如预期。这种表现的缺乏可能是由于……收集的相关预测值以模型难以获得良好表现的方式表示。
—Xi 页,“特征工程与选择”,2019。
它们将准备建模数据的过程称为“特征工程”
这和我习惯的定义略有不同。我会称之为“数据准备”或“数据预处理”并将“特征工程”分开作为一个子任务,专注于从现有数据创建新输入变量的系统步骤。
然而,我看到了它们的来源,因为所有的数据准备都符合这个定义。
调整和改造预测因子,使模型更好地揭示预测因子-反应的关系,被称为特征工程。
—Xi 页,“特征工程与选择”,2019。
他们指出,我们无法知道使用最合适的数据表示来实现最佳的预测建模表现,从而激发了这本书。
我们可能需要系统地测试一套表示,以便发现什么最有效。这与我通常推荐的经验方法相匹配,这种方法很少被讨论,尽管在教科书中看到令人欣慰。
…我们通常不知道改善模型表现的预测因子的最佳再现。[……]我们可能需要搜索许多替代的预测器表示来提高模型表现。
—第十二页,“特征工程与选择”,2019 年。
鉴于数据准备对于在数据集上实现良好表现的重要性,本书重点强调了具体的数据准备技术以及如何使用这些技术。
特征工程和选择的目标是提供重新表示预测器的工具,将这些工具放在一个好的预测建模框架中,并传达我们在实践中使用这些工具的经验。
—第十二页,“特征工程与选择”,2019 年。
和他们之前的书一样,所有工作过的例子都在 R 中,在这种情况下,源代码可以从书的 GitHub 项目中获得。
此外,与前一本书不同,这本书的全部内容也可以在网上免费获得:
接下来,让我们仔细看看这本书涵盖的主题。
书的分解
这本书分为 12 章
它们是:
- 第一章。介绍
- 第二章。示例:预测缺血性中风的风险
- 第三章。预测建模过程综述
- 第四章。探索性可视化
- 第五章。编码分类预测因子
- 第六章。工程数字预测器
- 第七章。检测交互效果
- 第八章。处理丢失的数据
- 第九章。使用配置文件数据
- 第十章。功能选择概述
- 第十一章。贪婪搜索方法
- 第十二章。全局搜索方法
让我们仔细看看每一章。
第一章。介绍
介绍性章节很好地概述了预测建模的挑战。
它首先强调了描述性模型和预测性模型之间的重要区别。
…对特定值(如到达时间)的预测反映了一个估计问题,我们的目标不一定是了解趋势或事实是否真实,而是专注于对该值进行最准确的确定。预测中的不确定性是另一个重要的量,尤其是衡量模型生成的值的可信度。
—第 1 页,“特征工程与选择”,2019 年。
重要的是,这一章强调了数据准备的必要性,以便充分利用项目的预测模型。
在模型中有不同的方法来表示预测器,并且其中一些表示比其他的更好,这种想法导致了特征工程的想法——创建数据表示的过程,以提高模型的有效性。
—第 3 页,特征工程与选择,2019。
作为介绍,涵盖了许多您可能已经熟悉的基础主题,包括:
- 过拟合
- 监督和非监督程序
- 没有免费午餐
- 模型与建模过程
- 模型偏差和方差
- 经验驱动建模和经验驱动建模
- 大数据
我真的很喜欢他们指出预测建模过程的迭代本质。这不是其他地方经常讨论的数据传递。
在建模数据时,几乎从来没有一个单一的模型拟合或特征集可以立即解决问题。这个过程更有可能是一场反复试验以获得最佳结果的运动。
—第 16 页,“特征工程与选择”,2019 年。
我也很喜欢他们反复强调输入数据的所选表示对模型表现的影响,我们无法猜测给定的表示能让模型表现得多好。
特征集的影响可能比不同模型的影响大得多。模型和特性之间的相互作用是复杂的,有些不可预测。
—第 16 页,“特征工程与选择”,2019 年。
第二章。示例:预测缺血性中风的风险
顾名思义,本章旨在通过一个工作示例来具体说明预测建模的过程。
作为特征工程的入门,提供了一个带有建模过程的简短示例[……]为了说明起见,该示例将通过单个模型(逻辑回归)的镜头重点介绍探索、分析拟合和特征工程。
—第 21 页,特征工程与选择,2019。
第三章。预测建模过程综述
本章回顾了预测建模的过程,重点是数据准备如何以及在哪里适合这个过程。
它涵盖以下问题:
- 衡量绩效
- 数据分割
- 重采样
- 调整参数和过拟合
- 模型优化和调整
- 使用训练集比较模型
- 不过拟合的特征工程
本章的重要内容是,数据准备在流程中的应用至关重要,因为误用会导致数据泄露和过拟合。
为了使任何重采样方案产生推广到新数据的表现估计,它必须包含建模过程中可能显著影响模型有效性的所有步骤。
—第 54-55 页,“特征工程与选择”,2019 年。
解决方案是只在训练数据集上拟合数据准备,然后根据需要在测试集和其他数据集上应用拟合变换。当使用训练/测试分割和 k 倍交叉验证时,这是预测建模的最佳实践。
为了提供一个可靠的方法,我们应该限制自己开发预处理技术的列表,仅在训练数据点存在的情况下估计它们,然后将这些技术应用于未来的数据(包括测试集)。
—第 55 页,“特征工程与选择”,2019 年。
第四章。探索性可视化
本章重点介绍数据准备之前要执行的一个重要步骤,即仔细查看数据。
作者建议使用数据可视化技术来首先理解被预测的目标变量,然后关注输入变量。然后,这些信息可以用来通知要探索的数据准备方法的类型。
当最终目的是预测响应时,探索性数据过程的第一步之一是创建可视化,帮助阐明响应的知识,然后揭示预测者和响应之间的关系。
—第 65 页,“特征工程与选择”,2019 年。
第五章。编码分类预测因子
这一章着重于总结定性信息的分类变量的替代表示。
分类或名义预测是那些包含定性数据
—第 93 页,“特征工程与选择”,2019 年。
分类变量可能具有等级顺序关系(序数)或者没有这种关系(名义)。
简单的分类变量也可以分为有序变量和无序变量。[……]有序和无序因素可能需要不同的方法来将嵌入的信息包含在模型中。
—第 93 页,“特征工程与选择”,2019 年。
这包括虚拟变量、散列和嵌入等技术。
第六章。工程数字预测器
这一章着重于总结定量信息的数字变量的替代表示。
本章的目的是开发工具,将这些类型的预测器转换成模型可以更好利用的形式。
—第 121 页,“特征工程与选择”,2019 年。
我们可以通过数值变量观察到许多众所周知的问题,例如:
- 变量有不同的尺度。
- 偏斜概率分布。
- 异常值或极值。
- 双峰分布。
- 复杂的相互关系。
- 多余的信息。
有趣的是,作者代表了一套由每种方法对输入变量的影响组织的技术。也就是说,该方法是对一个输入变量还是多个输入变量进行操作,并产生单个结果还是多个结果,例如:
- 一对一
- 一对多
- 多对多
这包括许多方法,例如数据缩放、幂变换和投影方法。
第七章。检测交互效果
本章集中讨论一个经常被忽视的主题,即研究变量如何在数据集中相互作用。
从技术上来说,相互作用是指那些变量在一起比单独考虑变量时或多或少有影响。
对于许多问题,响应中的额外变化可以用两个或多个预测器相互协同工作的效果来解释。[……]更正式地说,如果两个或两个以上的预测因子的综合效应不同于(小于或大于)我们在单独考虑时将它们各自效应的影响相加的预期,则称它们相互作用。
—第 157 页,“特征工程与选择”,2019 年。
在数据准备的背景下,这一主题经常被忽略,因为人们通常认为预测建模中使用的学习算法将学习有助于预测目标变量的变量之间的任何相关相互关系。
第八章。处理丢失的数据
本章重点讨论可用数据中缺少观测值的问题。
这是一个重要的主题,因为大多数数据都有缺失或损坏的值,或者如果数据集按比例扩大,就会有缺失或损坏的值。
缺失数据在真实数据集中并不罕见。
—第 157 页,“特征工程与选择”,2019 年。
在回顾了数据缺失的原因和有助于理解数据集中缺失值的范围的数据可视化之后,本章通过三个主要解决方案展开讨论:
- 删除缺少值的数据。
- 对缺失值进行编码,以便模型可以了解它们。
- 从可用数据中估计缺失值。
第九章。使用配置文件数据
本章提供了剖面数据的数据准备方法的案例研究。
它可能命名不当,但与不同规模的依赖数据有关,例如,如何对给定数据集(例如,分层结构)上的日/周/月范围的数据进行有用的数据准备。
由于目标是进行每日预测,日内天气测量的概况应该以某种方式在日水平上以保留潜在预测信息的方式进行总结。对于这个例子,每日特征可以包括数字数据的平均值或中间值,并且可能包括一天内的数值范围。
—第 205 页,“特征工程与选择”,2019 年。
恐怕我觉得这完全没意思。但我相信,对于目前从事这类数据工作的人来说,这将是最有趣的一章。
第十章。功能选择概述
本章将特征选择的需求作为最相关输入的选择,而不是被预测的目标变量。
…有些可能与结果无关。[……]确实需要为建模适当地选择预测器。
—第 227 页,“特征工程与选择”,2019 年。
除了提升模型表现之外,选择更少的输入变量可以使模型更易于解释,尽管这通常是以牺牲模型技能为代价的。这是预测建模中常见的权衡。
……预测表现和可解释性之间往往存在权衡,通常不可能同时最大化两者。
—第 227 页,“特征工程与选择”,2019 年。
三种方法的框架用于组织特征选择方法,包括:
- 内在/隐含特征选择。
- 过滤特征选择。
- 包装特征选择。
特征选择方法分为三大类:内在(或隐含)方法、过滤方法和包装方法。
—第 228 页,“特征工程与选择”,2019 年。
剩下的两章也着重于特征选择。
第十一章。贪婪搜索方法
本章重点介绍一次评估一个要素,然后选择得分较高的要素子集的方法。
这包括计算输入和目标之间的统计关系强度的方法,以及重复从数据集中删除要素并在每个步骤评估模型的方法。
识别潜在预测性重要特征的简单方法是单独评估每个特征。[……]简单的过滤器是寻找个体预测因子的理想选择。然而,这种方法没有考虑到多个特性的影响。
—第 255 页,“特征工程与选择”,2019 年。
第十二章。全局搜索方法
本章重点介绍全局搜索算法,该算法根据适合这些特征的模型的表现来测试不同的特征子集。
全局搜索方法可以成为研究预测器空间和识别与响应最佳相关的预测器子集的有效工具。[……]虽然全局搜索方法通常能有效地找到好的特征集,但它们在计算上很费力。
—第 281 页,“特征工程与选择”,2019 年。
这包括众所周知的全局随机搜索算法,如模拟退火和遗传算法。
对这本书的最后思考
我认为这是数据准备方面急需的缺失教材。
我也认为,如果你是一个认真的机器学习实践者,你需要一个副本。
如果你对机器学习的 R 和 Python 都很熟悉,这本书强调了像 Python/Sklearn 这样的库要赶上 R/caret 生态系统还有多远。
说到数据准备,我认为工作示例不如演示算法时有用。也许只是我和我的喜好。考虑到每个数据集在数量、类型和要素组成方面的差异,在标准数据集上演示数据准备并不是一个有用的教学辅助工具。
我更喜欢的是更系统地涵盖我们在原始数据中可能看到的建模问题,以及每种数据准备方法如何解决这些问题。我喜欢一个长长的方法目录,它们是如何工作的,什么时候使用它们,而不是每种方法的散文。
无论如何,这只是我在努力推动如何让这本书变得更好,或者对材料的另一种看法。毫无疑问,这是必备的。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
- 特征工程和选择:预测模型的实用方法,2019。
- 应用预测建模,2013。
- 特征工程与选择,官网。
- 功能工程与选择,GitHub 。
摘要
在这篇文章中,你发现了我对《特征工程与选择》一书的评论和分解,该书的主题是机器学习的数据准备。
你读过这本书吗? 在下面的评论中告诉我你对它的看法。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
如何为机器学习在表格数据上使用特征提取
最后更新于 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,)
接下来,让我们在这个数据集上评估一个模型,并建立一个表现基线。
基线模型表现
我们可以通过评估原始输入数据的模型来建立葡萄酒分类任务的表现基线。
在这种情况下,我们将评估逻辑回归模型。
首先,我们可以通过确保输入变量是数字的并且目标变量是标签编码的来执行最少的数据准备工作,正如 Sklearn 库所期望的那样。
...
# minimally prepare dataset
X = X.astype('float')
y = LabelEncoder().fit_transform(y.astype('str'))
接下来,我们可以定义我们的预测模型。
...
# define the model
model = LogisticRegression(solver='liblinear')
我们将使用重复分层 k-fold 交叉验证的金标准对模型进行评估,重复 10 次,重复 3 次。
将使用分类准确度评估模型表现。
...
model = LogisticRegression(solver='liblinear')
# 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)
在运行结束时,我们将报告在所有重复和评估折叠中收集的准确度分数的平均值和标准偏差。
...
# 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
# 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'))
# define the model
model = LogisticRegression(solver='liblinear')
# 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)
# report performance
print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))
运行该示例评估模型表现,并报告平均和标准偏差分类准确率。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到,适合原始输入数据的逻辑回归模型实现了大约 95.3%的平均分类准确率,提供了表现基线。
Accuracy: 0.953 (0.048)
接下来,让我们探索是否可以使用基于特征提取的数据准备方法来提高表现。
数据准备的特征提取方法
在本节中,我们可以探索是否可以使用特征提取方法来提高数据准备的表现。
第一步是选择一套常见且常用的数据准备技术。
在这种情况下,假设输入变量是数字,我们将使用一系列转换来更改输入变量的比例,如最小最大缩放器、标准缩放器和鲁棒缩放器,以及用于链接输入变量分布的转换,如量化转换器和kbins 离散器。最后,我们还将使用消除输入变量之间线性依赖关系的变换,如主成分分析和截断变量。
功能联合类可用于定义要执行的转换列表,其结果将被聚合在一起,即联合。这将创建一个包含大量列的新数据集。
列数的估计是 13 个输入变量乘以 5 个变换,或者 65 加上从主成分分析和奇异值分解降维方法输出的 14 列,得到总共约 79 个特征。
...
# transforms for the feature union
transforms = list()
transforms.append(('mms', MinMaxScaler()))
transforms.append(('ss', StandardScaler()))
transforms.append(('rs', RobustScaler()))
transforms.append(('qt', QuantileTransformer(n_quantiles=100, output_distribution='normal')))
transforms.append(('kbd', KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')))
transforms.append(('pca', PCA(n_components=7)))
transforms.append(('svd', TruncatedSVD(n_components=7)))
# create the feature union
fu = FeatureUnion(transforms)
然后我们可以创建一个建模管道,第一步是特征联合,最后一步是逻辑回归模型。
...
# define the model
model = LogisticRegression(solver='liblinear')
# define the pipeline
steps = list()
steps.append(('fu', fu))
steps.append(('m', model))
pipeline = Pipeline(steps=steps)
然后可以像以前一样,使用重复的分层 k-fold 交叉验证来评估管道。
将这些联系在一起,完整的示例如下所示。
# data preparation as feature engineering for wine 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.pipeline import FeatureUnion
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import RobustScaler
from sklearn.preprocessing import QuantileTransformer
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.decomposition import PCA
from sklearn.decomposition import TruncatedSVD
# 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'))
# transforms for the feature union
transforms = list()
transforms.append(('mms', MinMaxScaler()))
transforms.append(('ss', StandardScaler()))
transforms.append(('rs', RobustScaler()))
transforms.append(('qt', QuantileTransformer(n_quantiles=100, output_distribution='normal')))
transforms.append(('kbd', KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')))
transforms.append(('pca', PCA(n_components=7)))
transforms.append(('svd', TruncatedSVD(n_components=7)))
# create the feature union
fu = FeatureUnion(transforms)
# define the model
model = LogisticRegression(solver='liblinear')
# define the pipeline
steps = list()
steps.append(('fu', fu))
steps.append(('m', model))
pipeline = Pipeline(steps=steps)
# define the cross-validation procedure
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)
# report performance
print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))
运行该示例评估模型表现,并报告平均和标准偏差分类准确率。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到表现比基线表现有所提升,平均分类准确率约为 96.8%,而上一节为 95.3%。
Accuracy: 0.968 (0.037)
尝试向 FeatureUnion 添加更多数据准备方法,看看是否可以提高表现。
能不能取得更好的表现? 让我知道你在下面的评论中发现了什么。
我们还可以使用特征选择将大约 80 个提取的特征减少到与模型最相关的那些特征的子集。除了降低模型的复杂性,它还可以通过移除不相关和冗余的输入特征来提升表现。
在这种情况下,我们将使用递归特征消除或 RFE 技术进行特征选择,并将其配置为选择 15 个最相关的特征。
...
# define the feature selection
rfe = RFE(estimator=LogisticRegression(solver='liblinear'), n_features_to_select=15)
然后,我们可以在特征联合之后和物流配送算法之前,将 RFE 特征选择添加到建模管道中。
...
# define the pipeline
steps = list()
steps.append(('fu', fu))
steps.append(('rfe', rfe))
steps.append(('m', model))
pipeline = Pipeline(steps=steps)
将这些结合在一起,下面列出了带有特征选择的特征选择数据准备方法的完整示例。
# data preparation as feature engineering with feature selection for wine 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.pipeline import FeatureUnion
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler
from sklearn.preprocessing import RobustScaler
from sklearn.preprocessing import QuantileTransformer
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.feature_selection import RFE
from sklearn.decomposition import PCA
from sklearn.decomposition import TruncatedSVD
# 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'))
# transforms for the feature union
transforms = list()
transforms.append(('mms', MinMaxScaler()))
transforms.append(('ss', StandardScaler()))
transforms.append(('rs', RobustScaler()))
transforms.append(('qt', QuantileTransformer(n_quantiles=100, output_distribution='normal')))
transforms.append(('kbd', KBinsDiscretizer(n_bins=10, encode='ordinal', strategy='uniform')))
transforms.append(('pca', PCA(n_components=7)))
transforms.append(('svd', TruncatedSVD(n_components=7)))
# create the feature union
fu = FeatureUnion(transforms)
# define the feature selection
rfe = RFE(estimator=LogisticRegression(solver='liblinear'), n_features_to_select=15)
# define the model
model = LogisticRegression(solver='liblinear')
# define the pipeline
steps = list()
steps.append(('fu', fu))
steps.append(('rfe', rfe))
steps.append(('m', model))
pipeline = Pipeline(steps=steps)
# define the cross-validation procedure
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)
# report performance
print('Accuracy: %.3f (%.3f)' % (mean(scores), std(scores)))
运行该示例评估模型表现,并报告平均和标准偏差分类准确率。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
同样,我们可以看到表现进一步提升,从所有提取特征的 96.8%提升到建模前使用特征选择的 98.9%左右。
Accuracy: 0.989 (0.022)
使用不同的特征选择技术,或者选择更多或更少的特征,可以获得更好的表现吗? 让我知道你在下面的评论中发现了什么。
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
相关教程
书
蜜蜂
摘要
在本教程中,您发现了如何使用特征提取来准备表格数据。
具体来说,您了解到:
- 特征提取为表格数据的数据准备提供了一种替代方法,其中所有数据转换并行应用于原始输入数据,并组合在一起创建一个大型数据集。
- 如何使用数据准备的特征提取方法来提高标准类别数据集的模型表现。
- 如何将特征选择添加到特征提取建模管道中,以进一步提升标准数据集的建模表现。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
如何对回归数据执行特征选择
最后更新于 2020 年 8 月 18 日
特征选择是识别和选择与目标变量最相关的输入变量子集的过程。
也许特征选择最简单的情况是有数值输入变量和回归预测建模的数值目标的情况。这是因为可以计算每个输入变量和目标之间的关系强度,称为相关性,并相互进行比较。
在本教程中,您将了解如何使用回归预测建模的数字输入数据执行特征选择。
完成本教程后,您将知道:
- 如何利用相关和互信息统计评估数值输入数据的重要性?
- 拟合和评估回归模型时,如何对数值输入数据进行特征选择。
- 如何使用网格搜索调整建模管道中所选要素的数量。
用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
如何对回归数据进行特征选择丹尼斯·贾维斯摄,版权所有。
教程概述
本教程分为四个部分;它们是:
- 回归数据集
- 数字特征选择
- 相关特征选择
- 互信息特征选择
- 使用选定特征建模
- 使用所有功能构建的模型
- 使用相关特征构建的模型
- 利用互信息特征建立的模型
- 调整选定特征的数量
回归数据集
我们将使用合成回归数据集作为本教程的基础。
回想一下,回归问题是一个我们想要预测数值的问题。在这种情况下,我们需要一个也有数字输入变量的数据集。
Sklearn 库中的make _ revolution()函数可用于定义数据集。它提供了对样本数量、输入特征数量以及重要的相关和冗余输入特征数量的控制。这一点至关重要,因为我们特别希望数据集具有一些冗余的输入特征。
在这种情况下,我们将定义一个包含 1000 个样本的数据集,每个样本包含 100 个输入要素,其中 10 个是信息性的,其余 90 个是冗余的。
...
# generate regression dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
希望特征选择技术能够识别与目标相关的部分或全部特征,或者至少识别并去除一些冗余的输入特征。
一旦定义好,我们就可以将数据分成训练集和测试集,这样我们就可以拟合和评估一个学习模型。
我们将使用 train_test_split()函数形成 Sklearn,并将 67%的数据用于训练,33%的数据用于测试。
...
# 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 sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
# generate regression dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# 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)
运行该示例会报告训练集和测试集的输入和输出元素的大小。
我们可以看到,我们有 670 个示例用于培训,330 个示例用于测试。
Train (670, 100) (670,)
Test (330, 100) (330,)
现在我们已经加载并准备好数据集,我们可以探索特征选择。
数字特征选择
有两种流行的特征选择技术可用于数值输入数据和数值目标变量。
它们是:
- 相关性统计。
- 相互信息统计。
让我们依次仔细看看每一个。
相关特征选择
相关性是衡量两个变量如何一起变化的指标。也许最常见的相关度量是皮尔逊相关,假设每个变量呈高斯分布,并报告它们的线性关系。
对于数字预测,量化每种关系和结果的经典方法是使用样本相关统计量。
—第 464 页,应用预测建模,2013 年。
有关线性或参数相关的更多信息,请参见教程:
线性相关分数通常是介于-1 和 1 之间的值,0 表示没有关系。对于特征选择,我们通常对正值感兴趣,正值越大,关系越大,更有可能的是,特征应该被选择用于建模。这样,线性相关可以被转换成仅具有正值的相关统计。
Sklearn 机器库提供了相关统计在f _ revolution()函数中的实现。该功能可用于特征选择策略,例如通过选择最相关的前 k 个特征(最大值)。
例如,我们可以定义 SelectKBest 类来使用*f _ revolution()*函数并选择所有特征,然后转换火车和测试集。
...
# configure to select all features
fs = SelectKBest(score_func=f_regression, 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
然后,我们可以打印每个变量的分数(越大越好),并将每个变量的分数绘制成条形图,以了解我们应该选择多少特征。
...
# 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 correlation feature selection for numerical data
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_regression
from matplotlib import pyplot
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select all features
fs = SelectKBest(score_func=f_regression, 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 = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# 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()
运行该示例首先打印为每个输入要素和目标变量计算的分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
我们不会列出所有 100 个输入变量的分数,因为这会占用太多空间。然而,我们可以看到一些变量比其他变量得分更高,例如小于 1 比 5,而其他变量得分更高,例如特征 9 的得分为 101。
Feature 0: 0.009419
Feature 1: 1.018881
Feature 2: 1.205187
Feature 3: 0.000138
Feature 4: 0.167511
Feature 5: 5.985083
Feature 6: 0.062405
Feature 7: 1.455257
Feature 8: 0.420384
Feature 9: 101.392225
...
创建每个输入要素的要素重要性得分的条形图。
该图清楚地显示了 8 到 10 个特征比其他特征重要得多。
我们可以在配置选择测试时设置 k=10 来选择这些顶级功能。
输入特征条形图(x)与相关特征重要性条形图(y)
互信息特征选择
信息论领域的互信息是信息增益(通常用于决策树的构建)在特征选择中的应用。
计算两个变量之间的互信息,并在已知另一个变量的值的情况下,测量一个变量不确定性的减少。
您可以在下面的教程中了解更多关于相互信息的信息。
当考虑两个离散(分类或序数)变量的分布时,如分类输入和分类输出数据,互信息是直接的。然而,它可以适用于数字输入和输出数据。
有关如何实现这一点的技术细节,请参见 2014 年发表的题为“离散数据集和连续数据集之间的相互信息”的论文
Sklearn 机器学习库通过mutual _ info _ revolution()函数为特征选择提供了一个带有数字输入和输出变量的互信息实现。
和*f _ revolution()*一样,可以在 SelectKBest 特征选择策略(和其他策略)中使用。
...
# configure to select all features
fs = SelectKBest(score_func=mutual_info_regression, 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
我们可以使用数据集的互信息来执行特征选择,并打印和绘制分数(越大越好),就像我们在上一节中所做的那样。
下面列出了使用互信息进行数字特征选择的完整示例。
# example of mutual information feature selection for numerical input data
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_regression
from matplotlib import pyplot
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select all features
fs = SelectKBest(score_func=mutual_info_regression, 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 = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# 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()
运行该示例首先打印为每个输入要素和目标变量计算的分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
同样,我们不会列出所有 100 个输入变量的分数。我们可以看到许多特性的得分为 0.0,而这项技术已经识别了更多可能与目标相关的特性。
Feature 0: 0.045484
Feature 1: 0.000000
Feature 2: 0.000000
Feature 3: 0.000000
Feature 4: 0.024816
Feature 5: 0.000000
Feature 6: 0.022659
Feature 7: 0.000000
Feature 8: 0.000000
Feature 9: 0.074320
...
创建每个输入要素的要素重要性得分的条形图。
与相关特征选择方法相比,我们可以清楚地看到更多被评分为相关的特征。这可能是因为我们在构建数据集时添加了统计噪声。
输入特征条形图(x)与互信息特征重要性条形图(y)
既然我们知道了如何对回归预测建模问题的数值输入数据执行特征选择,我们可以尝试使用所选特征开发模型并比较结果。
使用选定特征建模
有许多不同的技术用于对特征进行评分和基于评分选择特征;你怎么知道用哪个?
一种稳健的方法是使用不同的特征选择方法(和特征数量)来评估模型,并选择产生具有最佳表现的模型的方法。
在本节中,我们将评估一个线性回归模型,将所有特征与通过相关统计选择的特征和通过互信息选择的特征构建的模型进行比较。
线性回归是测试特征选择方法的好模型,因为如果从模型中移除不相关的特征,它可以表现得更好。
使用所有功能构建的模型
作为第一步,我们将使用所有可用的特征评估线性回归模型。
该模型适合训练数据集,并在测试数据集上进行评估。
下面列出了完整的示例。
# evaluation of a model using all input features
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
# load the dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# 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 = LinearRegression()
model.fit(X_train, y_train)
# evaluate the model
yhat = model.predict(X_test)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)
运行该示例将打印训练数据集中模型的平均绝对误差(MAE)。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到模型实现了大约 0.086 的误差。
我们更喜欢使用一个特征子集,它能达到和这个一样好或者更好的误差。
MAE: 0.086
使用相关特征构建的模型
我们可以使用相关性方法对特征进行评分,并选择 10 个最相关的特征。
下面的 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_regression, k=10)
# 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 10 features chosen with correlation
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_regression
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select a subset of features
fs = SelectKBest(score_func=f_regression, k=10)
# 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 = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# 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 = LinearRegression()
model.fit(X_train_fs, y_train)
# evaluate the model
yhat = model.predict(X_test_fs)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)
运行该示例会报告模型在使用相关性统计信息选择的 100 个输入要素中的 10 个要素上的表现。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们看到模型获得了大约 2.7 的误差分数,这比使用所有特征并获得 0.086 的 MAE 的基线模型大得多。
这表明,尽管该方法对于选择什么特征有很强的想法,但是仅从这些特征构建模型并不能产生更熟练的模型。这可能是因为对目标很重要的特征被忽略了,这意味着方法在什么是重要的问题上被欺骗了。
MAE: 2.740
让我们走另一条路,尝试使用方法删除一些冗余特征,而不是所有冗余特征。
我们可以通过将所选特征的数量设置为更大的值来实现这一点,在本例中为 88 个,希望它可以找到并丢弃 90 个冗余特征中的 12 个。
下面列出了完整的示例。
# evaluation of a model using 88 features chosen with correlation
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_regression
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select a subset of features
fs = SelectKBest(score_func=f_regression, k=88)
# 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 = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# 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 = LinearRegression()
model.fit(X_train_fs, y_train)
# evaluate the model
yhat = model.predict(X_test_fs)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)
运行该示例会报告模型在使用相关性统计信息选择的 100 个输入要素中的 88 个要素上的表现。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到,删除一些冗余功能导致了表现的小幅提升,与实现约 0.086 误差的基线相比,误差约为 0.085。
MAE: 0.085
利用互信息特征建立的模型
我们可以重复实验,并使用互信息统计选择前 88 个特征。
下面列出了实现此功能的 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_regression, k=88)
# 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 88 features chosen with mutual information
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_regression
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
# feature selection
def select_features(X_train, y_train, X_test):
# configure to select a subset of features
fs = SelectKBest(score_func=mutual_info_regression, k=88)
# 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 = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# 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 = LinearRegression()
model.fit(X_train_fs, y_train)
# evaluate the model
yhat = model.predict(X_test_fs)
# evaluate predictions
mae = mean_absolute_error(y_test, yhat)
print('MAE: %.3f' % mae)
运行该示例使模型适合使用互信息选择的 88 个顶级精选要素。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,与相关统计相比,我们可以看到误差进一步减小,在这种情况下,与上一节中的 0.085 相比,MAE 约为 0.084。
MAE: 0.084
调整选定特征的数量
在前面的例子中,我们选择了 88 个特征,但是我们如何知道这是一个好的或者最好的特征选择数量呢?
代替猜测,我们可以系统地测试一系列不同数量的所选特征,并发现哪一个导致最佳表现的模型。这被称为网格搜索,其中可以调整 SelectKBest 类的 k 参数。
使用重复分层 K 折交叉验证来评估回归任务的模型配置是一个很好的实践。我们将通过 RepeatedKFold 类使用三次重复的 10 倍交叉验证。
...
# define the evaluation method
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
我们可以定义一个管道,它可以在训练集上正确准备特征选择变换,并将其应用于交叉验证的每个折叠的训练集和测试集。
在这种情况下,我们将使用互信息统计方法来选择特征。
...
# define the pipeline to evaluate
model = LinearRegression()
fs = SelectKBest(score_func=mutual_info_regression)
pipeline = Pipeline(steps=[('sel',fs), ('lr', model)])
然后,我们可以将评估值的网格定义为 80 到 100。
请注意,网格是要搜索的参数到值的字典映射,假设我们使用的是管道,我们可以通过我们给它起的名称“ sel ”来访问 SelectKBest 对象,然后是由两个下划线分隔的参数名称“ k ,或者“ sel__k ”。
...
# define the grid
grid = dict()
grid['sel__k'] = [i for i in range(X.shape[1]-20, X.shape[1]+1)]
然后,我们可以定义并运行搜索。
在这种情况下,我们将使用负平均绝对误差( neg_mean_absolute_error )来评估模型。它是负的,因为 Sklearn 要求分数最大化,所以 MAE 是负的,这意味着分数从-无穷大到 0(最佳)。
...
# define the grid search
search = GridSearchCV(pipeline, grid, scoring='neg_mean_absolure_error', n_jobs=-1, cv=cv)
# perform the search
results = search.fit(X, y)
将这些联系在一起,完整的示例如下所示。
# compare different numbers of features selected using mutual information
from sklearn.datasets import make_regression
from sklearn.model_selection import RepeatedKFold
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_regression
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
# define dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# define the evaluation method
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
# define the pipeline to evaluate
model = LinearRegression()
fs = SelectKBest(score_func=mutual_info_regression)
pipeline = Pipeline(steps=[('sel',fs), ('lr', model)])
# define the grid
grid = dict()
grid['sel__k'] = [i for i in range(X.shape[1]-20, X.shape[1]+1)]
# define the grid search
search = GridSearchCV(pipeline, grid, scoring='neg_mean_squared_error', n_jobs=-1, cv=cv)
# perform the search
results = search.fit(X, y)
# summarize best
print('Best MAE: %.3f' % results.best_score_)
print('Best Config: %s' % results.best_params_)
# summarize all
means = results.cv_results_['mean_test_score']
params = results.cv_results_['params']
for mean, param in zip(means, params):
print(">%.3f with: %r" % (mean, param))
运行示例网格使用互信息统计搜索不同数量的选定要素,其中使用重复交叉验证评估每个建模管道。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到所选特征的最佳数量是 81,这实现了大约 0.082 的 MAE(忽略符号)。
Best MAE: -0.082
Best Config: {'sel__k': 81}
>-1.100 with: {'sel__k': 80}
>-0.082 with: {'sel__k': 81}
>-0.082 with: {'sel__k': 82}
>-0.082 with: {'sel__k': 83}
>-0.082 with: {'sel__k': 84}
>-0.082 with: {'sel__k': 85}
>-0.082 with: {'sel__k': 86}
>-0.082 with: {'sel__k': 87}
>-0.082 with: {'sel__k': 88}
>-0.083 with: {'sel__k': 89}
>-0.083 with: {'sel__k': 90}
>-0.083 with: {'sel__k': 91}
>-0.083 with: {'sel__k': 92}
>-0.083 with: {'sel__k': 93}
>-0.083 with: {'sel__k': 94}
>-0.083 with: {'sel__k': 95}
>-0.083 with: {'sel__k': 96}
>-0.083 with: {'sel__k': 97}
>-0.083 with: {'sel__k': 98}
>-0.083 with: {'sel__k': 99}
>-0.083 with: {'sel__k': 100}
我们可能希望看到所选特征的数量和 MAE 之间的关系。在这种关系中,在某种程度上,我们可能期望更多的特性导致更好的表现。
这种关系可以通过手动评估从 81 到 100 的 SelectKBest 的 k 的每个配置,收集 MAE 分数的样本,并使用方框图和晶须图并排绘制结果来探索。这些箱线图的分布和平均值将显示所选要素的数量和管道的 MAE 之间的任何有趣关系。
请注意,我们是在 81 而不是 80 开始传播 k 值的,因为 k=80 的 MAE 分数的分布比所考虑的所有其他 k 值都要大得多,并且它冲掉了图表上的结果图。
下面列出了实现这一点的完整示例。
# compare different numbers of features selected using mutual information
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_regression
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
from matplotlib import pyplot
# define dataset
X, y = make_regression(n_samples=1000, n_features=100, n_informative=10, noise=0.1, random_state=1)
# define number of features to evaluate
num_features = [i for i in range(X.shape[1]-19, X.shape[1]+1)]
# enumerate each number of features
results = list()
for k in num_features:
# create pipeline
model = LinearRegression()
fs = SelectKBest(score_func=mutual_info_regression, k=k)
pipeline = Pipeline(steps=[('sel',fs), ('lr', model)])
# evaluate the model
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
scores = cross_val_score(pipeline, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1)
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()
运行该示例首先报告每个选定特征的平均值和标准偏差。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,报告 MAE 的平均值和标准差不是很有趣,除了 80 年代的 k 值比 90 年代的 k 值更好。
>81 -0.082 (0.006)
>82 -0.082 (0.006)
>83 -0.082 (0.006)
>84 -0.082 (0.006)
>85 -0.082 (0.006)
>86 -0.082 (0.006)
>87 -0.082 (0.006)
>88 -0.082 (0.006)
>89 -0.083 (0.006)
>90 -0.083 (0.006)
>91 -0.083 (0.006)
>92 -0.083 (0.006)
>93 -0.083 (0.006)
>94 -0.083 (0.006)
>95 -0.083 (0.006)
>96 -0.083 (0.006)
>97 -0.083 (0.006)
>98 -0.083 (0.006)
>99 -0.083 (0.006)
>100 -0.083 (0.006)
并排创建方框图和须图,显示 k 与 MAE 的趋势,其中绿色三角形代表平均值,橙色线代表分布的中值。
使用互信息的每个选定特征的 MAE 方框图和触须图
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
教程
书
- 应用预测建模,2013。
蜜蜂
- 功能选择,sci kit-学习用户指南。
- sklearn . datasets . make _ revolution API。
- sklearn . feature _ selection . f _ 回归 API 。
- sklearn . feature _ selection . mutual _ info _ revolution API。
文章
摘要
在本教程中,您发现了如何使用回归预测建模的数字输入数据执行特征选择。
具体来说,您了解到:
- 如何利用相关和互信息统计评估数值输入数据的重要性?
- 拟合和评估回归模型时,如何对数值输入数据进行特征选择。
- 如何使用网格搜索调整建模管道中所选要素的数量。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。
如何对类别数据执行特征选择
最后更新于 2020 年 8 月 18 日
特征选择是识别和选择与目标变量最相关的输入特征子集的过程。
在处理实值数据时,特征选择通常很简单,例如使用皮尔逊相关系数,但在处理类别数据时可能很有挑战性。
当目标变量也是分类的时,分类输入数据最常用的两种特征选择方法是卡方统计和互信息统计。
在本教程中,您将了解如何使用分类输入数据执行要素选择。
完成本教程后,您将知道:
- 具有分类输入和二分类目标变量的乳腺癌预测建模问题。
- 如何利用卡方统计和互信息统计评估分类特征的重要性。
- 在拟合和评估分类模型时,如何对类别数据进行特征选择。
用我的新书机器学习的数据准备启动你的项目,包括分步教程和所有示例的 Python 源代码文件。
我们开始吧。
如何使用类别数据进行特征选择 图片由菲尔杜比提供,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 乳腺癌类别数据集
- 分类特征选择
- 卡方特征选择
- 互信息特征选择
- 使用选定特征建模
- 使用所有功能构建的模型
- 使用卡方特征建立的模型
- 利用互信息特征建立的模型
乳腺癌类别数据集
作为本教程的基础,我们将使用自 20 世纪 80 年代以来作为机器学习数据集被广泛研究的所谓的“乳腺癌”数据集。
数据集将乳腺癌患者数据分类为癌症复发或不复发。有 286 个例子和 9 个输入变量。这是一个二分类问题。
一个简单的模型在这个数据集上可以达到 70%的准确率。好的分数大约是 76% +/- 3%。我们将针对该地区,但请注意,本教程中的模型没有优化;它们旨在演示编码方案。
您可以下载数据集,并将文件保存为当前工作目录中的“乳腺癌. csv ”。
查看数据,我们可以看到所有九个输入变量都是绝对的。
具体来说,所有变量都是带引号的字符串;有些是序数,有些不是。
'40-49','premeno','15-19','0-2','yes','3','right','left_up','no','recurrence-events'
'50-59','ge40','15-19','0-2','no','1','right','central','no','no-recurrence-events'
'50-59','ge40','35-39','0-2','no','2','left','left_low','no','recurrence-events'
'40-49','premeno','35-39','0-2','yes','3','right','left_low','yes','no-recurrence-events'
'40-49','premeno','30-34','3-5','yes','2','left','right_up','no','recurrence-events'
...
我们可以使用熊猫库将这个数据集加载到内存中。
...
# load the dataset as a pandas DataFrame
data = read_csv(filename, header=None)
# retrieve numpy array
dataset = data.values
加载后,我们可以将列拆分为输入( X )和输出进行建模。
...
# split into input (X) and output (y) variables
X = dataset[:, :-1]
y = dataset[:,-1]
最后,我们可以强制输入数据中的所有字段都是字符串,以防 Pandas 尝试自动将一些字段映射到数字(它确实尝试了)。
...
# format all fields as string
X = X.astype(str)
我们可以将所有这些结合到一个有用的函数中,以便以后重用。
# 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]
# format all fields as string
X = X.astype(str)
return X, y
加载后,我们可以将数据分成训练集和测试集,这样我们就可以拟合和评估学习模型。
我们将使用 train_test_split()函数形成 Sklearn,使用 67%的数据进行训练,33%的数据进行测试。
...
# load the dataset
X, y = load_dataset('breast-cancer.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]
# format all fields as string
X = X.astype(str)
return X, y
# load the dataset
X, y = load_dataset('breast-cancer.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)
运行该示例会报告训练集和测试集的输入和输出元素的大小。
我们可以看到,我们有 191 个示例用于培训,95 个示例用于测试。
Train (191, 9) (191, 1)
Test (95, 9) (95, 1)
现在我们已经熟悉了数据集,让我们看看如何对它进行编码以进行建模。
我们可以使用 Sklearn 中的序数编码器()将每个变量编码为整数。这是一个灵活的类,如果已知任何这样的顺序,它确实允许将类别的顺序指定为参数。
注:我将把它作为一个练习留给你来更新下面的例子,尝试为那些具有自然顺序的变量指定顺序,看看它是否对模型表现有影响。
对变量进行编码的最佳实践是在训练数据集上进行编码,然后将其应用于训练和测试数据集。
下面名为 prepare_inputs() 的函数获取列车和测试集的输入数据,并使用顺序编码对其进行编码。
# prepare input data
def prepare_inputs(X_train, X_test):
oe = OrdinalEncoder()
oe.fit(X_train)
X_train_enc = oe.transform(X_train)
X_test_enc = oe.transform(X_test)
return X_train_enc, X_test_enc
我们还需要准备目标变量。
这是一个二分类问题,所以我们需要将两个类标签映射为 0 和 1。这是一种序数编码,Sklearn 提供了专门为此目的设计的 LabelEncoder 类。虽然标签编码器是为编码单个变量而设计的,但是我们也可以很容易地使用普通编码器来获得同样的结果。
prepare_targets() 函数对列车和测试集的输出数据进行整数编码。
# prepare target
def prepare_targets(y_train, y_test):
le = LabelEncoder()
le.fit(y_train)
y_train_enc = le.transform(y_train)
y_test_enc = le.transform(y_test)
return y_train_enc, y_test_enc
我们可以调用这些函数来准备我们的数据。
...
# prepare input data
X_train_enc, X_test_enc = prepare_inputs(X_train, X_test)
# prepare output data
y_train_enc, y_test_enc = prepare_targets(y_train, y_test)
将所有这些结合起来,下面列出了为乳腺癌类别数据集加载和编码输入和输出变量的完整示例。
# example of loading and preparing the breast cancer dataset
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OrdinalEncoder
# 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]
# format all fields as string
X = X.astype(str)
return X, y
# prepare input data
def prepare_inputs(X_train, X_test):
oe = OrdinalEncoder()
oe.fit(X_train)
X_train_enc = oe.transform(X_train)
X_test_enc = oe.transform(X_test)
return X_train_enc, X_test_enc
# prepare target
def prepare_targets(y_train, y_test):
le = LabelEncoder()
le.fit(y_train)
y_train_enc = le.transform(y_train)
y_test_enc = le.transform(y_test)
return y_train_enc, y_test_enc
# load the dataset
X, y = load_dataset('breast-cancer.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)
# prepare input data
X_train_enc, X_test_enc = prepare_inputs(X_train, X_test)
# prepare output data
y_train_enc, y_test_enc = prepare_targets(y_train, y_test)
现在我们已经加载并准备了乳腺癌数据集,我们可以探索特征选择。
分类特征选择
有两种流行的特征选择技术可用于分类输入数据和分类(类)目标变量。
它们是:
- 卡方统计量。
- 互信息统计。
让我们依次仔细看看每一个。
卡方特征选择
皮尔逊的卡方统计假设检验是分类变量之间独立性检验的一个例子。
您可以在教程中了解有关此统计测试的更多信息:
该测试的结果可用于特征选择,其中那些独立于目标变量的特征可从数据集中移除。
当预测因子有三个或三个以上的水平时,预测因子和结果之间的关联程度可以用统计学方法来衡量,如 X2(卡方)检验…
—第 242 页,特征工程与选择,2019。
Sklearn 机器库提供了 chi2()函数中卡方测试的实现。该功能可用于特征选择策略,例如通过选择最相关的特征(最大值)选择最相关的 k 类。
例如,我们可以定义 SelectKBest 类来使用 chi2() 功能并选择所有特征,然后转换列车和测试集。
...
fs = SelectKBest(score_func=chi2, k='all')
fs.fit(X_train, y_train)
X_train_fs = fs.transform(X_train)
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 chi squared feature selection for categorical data
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OrdinalEncoder
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
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]
# format all fields as string
X = X.astype(str)
return X, y
# prepare input data
def prepare_inputs(X_train, X_test):
oe = OrdinalEncoder()
oe.fit(X_train)
X_train_enc = oe.transform(X_train)
X_test_enc = oe.transform(X_test)
return X_train_enc, X_test_enc
# prepare target
def prepare_targets(y_train, y_test):
le = LabelEncoder()
le.fit(y_train)
y_train_enc = le.transform(y_train)
y_test_enc = le.transform(y_test)
return y_train_enc, y_test_enc
# feature selection
def select_features(X_train, y_train, X_test):
fs = SelectKBest(score_func=chi2, k='all')
fs.fit(X_train, y_train)
X_train_fs = fs.transform(X_train)
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
# load the dataset
X, y = load_dataset('breast-cancer.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)
# prepare input data
X_train_enc, X_test_enc = prepare_inputs(X_train, X_test)
# prepare output data
y_train_enc, y_test_enc = prepare_targets(y_train, y_test)
# feature selection
X_train_fs, X_test_fs, fs = select_features(X_train_enc, y_train_enc, X_test_enc)
# 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()
运行该示例首先打印为每个输入要素和目标变量计算的分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到分数很小,很难仅从数字中得出哪个特征更相关的想法。
也许特性 3、4、5 和 8 最相关。
Feature 0: 0.472553
Feature 1: 0.029193
Feature 2: 2.137658
Feature 3: 29.381059
Feature 4: 8.222601
Feature 5: 8.100183
Feature 6: 1.273822
Feature 7: 0.950682
Feature 8: 3.699989
创建每个输入要素的要素重要性得分的条形图。
这清楚地表明特征 3 可能是最相关的(根据卡方),并且九个输入特征中可能有四个是最相关的。
我们可以在配置选择测试时设置 k=4,以选择前四个特征。
输入要素条形图(x)与卡方要素重要性条形图(y)
互信息特征选择
信息论领域的互信息是信息增益(通常用于构造决策树)在特征选择中的应用。
计算两个变量之间的互信息,并在已知另一个变量的值的情况下,测量一个变量不确定性的减少。
您可以在下面的教程中了解更多关于相互信息的信息。
Sklearn 机器学习库通过 mutual_info_classif()函数为特征选择提供了一个互信息的实现。
和 chi2() 一样,可以在 SelectKBest 特征选择策略(和其他策略)中使用。
# feature selection
def select_features(X_train, y_train, X_test):
fs = SelectKBest(score_func=mutual_info_classif, k='all')
fs.fit(X_train, y_train)
X_train_fs = fs.transform(X_train)
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
我们可以使用乳腺癌集的互信息来执行特征选择,并打印和绘制分数(越大越好),就像我们在上一节中所做的那样。
下面列出了使用互信息进行分类特征选择的完整示例。
# example of mutual information feature selection for categorical data
from pandas import read_csv
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OrdinalEncoder
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]
# format all fields as string
X = X.astype(str)
return X, y
# prepare input data
def prepare_inputs(X_train, X_test):
oe = OrdinalEncoder()
oe.fit(X_train)
X_train_enc = oe.transform(X_train)
X_test_enc = oe.transform(X_test)
return X_train_enc, X_test_enc
# prepare target
def prepare_targets(y_train, y_test):
le = LabelEncoder()
le.fit(y_train)
y_train_enc = le.transform(y_train)
y_test_enc = le.transform(y_test)
return y_train_enc, y_test_enc
# feature selection
def select_features(X_train, y_train, X_test):
fs = SelectKBest(score_func=mutual_info_classif, k='all')
fs.fit(X_train, y_train)
X_train_fs = fs.transform(X_train)
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs, fs
# load the dataset
X, y = load_dataset('breast-cancer.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)
# prepare input data
X_train_enc, X_test_enc = prepare_inputs(X_train, X_test)
# prepare output data
y_train_enc, y_test_enc = prepare_targets(y_train, y_test)
# feature selection
X_train_fs, X_test_fs, fs = select_features(X_train_enc, y_train_enc, X_test_enc)
# 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()
运行该示例首先打印为每个输入要素和目标变量计算的分数。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到一些特征的得分非常低,这表明它们可能可以被移除。
也许特性 3、6、2 和 5 最相关。
Feature 0: 0.003588
Feature 1: 0.000000
Feature 2: 0.025934
Feature 3: 0.071461
Feature 4: 0.000000
Feature 5: 0.038973
Feature 6: 0.064759
Feature 7: 0.003068
Feature 8: 0.000000
创建每个输入要素的要素重要性得分的条形图。
重要的是,促进了不同功能的混合。
输入特征条形图(x)与互信息特征重要性条形图(y)
既然我们知道了如何对分类预测建模问题的类别数据执行特征选择,我们可以尝试使用所选特征开发模型并比较结果。
使用选定特征建模
有许多不同的技术用于对特征进行评分和基于评分选择特征;你怎么知道用哪个?
一种稳健的方法是使用不同的特征选择方法(和特征数量)来评估模型,并选择产生具有最佳表现的模型的方法。
在本节中,我们将评估一个逻辑回归模型,将所有特征与通过卡方选择的特征和通过互信息选择的特征构建的模型进行比较。
逻辑回归是测试特征选择方法的一个很好的模型,因为如果从模型中去除不相关的特征,它可以表现得更好。
使用所有功能构建的模型
作为第一步,我们将使用所有可用的特性来评估一个物流配送模型。
该模型适合训练数据集,并在测试数据集上进行评估。
下面列出了完整的示例。
# evaluation of a model using all input features
from pandas import read_csv
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OrdinalEncoder
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]
# format all fields as string
X = X.astype(str)
return X, y
# prepare input data
def prepare_inputs(X_train, X_test):
oe = OrdinalEncoder()
oe.fit(X_train)
X_train_enc = oe.transform(X_train)
X_test_enc = oe.transform(X_test)
return X_train_enc, X_test_enc
# prepare target
def prepare_targets(y_train, y_test):
le = LabelEncoder()
le.fit(y_train)
y_train_enc = le.transform(y_train)
y_test_enc = le.transform(y_test)
return y_train_enc, y_test_enc
# load the dataset
X, y = load_dataset('breast-cancer.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)
# prepare input data
X_train_enc, X_test_enc = prepare_inputs(X_train, X_test)
# prepare output data
y_train_enc, y_test_enc = prepare_targets(y_train, y_test)
# fit the model
model = LogisticRegression(solver='lbfgs')
model.fit(X_train_enc, y_train_enc)
# evaluate the model
yhat = model.predict(X_test_enc)
# evaluate predictions
accuracy = accuracy_score(y_test_enc, yhat)
print('Accuracy: %.2f' % (accuracy*100))
运行该示例将打印训练数据集中模型的准确性。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到该模型实现了大约 75%的分类准确率。
我们更喜欢使用达到与此相同或更好的分类准确率的特征子集。
Accuracy: 75.79
使用卡方特征建立的模型
我们可以使用卡方检验对特征进行评分,并选择四个最相关的特征。
下面的 select_features() 功能被更新以实现这一点。
# feature selection
def select_features(X_train, y_train, X_test):
fs = SelectKBest(score_func=chi2, k=4)
fs.fit(X_train, y_train)
X_train_fs = fs.transform(X_train)
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs
下面列出了使用此特征选择方法评估逻辑回归模型拟合和评估数据的完整示例。
# evaluation of a model fit using chi squared input features
from pandas import read_csv
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OrdinalEncoder
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
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]
# format all fields as string
X = X.astype(str)
return X, y
# prepare input data
def prepare_inputs(X_train, X_test):
oe = OrdinalEncoder()
oe.fit(X_train)
X_train_enc = oe.transform(X_train)
X_test_enc = oe.transform(X_test)
return X_train_enc, X_test_enc
# prepare target
def prepare_targets(y_train, y_test):
le = LabelEncoder()
le.fit(y_train)
y_train_enc = le.transform(y_train)
y_test_enc = le.transform(y_test)
return y_train_enc, y_test_enc
# feature selection
def select_features(X_train, y_train, X_test):
fs = SelectKBest(score_func=chi2, k=4)
fs.fit(X_train, y_train)
X_train_fs = fs.transform(X_train)
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs
# load the dataset
X, y = load_dataset('breast-cancer.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)
# prepare input data
X_train_enc, X_test_enc = prepare_inputs(X_train, X_test)
# prepare output data
y_train_enc, y_test_enc = prepare_targets(y_train, y_test)
# feature selection
X_train_fs, X_test_fs = select_features(X_train_enc, y_train_enc, X_test_enc)
# fit the model
model = LogisticRegression(solver='lbfgs')
model.fit(X_train_fs, y_train_enc)
# evaluate the model
yhat = model.predict(X_test_fs)
# evaluate predictions
accuracy = accuracy_score(y_test_enc, yhat)
print('Accuracy: %.2f' % (accuracy*100))
运行该示例报告了模型在使用卡方统计选择的九个输入要素中的四个要素上的表现。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们看到模型达到了大约 74%的准确率,表现略有下降。
事实上,删除的一些功能可能会直接或与所选功能一起增加价值。
在这个阶段,我们可能更喜欢使用所有的输入特性。
Accuracy: 74.74
利用互信息特征建立的模型
我们可以重复实验,并使用互信息统计选择前四个特征。
下面列出了实现此功能的 select_features() 功能的更新版本。
# feature selection
def select_features(X_train, y_train, X_test):
fs = SelectKBest(score_func=mutual_info_classif, k=4)
fs.fit(X_train, y_train)
X_train_fs = fs.transform(X_train)
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs
下面列出了使用互信息进行特征选择以拟合逻辑回归模型的完整示例。
# evaluation of a model fit using mutual information input features
from pandas import read_csv
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OrdinalEncoder
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import mutual_info_classif
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]
# format all fields as string
X = X.astype(str)
return X, y
# prepare input data
def prepare_inputs(X_train, X_test):
oe = OrdinalEncoder()
oe.fit(X_train)
X_train_enc = oe.transform(X_train)
X_test_enc = oe.transform(X_test)
return X_train_enc, X_test_enc
# prepare target
def prepare_targets(y_train, y_test):
le = LabelEncoder()
le.fit(y_train)
y_train_enc = le.transform(y_train)
y_test_enc = le.transform(y_test)
return y_train_enc, y_test_enc
# feature selection
def select_features(X_train, y_train, X_test):
fs = SelectKBest(score_func=mutual_info_classif, k=4)
fs.fit(X_train, y_train)
X_train_fs = fs.transform(X_train)
X_test_fs = fs.transform(X_test)
return X_train_fs, X_test_fs
# load the dataset
X, y = load_dataset('breast-cancer.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)
# prepare input data
X_train_enc, X_test_enc = prepare_inputs(X_train, X_test)
# prepare output data
y_train_enc, y_test_enc = prepare_targets(y_train, y_test)
# feature selection
X_train_fs, X_test_fs = select_features(X_train_enc, y_train_enc, X_test_enc)
# fit the model
model = LogisticRegression(solver='lbfgs')
model.fit(X_train_fs, y_train_enc)
# evaluate the model
yhat = model.predict(X_test_fs)
# evaluate predictions
accuracy = accuracy_score(y_test_enc, yhat)
print('Accuracy: %.2f' % (accuracy*100))
运行该示例使模型适合使用互信息选择的四个顶级选定要素。
注:考虑到算法或评估程序的随机性,或数值准确率的差异,您的结果可能会有所不同。考虑运行该示例几次,并比较平均结果。
在这种情况下,我们可以看到分类准确率小幅提升至 76%。
为了确保效果是真实的,将每个实验重复多次并比较平均表现将是一个好主意。探索使用 k-fold 交叉验证而不是简单的训练/测试分割可能也是一个好主意。
Accuracy: 76.84
进一步阅读
如果您想更深入地了解这个主题,本节将提供更多资源。
邮件
书
- 特征工程与选择,2019。
应用程序接口
- sklearn . model _ selection . train _ test _ split API。
- 硬化。预处理。序编码器 API 。
- 硬化。预处理。标签编码 API 。
- sklearn . feature _ selection . chi2 API
- 硬化. feature_selection。SelectKBest API
- sklearn . feature _ selection . mutual _ info _ class if API。
- sklearn.linear_model。物流配送应用编程接口。
文章
摘要
在本教程中,您发现了如何使用分类输入数据执行要素选择。
具体来说,您了解到:
- 具有分类输入和二分类目标变量的乳腺癌预测建模问题。
- 如何利用卡方统计和互信息统计评估分类特征的重要性。
- 在拟合和评估分类模型时,如何对类别数据进行特征选择。
你有什么问题吗? 在下面的评论中提问,我会尽力回答。