【机器学习】入门ML?跟着做这几个实验足矣!(二)
随机森林
本课程需要使用的module: os, numpy, pandas, tensorflow(2.0.0及以上), matplotlib, sklearn, graphviz, pydotplus, skimage, opencv, seaborn.
目录
0. 课程摘要
1. 决策树
2. 分类决策树
3. 回归决策树
4. 本课任务介绍
- 4.1 MNIST介绍
- 4.2 数据的预处理
5. 随机森林
- 5.1 分类式随机森林
- 5.2 回归式随机森林
- 5.3 预测错误展示
6. 非数据库图片测试
7. 总结
Homework
作业1
作业2
作业3
作业4
作业5
加载library
首先让我们将需要的module准备好。
1 | !pip install scikit-image |
Requirement already satisfied: scikit-image in d:\application\anaconda\lib\site-packages (0.18.3)
Requirement already satisfied: numpy>=1.16.5 in d:\application\anaconda\lib\site-packages (from scikit-image) (1.20.3)
Requirement already satisfied: scipy>=1.0.1 in d:\application\anaconda\lib\site-packages (from scikit-image) (1.7.1)
Requirement already satisfied: matplotlib!=3.0.0,>=2.0.0 in d:\application\anaconda\lib\site-packages (from scikit-image) (3.4.3)
Requirement already satisfied: networkx>=2.0 in d:\application\anaconda\lib\site-packages (from scikit-image) (2.6.3)
Requirement already satisfied: pillow!=7.1.0,!=7.1.1,>=4.3.0 in d:\application\anaconda\lib\site-packages (from scikit-image) (8.4.0)
Requirement already satisfied: imageio>=2.3.0 in d:\application\anaconda\lib\site-packages (from scikit-image) (2.9.0)
Requirement already satisfied: tifffile>=2019.7.26 in d:\application\anaconda\lib\site-packages (from scikit-image) (2021.7.2)
Requirement already satisfied: PyWavelets>=1.1.1 in d:\application\anaconda\lib\site-packages (from scikit-image) (1.1.1)
Requirement already satisfied: kiwisolver>=1.0.1 in d:\application\anaconda\lib\site-packages (from matplotlib!=3.0.0,>=2.0.0->scikit-image) (1.3.1)
Requirement already satisfied: cycler>=0.10 in d:\application\anaconda\lib\site-packages (from matplotlib!=3.0.0,>=2.0.0->scikit-image) (0.10.0)
Requirement already satisfied: python-dateutil>=2.7 in d:\application\anaconda\lib\site-packages (from matplotlib!=3.0.0,>=2.0.0->scikit-image) (2.8.2)
Requirement already satisfied: pyparsing>=2.2.1 in d:\application\anaconda\lib\site-packages (from matplotlib!=3.0.0,>=2.0.0->scikit-image) (3.0.4)
Requirement already satisfied: six in d:\application\anaconda\lib\site-packages (from cycler>=0.10->matplotlib!=3.0.0,>=2.0.0->scikit-image) (1.16.0)
Collecting pydotplus
Downloading pydotplus-2.0.2.tar.gz (278 kB)
Requirement already satisfied: pyparsing>=2.0.1 in d:\application\anaconda\lib\site-packages (from pydotplus) (3.0.4)
Building wheels for collected packages: pydotplus
Building wheel for pydotplus (setup.py): started
Building wheel for pydotplus (setup.py): finished with status 'done'
Created wheel for pydotplus: filename=pydotplus-2.0.2-py3-none-any.whl size=24575 sha256=5077bd53ca5a3f6f7f24d96630ee00a36f705cdd2ceba0c43c4046b659ba42cd
Stored in directory: c:\users\71852\appdata\local\pip\cache\wheels\89\e5\de\6966007cf223872eedfbebbe0e074534e72e9128c8fd4b55eb
Successfully built pydotplus
Installing collected packages: pydotplus
Successfully installed pydotplus-2.0.2
1 | import tensorflow as tf #tensorflow: conda install tensorflow |
0. 课程摘要
前一部分的课程给大家介绍了分类和回归问题的处理方法,这一课给大家介绍一种既可以用于回归问题,也可以用于分类问题的算法:随机森林。
随机森林是一种灵活,易于使用的机器学习算法,即使没有超参数调整,也能在大多数情况下产生出色的结果。
本课内容包括随机森林的组成部分:决策树的原理和生成,随机森林的原理、生成。我们将使用随机森林模型解决一个有趣的问题:手写数字识别问题。
随机森林是由不同的决策树组成的,所以首先给大家介绍决策树。
1. 决策树
决策树是一种二叉树。在计算机科学中,二叉树(英语:Binary tree)是每个节点最多只有两个分支(即不存在分支度大于2的节点)的树结构。通常分支被称作“左子树”或“右子树”。二叉树的分支具有左右次序,不能随意颠倒。
树的相关知识:
节点的度:一个节点含有的子树的个数称为该节点的度;
树的度:一棵树中,最大的节点度称为树的度;
叶节点或终端节点:度为零的节点;
父亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
兄弟节点:具有相同父节点的节点互称为兄弟节点;
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
深度:对于任意节点n,n的深度为从根到n的唯一路径长,根的深度为0;
高度:对于任意节点n,n的高度为从n到一片树叶的最长路径长,所有树叶的高度为0;
例:此处我们以iris dataset的分类问题建立一个决策树。
1 | from sklearn.datasets import load_iris #鸢尾花数据集 |
True

