机器学习算法性能比对分析流程

写这篇文章的初衷是受到优达学城“机器学习纳米学位(进阶)”课程中“finding donors”项目的启发。主要是梳理比对不同的机器学习算法的流程。

本文章使用的数据集是“Census Income Data Set”,来自UCI Machine Learning Repository(https://link.zhihu.com/?target=https%3A//archive.ics.uci.edu/ml/datasets/Census%2BIncome)。我们的目标是使用多种机器学习算法预测收入,具体来说,预测一个人的收入是否超过50000美金.

本文所有代码均在jupyter notebook上运行通过,使用的python版本是2.7.14,源代码点击这里(https://link.zhihu.com/?target=https%3A//github.com/freefrog1986/ML-master-udacity/tree/master/3.%2520Supervised%2520Learning/finding_donors)。

1. 探索数据

首先,读入需要的库。numpy用于处理运算,pandas用于处理数据,time用于计算运行时间,display用于更好的显示图片。

首先我们读入了数据集并显示前三行,这个数据集有不同类型的特征值,有连续值例如age,也有离散值例如workclass。

1.1 数据初探

我们的目标是预测收入,也就是数据集中的income变量。下面先看一看income变量的大概情况。

income只有两类,大于$50000和小于$50000,数据值一共有45222个样本,我们想要预测的数据(大于$50000)占24.78%。

注意这里可以使用.value_counts()属性得到某一特征不同类别的数量。

另外值得注意的是,python中使用除法要非常小心,最好使用np.true_divide()来进行传统意义上的除法运算。

2. 准备数据

在使用数据之前,通常要经过清理、格式化和重组等步骤——这通常被称为预处理。幸运的是,这个数据集没有无效或丢失的样本。但是,需要对某些特征进行调整。这种预处理对几乎所有学习算法都有很大的帮助。

2.1 转换偏差的数值特征

首先我们来看一下如何处理数值特征,这类数据最容易出现的问题之一就是分布的偏差和方差过大,也就是说当大部分数据分布在一个固定值周围时,也会出现很多特别大或者特别小的值。

对于我们要处理的数据集来说capital-gain和capital-loss就是这样的特征。我们来画图看一下这两个特征的分布情况。

我们发现,对于'capital-gain',大部分值分布在0-20000范围内,也有一些值分布在100000附近。而对于'capital-loss',大部分数值分布在2000附近,另外有很大一部分数值分布在0附近,这种数据分布我们称为‘偏差’。另外,我们观察数值的分布范围,'capital-gain'是[0, 100000], 而'capital-loss'是[0, 4000],取值范围很大。

对于高度偏差的特征分布,如'capital-gain'和'capital-loss',应用对数变换是很常见的做法,这样,非常大和非常小的值就不会对算法的性能产生负面影响。使用对数变换大大缩小了数值的范围。但是,在应用这种转换时必须注意:0的对数是未定义的,因此我们必须将数值转换成大于0的值。

运行下面的代码,对数据进行转换并可视化结果。同样,请注意数值的范围及分布。

代码首先将数据转换为pandas.Dataframe类型,然后将特征的取值加1后取对数,加1的作用是避免出现0值。我们发现,转换后的分布由原来的很大的取值区间转换为现在的[0, 12].

2.2 连续特征正则化

除了在高度偏差的特性上执行转换之外,在数值特征上执行某种类型的缩放也是很好的做法。缩放操作不改变特征的分布(如上面的'capital-gain”或'capital-loss”);然而,正则化确保平等对待每个特征。需要注意的是,一旦进行缩放,其原始形式的数据的含义将改变(例如0.301370显然不是这个人的真实年龄),见下面的例子。

观察结果,所有连续特征均被转换到[0,1]区间。

总结以上步骤:

1. 观察所有数值特征

2. 对高偏差的特征进行对数转换

3. 对所有数值特征进行正则化

2.3 数据预处理

接下来我们来考虑离非数值征值,当然,我们需要将其转换为数值特征。一种常用的方法是使用one-hot编码。One-hot编码为非数值特征的每一种可能创建一个_"dummy"_ 变量. 例如, 假设someFeature有三种可能的取值:A,B, 或C. 我们可以将其编码为someFeature_A,someFeature_B和someFeature_C.

同样,我们也需要对标签'income'进行转换。由于我们的标签只有两种取值("50K"), 我们可以不使用one-hot编码,而是直接使用0或1分别代表.

下面是实战代码

这里主要使用了pd.get_dummies()和LabelEncoder().fit_transform(),前者是将非数值特征进行one-hot编码,后者是将标签特征进行0,1编码

2.4 数据集划分

现在所有特征均被转换为数值并进行了归一化处理。接下来我们将数据集划分为训练集和测试集。

3. 评估模型性能

在这一节,我们将探索4个不同的分类器, 并决定哪一个最适合我们的数据. 其中,我们首先打造一个朴素分类器作为比对基准.

3.1 测量指标和朴素分类器

我们使用的测量指标是准确率(accuracy)和F-beta得分。

观察标签数据的分布不难发现,大部分人的收入没有超过$50,000. 这种情况很容易影响准确率(accuracy)。假设我们简单的认为所有人的收入都不超过$50,000,这样的一个朴素分类器也会有很好的准确率!

接下来我们就先来打造这个朴素分类器。

如果读者不熟悉这里使用的测量指标,可以参考这篇文章(https://zhuanlan.zhihu.com/p/31832769/edit)。我们发现,即便是这样一个简单的模型,也可以得到准确率0.2478。

3.2 模型选择

接下来就是模型选择了,一般来说使用选择模型从以下几方面考虑:数据量大小,特征值特点,模型的适用条件等等。我们以朴素贝叶斯,决策树和支持向量机为例。

先来说说朴素贝叶斯,我们知道朴素贝叶斯基于特征之间相互独立的假设,所以我们数据集的特征越是相互独立,该模型的表现越好,另外朴素贝叶斯对于数据集的大小不敏感,所以如果数据集较小可以采用朴素贝叶斯。但是朴素贝叶斯也有缺点,一个缺点就是朴素贝叶斯的前提条件:特征之间相互独立,换句话说,如果不是相互独立的话,效果就会打折扣。

再来说说决策树,使用决策树的好处是,我们能够得到一套明确的筛选机制(树结构)用于预测,如果数据的某些特征能够明确的代表某些类的话,那么使用决策树是很好的选择。另外更多的离散值特征也是我们可以选择决策树的理由之一。决策树的缺点是比较依赖于一些关键特征,如果这些关键特征不能够很好的用于分类的话,决策树将会表现的很差。最后一个缺点是过拟合问题,决策树的特点决定了它容易产生过拟合,所以泛化能力差也是决策树的缺点之一。

最后说一下支持向量机,支持向量机的优点是有较强的泛化能力,因为它努力找到使不同类别之间的空隙最大化的平面,如果空隙中再出现测试数据,也可以很好的分类。但是支持向量机的缺点是太依赖于核函数。另外计算时间较长也是它的缺点。

3.3 打造训练和预测流程

这里我们要打造一个训练和预测的流程(pipeline),为什么要这么做?因为这样我们就可以轻松的测试不同模型的性能。具体代码见下面

实际上,我们创造了 train_predict函数,函数实现的功能就是利用输入的模型进行训练和和预测,并得到模型在训练集和测试集上的测量指标(我们选用的是准确率和f-beta得分)。另外,我们还计算了每个模型的运行时间,便于后续分析。函数的输入还包括一个变量sample_size用于控制训练集的大小,分析不同的模型适用什么规模的数据。

3.4 初始模型评估

接下来我们就可以利用上面的函数来测试不同模型在我们的数据集上的表现了。

我们来分析一下结果,结果分为六组图片,上面三组代表在训练集的表现,下面三组代表在测试集的表现。从左到右分别是测试时间,准确率,f-beta得分。

先来分析运行时间,很明显SVC无论在测试集还是在训练集都是非常消耗时间的,我们发现,SVC对训练集数据规模比较敏感,当数据集规模增加90%时,svc的运行时间增加了200倍。

再看不同的模型在测试集和训练集上的准确率表现,首先,在训练集,无论数据规模大小,决策树性能优于SVC优于朴素贝叶斯且均优于我们的朴素分类器。然后在测试集上,SVC的性能表现超越了决策树,这也是之前在模型选择时我们提到的,决策树容易产生过拟合,而svc的泛化能力较强。使用f-bata得分作为测量标准也发生了同样的情况。

4. 改进结果

4.1 选择最好的模型

接下来需要考虑的是,哪个模型更加适合我们的数据集,很明显,从运行时时间,准确率和泛化能力来看,决策树是更优的选择。

4.2 模型参数调优

既然已经选定了模型,接下来就是调参数,优化模型。我们使用的方法是传统的网格搜索(grid search),也就是设定不同的参数值,通过不断的试验,得到表现最好的模型。

这里我们使用的核心函数就是GridSearchCV,该参数有三个输入,分别是分类器,参数和测量指标,其中测量标准需要使用make_scorer(fbeta_score, beta=0.5)来生成,参数的话使用字典数据类型来表示不同的参数及其取值。

通过测试,我们得到了更好的模型参数,模型的性能得到了提升!

5. 特征重要性

通常来说,不是所有的特征对模型性能都有同样的重要性,一般来说,一部分关键特征决定了模型的大部分性能。

5.1 提取特征的重要性

在scikit-learn库中,部分机器学习算法具有.feature_importances_属性,通过该属性,我们既可以得到影响算法性能的关键特征。我们以AdaBoost模型为例:

这里展示了前5个影响最大的特征及其影响权重。

6. 特征选择

最后,我们来看一下,如果仅使用最有影响力的5个特征进行训练,得到什么结果。

结果是,模型性能下降了,但是下降的不多,也就是说,如果仅使用5个特征值而不是13个,能得到接近的性能,大大提升了效率!

总结

最后,通过这个案例,我们总结一下机器学习算法性能比对分析流程:

1. 探索数据:了解数据的基本情况

2. 准备数据:对数据进行清洗,正则化等

3. 评估模型性能:根据经验选择比较适合模型以及测量标准进行比对分析

4. 改进结果:根据比对结果选择最好的模型,并对其进行调参

5. 特征选择:考虑使用影响力较大的部分特征

出处:https://zhuanlan.zhihu.com/p/33044332

版权申明:内容来源网络,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢。

架构文摘

互联网应用架构丨架构技术丨大型网站丨大数据丨机器学习

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180214B06OF100?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券