Machine Learning-教你用Scikit-Learn来做分类器(下)

2019-08-22 13:31:50 浏览数 (1)

机器学习系列专栏

选自 Python-Machine-Learning-Book On GitHub

作者:Sebastian Raschka

翻译&整理 By Sam

这篇是《教你用Scikit-Learn来做分类器》的结尾了,整个系列有3篇文章,每一篇文章专攻一个难点,方便大家利用碎片化的时间来给自己充电?!

由于文章篇幅较长,还是先把本文的结构贴在前面,如下:

上篇:

  • Scikit-Learn初认识
    • 使用Scikit-Learn训练感知器
  • 使用逻辑回归构建一个概率类的分类模型
    • 逻辑回归的激活函数
    • 逻辑回归的损失函数
    • 使用sklearn训练一个逻辑回归模型
    • 使用正则化处理过拟合

上篇传说门:Machine Learning-教你用Scikit-Learn来做分类器(上)

中篇:

  • 使用Kernel-SVM来解决非线性问题
    • 什么是非线性问题
    • 核方法函数及原理
    • 利用核技巧Kernel-SVM在高维空间中寻找分隔超平面

上篇传说门:Machine Learning-教你用Scikit-Learn来做分类器(中)

下篇:(新增)

  • 机器学习决策树模型
    • 最大化信息增益-获得最大的提升度
    • 建立决策树
    • 通过随机森林将“弱者”与“强者”模型集成
  • K近邻分类模型(一个懒惰的算法)
  • 参考文献

PS:代码已单独保存:可在公众号后台输入“sklearn”进行获取ipynb文件

机器学习决策树模型

关于决策树模型的定义解释这边就不说明了,该算法的框架表述还是比较清晰的,从根节点开始不断得分治,递归,生长,直至得到最后的结果。根节点代表整个训练样本集,通过在每个节点对某个属性的测试验证,算法递归得将数据集分成更小的数据集.某一节点对应的子树对应着原数据集中满足某一属性测试的部分数据集.这个递归过程一直进行下去,直到某一节点对应的子树对应的数据集都属于同一个类为止。

图:决策数模型过程

基于训练集中的特征,决策树模型提出了一系列问题来推测样本的类别。虽然上图中做出的每个决策都是根据离散变量,但也可以用于连续型变量,比如,对于Iris中sepal width这一取值为实数的特征,我们可以问“sepal width是否大于2.8cm?”

训练决策树模型时,我们从根节点出发,使用信息增益(information gain, IG)最大的特征对数据分割。然后迭代此过程。显然,决策树的生成是一个递归过程,在决策树基本算法中,有三种情形会导致递归返回:

(1)当前节点包含的样本全属于同一类别,无需划分;

(2)当前属性集为空,或是所有样本在所有属性上取值相同,无法划分;

(3)当前节点包含的样本集合为空,不能划分。

每一个节点的样本都属于同一个类,同时这也可能导致树的深度很大,节点很多,很容易引起过拟合。因此,剪枝操作是必不可少的,来控制树深度。

最大化信息增益-获得最大的提升度

关于对信息、熵、信息增益是信息论里的概念,是对数据处理的量化,这几个概念主要是在决策树里用到的概念,因为在利用特征来分类的时候会对特征选取顺序的选择,这几个概念比较抽象。

信息增益( ID3算法 )定义:

以某特征划分数据集前后的熵的差值。熵表示样本集合的不确定性,熵越大,样本的不确定性就越大。因此可以使用划分前后集合熵的差值来衡量使用当前特征对于样本集合D划分效果的好坏。

  • 划分前样本集合D的熵是一定的,entroy(前)
  • 使用某个特征A划分数据集D,计算划分后的数据子集的熵,entroy(后)
  • 信息增益 = entroy(前) - entroy(后)
  • 原理:计算使用所有特征划分数据集D,得到多个特征划分数据集D的信息增益,从这些信息增益中选择最大的,因而当前结点的划分特征便是使信息增益最大的划分所使用的特征。
  • 详细解释:对于待划分的数据集D,其 entroy(前)是一定的,但是划分之后的熵 entroy(后)是不定的,entroy(后)越小说明使用此特征划分得到的子集的不确定性越小(也就是纯度越高),因此 entroy(前) - entroy(后)差异越大,说明使用当前特征划分数据集D的话,其纯度上升的更快。而我们在构建最优的决策树的时候总希望能更快速到达纯度更高的集合,这一点可以参考优化算法中的梯度下降算法,每一步沿着负梯度方法最小化损失函数的原因就是负梯度方向是函数值减小最快的方向。同理:在决策树构建的过程中我们总是希望集合往最快到达纯度更高的子集合方向发展,因此我们总是选择使得信息增益最大的特征来划分当前数据集D。
  • 缺点:信息增益偏向取值较多的特征。
  • 原因:当特征的取值较多时,根据此特征划分更容易得到纯度更高的子集,因此划分之后的熵更低,由于划分前的熵是一定的,因此信息增益更大,因此信息增益比较偏向取值较多的特征。

此外,还有信息增益比( C4.5算法 ),基尼指数等算法,大家可以去阅读一下参考文献3的文章。

建立决策树

上面讲了这么多原理,还是要放一些code来给大家学习一下。决策树通过将特征空间分割为矩形,所以其决策界很复杂。但是要知道过大的树深度会导致过拟合,所以决策界并不是越复杂越好。我们调用sklearn,使用熵作为度量,训练一颗最大深度为3的决策树,代码如下:

代码语言:javascript复制
 1from sklearn.tree import DecisionTreeClassifier
 2tree = DecisionTreeClassifier(criterion='entropy', max_depth=3, random_state=0)
 3tree.fit(X_train, y_train)
 4X_combined = np.vstack((X_train, X_test))
 5y_combined = np.hstack((y_train, y_test))
 6plot_decision_regions(X_combined, y_combined, 
 7                      classifier=tree, test_idx=range(105, 150))
 8plt.xlabel('petal length [cm]')
 9plt.ylabel('petal width [cm]')
10plt.legend(loc='upper left')
11plt.tight_layout()
12plt.show()

output:

可以看出,这个决策树将数据划分成了三类,不同的颜色代表着一类,此外,sklearn的一大优点是可以将训练好的决策树模型输出,保存在.dot文件。

代码语言:javascript复制
1from sklearn.tree import export_graphviz
2export_graphviz(tree, out_file='tree.dot', feature_names=['petal length', 'petal width'])

通过随机森林将“弱者”与“强者”模型集成

随机森林一直是广受欢迎的模型,优点很多:优秀的分类表现、扩展性和使用简单。随机森林的思想也不复杂,一个随机森林模型就是多颗决策树的集成。集成学习(ensemble learning)的观点是将多个弱分类器结合来构建一个强分类器,它的泛化误差小且不易过拟合。

随机森林算法大致分为4个步骤:

  • 步骤1: 通过自助法(bootstrap)构建大小为n的一个训练集,即重复抽样选择n个训练样例;
  • 步骤2: 对于刚才新得到的训练集,构建一棵决策树。在每个节点执行以下操作:
    • 通过不重复抽样选择d个特征
    • 利用上面的d个特征,选择某种度量分割节点
  • 步骤3: 重复步骤1和2,k次;
  • 步骤4: 对于每一个测试样例,对k颗决策树的预测结果进行投票。票数最多的结果就是随机森林的预测结果。

直接调用sklearn来看一下随机森林吧。

代码语言:javascript复制
 1from sklearn.ensemble import RandomForestClassifier
 2forest = RandomForestClassifier(criterion='entropy',
 3                                n_estimators=10, 
 4                                random_state=1,
 5                                n_jobs=2)
 6forest.fit(X_train, y_train)
 7plot_decision_regions(X_combined, y_combined, 
 8                      classifier=forest, test_idx=range(105, 150))
 9plt.xlabel('petal length [cm]')
10plt.ylabel('petal width [cm]')
11plt.legend(loc='upper left')
12plt.tight_layout()
13plt.show()

output:

K近邻分类模型(一个懒惰的算法)

本系列最后一个监督学习算法是k紧邻算法(k-nearest neighbor classifier, KNN), 这个算法很有意思,因为他背后的思想和本章其他算法完全不同。

KNN是懒惰学习的一个典型示例。之所以称为“懒惰”并不是由于此类算法看起来很简单,而是在训练模型过程中这类算法并不去学习一个判别式函数(损失函数)而是要记住整个训练集。

这里引入一个概念:参数模型VS变参模型

机器学习算法可以被分为两大类:参数模型和变参模型

对于参数模型,在训练过程中我们要学习一个函数,重点是估计函数的参数,然后对于新数据集,我们直接用学习到的函数对齐分类。典型的参数模型包括感知机、逻辑斯蒂回归和线性SVM。

对于变参模型,其参数个数不是固定的,它的参数个数随着训练集增大而增多!很多书中变参(nonparametric)被翻译为无参模型,一定要记住,不是没有参数,而是参数个数是变量!变参模型的两个典型示例是决策树/随机森林和核SVM。

KNN属于变参模型的一个子类:基于实例的学习(instance-based learning)。基于实例的学习的模型在训练过程中要做的是记住整个训练集,而懒惰学习是基于实例的学习的特例,在整个学习过程中不涉及损失函数的概念。

KNN算法本身非常简单,步骤如下:

  1. 确定k大小和距离度量。
  2. 对于测试集中的一个样本,找到训练集中和它最近的k个样本。
  3. 将这k个样本的投票结果作为测试样本的类别。

对每一个测试样本,基于事先选择的距离度量,KNN算法在训练集中找到距离最近(最相似)的k个样本,然后将k个样本的类别的投票结果作为测试样本的类别。

像KNN这种基于内存的方法一大优点是:一旦训练集增加了新数据,模型能立刻改变。另一方面,缺点是分类时的最坏计算复杂度随着训练集增大而线性增加,除非特征维度非常低并且算法用诸如KD-树等数据结构实现。此外,我们要一直保存着训练集,不像参数模型训练好模型后,可以丢弃训练集。因此,存储空间也成为了KNN处理大数据的一个瓶颈。

下面我们调用sklearn训练一个KNN模型:

代码语言:javascript复制
 1from sklearn.neighbors import KNeighborsClassifier
 2knn = KNeighborsClassifier(n_neighbors=5, p=2, metric='minkowski')
 3knn.fit(X_train_std, y_train)
 4plot_decision_regions(X_combined_std, y_combined, 
 5                      classifier=knn, test_idx=range(105, 150))
 6plt.xlabel('petal length [standardized]')
 7plt.ylabel('petal width [standardized]')
 8plt.legend(loc='upper left')
 9plt.tight_layout()
10plt.show()

output:

参考文献

1)信息熵(Entropy)、信息增益(Information Gain)

https://www.cnblogs.com/liyuxia713/archive/2012/11/02/2749375.html

2)[机器学习]信息&熵&信息增益

https://www.cnblogs.com/fantasy01/p/4581803.html

3)决策树--信息增益,信息增益比,Geni指数的理解

https://www.cnblogs.com/muzixi/p/6566803.html

代码语言:javascript复制
—End—

0 人点赞