图注:
- sample:该节点所包含的样本数量。
- value:该节点中样本对应的各类鸢尾花的数量,该list中第一个元素为山鸢尾数量,第二个为变色鸢尾数量,第三个为维吉尼亚鸢尾数量。
- class:该节点的输出(山鸢尾 (Setosa)、变色鸢尾 (Versicolour) 和维吉尼亚鸢尾 (Virginica))
- gini:该节点的基尼指数。
- 颜色:该节点的输出。褐色为山鸢尾,绿色为变色鸢尾,紫色为维吉尼亚鸢尾。深浅度代表了所得结果的概率大小。
决策树以基尼指数(gini)为拓展分支的准则,在下面的内容里我们将介绍这一重要概念。
2. 分类决策树
分类树分析是当预计结果可能为离散类型(例如三个种类的花,输赢等)使用的概念。
-
特征和特征数值如何选取:
-
基尼指数
-
基尼指数表示集合不确定性,基尼指数表示集合D经分割后的不确定性(类似于熵),
-
基尼指数越小,样本的不确定性越小。
-
基尼值是指从一个样本集中选择2个样本,这2个样本不属于同一类的概率:
-
可以看出基尼值越小说明该数据集中不同类的数据越少,即数据集纯度越高。
-
在所有可能的特征A以及该特征所有的可能取值中,选择基尼指数最小的特征及其对应的取值作为最优特征和最优切分点。
当特征A所对应的值为连续值时,对样本的特征A的值进行升序排序,从小到大取相邻两个值的平均值作为阈值进行划分,在所有切分点中,基尼指数最小的即为最优切分点。
-
-
例:以体重与患心脏病情况的关系为例来说明如何生成分类二叉树。
Source: https://www.youtube.com/watch?v=7VeUPuFGJHk&t=779s

作业1:
写一个函数来计算基尼指数。(请在编写代码部分完成作业1)
1 | ######Mission 1: Compute Gini coefficient.###### |
1 | #此处为讲解基尼指数的计算方法和过程加载贷款申请样本数据表 |
age work house credit class
0 youth no no common refuse
1 youth no no good refuse
2 youth yes no good agree
3 youth yes yes common agree
4 youth no no common refuse
5 mid no no common refuse
6 mid no no good refuse
7 mid yes yes good agree
8 mid no yes excellent agree
9 mid no yes excellent agree
10 elder no yes excellent agree
11 elder no yes good agree
12 elder yes no good agree
13 elder yes no excellent agree
14 elder no no common refuse
1 | #获得特征种类 |
特征有: ['age', 'work', 'house', 'credit']
编写代码部分:
1 | #设计Gini函数求基尼指数,其中参数dataset是数据集,feature为所选特征,value为所选特征的取值(当然也可以不使用这里给出的参数)。 |
1 | #进行基尼指数输出 |
选择的特征是age,取值是youth, 基尼指数为: 0.48
选择的特征是age,取值是elder, 基尼指数为: 0.32
选择的特征是work,取值是yes, 基尼指数为: 0.0
选择的特征是house,取值是no, 基尼指数为: 0.44
选择的特征是house,取值是yes, 基尼指数为: 0.0
选择的特征是credit,取值是common, 基尼指数为: 0.32
选择的特征是credit,取值是good, 基尼指数为: 0.44
决策树的输出值为树叶上大多数样本所属的类别:
如上图例1所示,每个节点都有一个class数据成员。
譬如训练样本包括A,B,C三个类别,某一树叶上对应8个A类样本,2个B类样本,1个C类样本,那么这个树叶的输出则是A类别。
附:其它选择特征的方式:
信息熵(information entropy)是度量样本集合纯度的一种常用指标。
我们可以通过与之相关的信息增益选取特征。
(简单了解即可)
3. 回归决策树
回归决策树是可以用于回归的决策树模型,一个回归树对应着输入空间(即特征空间)的一个划分以及在划分单元上的输出值。
在生成和输出过程中,回归决策树和分类决策树主要有两点不同:
- 特征选择
假设X和Y分别为输入和输出变量,并且Y是连续变量,给定训练数据集为,其中为输入实例(特征向量),n为特征个数,i=1,2,…,N, N为样本容量。
特征和特征取值:
其中, 。
找到最优的切分点后,依次将输入空间划分为两个区域,接着对每个区域重复上述划分过程,直到满足停止条件为止。这样就生成了一棵回归树,这样的回归树通常称为最小二乘回归树。
- 输出值
输出值为单元内每个样本点的值的均值。
例:药物剂量
Source: https://www.youtube.com/watch?v=g9c66TUylZ4&t=769s
此视频中的问题是一个单特征问题(Drug-Effective - Drug Dosage)。
4. 本课任务介绍:手写数字识别问题
输入为手写数字数据集,样本为三维数组,每个样本对应0~9中的一个数字。
作为10类别分类问题,输出为0~9。
也可以作为回归问题处理。
4.1 MNIST介绍
MNIST数据集(Mixed National Institute of Standards and Technology database)是美国国家标准与技术研究院收集整理的大型手写数字数据库。
1 | sns.set_style('white') |
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 2s 0us/step
11501568/11490434 [==============================] - 2s 0us/step
作业2:
补充下一个代码块使其能够按顺序展示0~9,每个标签各一个样本。
1 | #添加代码使mnist_example从hand_written_digits处获得样本。 |
MNIST样例
所以,我们这次课的任务具体地说,则是:
建立一个模型:
-
输入为一个包含手写文字的图片,尺寸大小是28*28,合计 个特征。
-
输出为手写文字图片对应的数字。
4.2 数据的预处理
-
扁平化:使二维数组(矩阵)一维化(向量)以便于处理数据
-
二值化:使元素取值取0或255,设定一个阈值,大于此阈值的元素取255,小于此阈值的元素取0。
1 | #数据扁平化 |
(12000, 784)
(12000, 28, 28)
1 | #数据可视化(Heatmap) |
5. 随机森林
在机器学习中,随机森林是一个包含多个决策树的分类器,并且其输出的类别是由个别树输出的类别的众数而定。 Leo Breiman和Adele Cutler发展出推论出随机森林的算法。
随机森林就是通过集成学习的思想将多棵树集成的一种算法,它的基本单元是决策树,而它的本质属于机器学习的一大分支——集成学习(Ensemble Learning)方法。
随机森林可以看作是决策树的组合
- 树的数量的影响(训练时间、欠拟合/过拟合)
- 随机抽取样本进行决策树的构造
- 随机抽取特征进行决策树的构造
随机森林的随机性
- 样本的随机性
如果训练集大小为N,对于每棵树而言,随机且有放回地从训练集中的抽取N个训练样本,作为该树的训练集。(询问家人、朋友的意见时,每个人以前去过的旅游地是不一样的,所以训练集是不同的。这其实是bagging。)
- 特征的随机性
如果每个样本的特征维度为M,指定一个常数m<<M,随机地从M个特征中选取m个特征子集,每次树进行分裂时,从这m个特征中选择最优的。(询问家人、朋友的意见时,每个人考虑的要素是不同的,有人考虑价格,有人考虑交通,所以特征的选取是不同的)
数据集的划分
随机森林是一种监督学习的算法,所以我们要对数据集进行划分:将其划分为训练集和测试集
作业3:
复习sklearn.model_selection.train_test_split函数并将hand_written_digits进行数据集划分,测试集大小为数据集的四分之一
注:hand_written_digits[0]为数据集X,hand_written_digits[1]为标签集y。
1 | #划分数据集 |
5.1 分类式随机森林
分类式随机森林由多棵分类决策树构成。

图注: 每棵树是一颗分类决策树,对输入给出自己的结果,最后综合所有决策树的结果给出随机森林的结果。
1 | #样例:随机森林及其参数 |
Sklearn分类式随机森林函数中的参数
-
criterion: ”gini” or “entropy”(default=”gini”)是计算属性的gini(基尼指数)还是entropy(信息增益),来选择最合适的节点。
-
max_depth: (default=None)设置树的最大深度,默认为None,这样建树时,会使每一个叶节点只有一个类别,或是达到min_samples_split。
-
min_samples_split: 根据属性划分节点时,每个划分最少的样本数。
-
n_estimators: 决策树的个数。
-
oob_score=False:oob(out of bag,袋外)数据,即:在某次决策树训练中没有被bootstrap选中的数据。
-
n_jobs=1:并行job个数。可通过并行提高性能。(n_job=-1时,有多少个core就可以启动多少个job)
将问题视为分类问题:
1 | #构造随机森林(默认参数,使用n_jobs=-1来加速训练速度) |
Score = 0.948
超参数对模型性能的影响
- 过拟合:
模型过于复杂会导致过拟合,表现为在训练集上的得分较高,但是泛化能力差,在测试集上的得分较低。
在本问题中,max_depth过大或n_estimator过大会导致过拟合。
- 欠拟合:
模型过于简单会导致欠拟合,表现为在训练集上和在测试集上得分都较低。
在本问题中,max_depth过大或n_estimator过低会导致过拟合。
1 | sns.set_style("whitegrid") |
1 | #观察决策树最大深度对模型accuracy的影响 |
可以看出,在本问题中,所选择的两个参数取值过小会导致欠拟合,但取值较大时并不容易产生过拟合(随着参数取值的不断增大,模型性能没有减弱)。
1 | #rfct为最终选择的随机森林模型 |
测试分数 = 0.9476666666666667
分类式随机森林决策过程:
作业4:
观察统计随机森林中所有决策树对某一个样本预测的结果。绘制柱状图。
1 | # 补充该cell。 |
正确答案是: 8
分类式随机森林中的每个决策树都得出结果后,所有决策树会进行一次majority vote。每个决策树为自己所得的结果投票, 得票最多的结果 就是随机森林得到的结果。上图中votes为每个可能结果所得的票数。
5.2 回归式随机森林
回归式随机森林由多棵回归决策树构成。
让我们先来看看sklearn的回归式随机森林函数
1 | sns.set_style('white') |
和分类式随机森林函数区别不大。
将问题视为回归问题:
- 最后输出结果会是一个实数,而不是一个分类标签。
- 汇总各个决策树的预测时可以求平均。
- 最终的预测结果可以是四舍五入的结果(譬如随机森林给出汇总结果为5.7,则预测为数字6)
1 | #建立随机森林(回归决策树,默认参数) |
训练分数: 0.976744221955607
测试分数: 0.8295041385895947
1 | #相同hyperparameter下的回归分类树的效果 |
训练分数: 0.9762783573500573
测试分数: 0.8278097569753089
5.3 预测错误展示
让我们观察一下在两种随机森林的分类错误测试样本:
1 | #从分类树中选取被错误分类的数据 |
首先是分类模型的预测错误
1 | print("错误分类(分类模型):\n") |
错误分类(分类模型):
预测错误总数量: 157
其次是回归模型的预测错误
1 | print("错误分类(回归模型):\n") |
错误分类(回归模型):
预测错误总数量: 1149
6. 非数据库图片测试
使用下面4个手写图片进行预测




非数据库图片预处理
图片需要进行预处理使模型可以处理它们。
1 | #运用训练好的模型进行预测 |
非数据库图片预测
1 | print("非数据库图片预测") |
非数据库图片预测
使用摄像头拍摄手写数字进行预测。(不作要求)
学习VideoCapture函数来调用摄像头
通过摄像头获得手写数字图片,文件名为test.jpg。
尽量将字迹写粗使特征容易被摄像头捕获。
1 | cap = cv2.VideoCapture(0) |
下面提供接口,您可以自己上传手写数字图片进行预测
请您把需要测试的图片存入该教程的目录下。
可以使用的图片列表:
hand_write_3.jpg
hand_write_4.jpg
hand_write_5.jpg
hand_write_6.jpg
hand_write_7.jpg
hand_write_8.png
hand_write_9.jpg
作业5:
手写一个数字(画图/iPad/数位板)保存成图片,命名为"学号_姓名.jpg"在下面给出的接口进行测试,结果仅供图一乐。
1 | #实现预测数字的函数,参数是所使用的模型 |
Please input the name of the picture(需要后缀名,输入q退出): 61520611_张公瑞.jpg
Please input the label of the picture: 1
7. 总结
在本课中,我们学习了:
- 决策树的概念
- 分类决策树和回归决策树的概念和生成步骤
- 随机森林的概念,随机森林的生成,超参数对随机森林的影响
- 随机森林的运用:手写数字的识别