带你读《C#神经网络编程》之三:决策树和随机森林

点击查看第一章
点击查看第二章

第3章

决策树和随机森林
决策树和随机森林是一种可以增加应用程序功能的强大技术。我们将介绍一些概念和代码,希望有助于你快速掌握并运行。
在本章中,我们将涉及以下主题:

  • 通过大量代码示例展示如何向应用程序添加强大的功能
  • 决策树
  • 随机森林

技术要求
你需要在系统中安装Microsoft Visual Studio。你可能还需要参考开源SharpLearning架构的GitHub代码库,地址为https://github.com/mdabros/SharpLearning
请观看视频,学习如何编码:http://bit.ly/201Lbhr

3.1 决策树

决策树可以用于分类和回归。决策树以“是/否、真/假”的方式回答连续的问题。根据这些回答,决策树按照预定的路径实现它的目标。决策树是有向无环图的一个变种。最后,利用整个数据集和所有特征构建决策树。
图3-1展示了一个决策树的例子。你可能不理解决策树,但是你肯定知道这个过程。有人要甜甜圈吗?
如你所见,决策树的流程为自上而下式,直到获得具体的结果。树根是数据集拆分的初始决策点。决策树根据每个节点上的分割标准来分割数据集。最常用的两个分割标准是“基尼不纯度”和“信息增益”。
图3-2所示为决策树的另一种描述,虽然没有好吃的甜甜圈!
到目前为止,决策树的深度表示已经提出了许多问题。这是树所能达到的最深层次(可询问问题的总数),虽然在某些分支上,提出较少的问题也能获得一些结果。例如,如图3-2所示,提出1个问题之后就可以得到一些结果,有些结果在2个问题之后才能得到。因此,该决策树的深度为2。

带你读《C#神经网络编程》之三:决策树和随机森林

3.1.1 决策树的优点

以下是使用决策树的一些优点:

  • 便于说明。
  • 简明、无须加以说明的可视化。
  • 便于复制。
  • 能处理数字和分类数据。
  • 针对大数据集性能良好。
  • 速度通常较快。
  • 树的深度位置便于显示重要特性,树的深度可体现重要性。

3.1.2 决策树的缺点

以下是使用决策树的一些缺点:

  • 每个节点上,算法需要做出正确选择。一个节点上的最佳选择不一定是整棵树的最佳选择。
  • 如果一棵树层级较深,就容易过度拟合。
  • 决策树会记忆训练集的数据,范化能力不强。

3.1.3 何时应该使用决策树

以下是一些关于何时使用决策树的例子:

  • 当你想要一个简单且可解释的模型时。
  • 当你的模型应该是非参数时。
  • 当你不用担心特征选择时。

3.2 随机森林

在前面我们已经讨论过决策树,接下来讨论随机森林。基本上,随机森林是决策树的集合。在随机森林中,随机选择总行数和特征数的一小部分来进行训练。然后在该子集上构建决策树。该集合会将结果聚合成单个结果。
随机森林也可以减少偏差和方差。它们是如何做到的?通过对不同数据样本进行训练,或者通过使用特征的随机子集。让我们来举例说明,假设我们有30个特征,随机森林可能只使用其中的10个特征,这会导致20个特征不被使用,但是这20个特性中的某些可能很重要。请记住,随机森林是决策树的集合。因此,在每个决策树中,如果我们使用10个特征,随着时间的推移,大多数(如果不是全部的话)特征都会因为平均法则被包含在内。因此,正是这种包含有助于控制因偏差和方差而产生的误差。
对于大型数据集,决策树的数量可能会大幅增加,有时会增长到数万个甚至更多,这取决于你使用的特征数量,因此你需要仔细考虑性能问题。
随机森林的示意图如图3-3所示。

带你读《C#神经网络编程》之三:决策树和随机森林

3.2.1 随机森林的优点

以下是使用随机森林的一些优点:

  • 比单个决策树更强大。
  • 随机森林包含许多决策树,因此能够限制过度拟合和误差。
  • 深度信息显示了哪些特征有助于分类或回归,以及它们的相对重要性。
  • 可用于回归和分类。
  • 默认参数就足够了。
  • 可快速训练。

3.2.2 随机森林的缺点

以下是使用随机森林的一些缺点:

  • 为了提高速度,随机森林需要并行进行。
  • 一旦训练完成,预测可能会变得很慢。
  • 需要更多决策树才能更准确,这可能导致模型的速度变慢。

3.2.3 何时应该使用随机森林

以下是一些何时使用随机森林的例子:

  • 当模型解释不是最重要的标准,解释不像决策树那么简单时。
  • 当模型精度最为重要时。
  • 当需要强大的分类、回归和特征选择分析时。
  • 防止过度拟合。
  • 图像分类。
  • 推荐引擎。

3.3 SharpLearning

现在,让我们将注意力转向一个不可思议的开源软件包SharpLearning。SharpLearning是一种卓越的机器学习框架,可以让人们学习机器学习的许多方面,包括前面几节描述的决策树和随机森林。在深入了解一些代码示例和示例应用程序之前,让我们先花几分钟了解一些知识。

3.3.1 术语

本章将会涉及以下术语:

  • 学习器:这里指机器学习算法。
  • 模型:这里指机器学习模型。
  • 超参数:这些是用来调整和调节(希望如此)机器学习模型的参数。
  • 目标:这些目标通常称为因变量,用符号y表示,是尝试建模的值。
  • 观察值:这些是特征矩阵,包含当前目标的所有信息,用符号x表示。

在大多数示例中,我们将重点关注SharpLearning的两个名称空间:
带你读《C#神经网络编程》之三:决策树和随机森林

基于此,我们开始深入了解SharpLearning,并向你展示一些关于它如何工作的概念。

3.3.2 加载和保存模型

SharpLearning非常便于将模型加载和保存到磁盘中。这是机器学习库中非常重要的一部分,SharpLearning是最容易实现的部分。
SharpLearning中的所有模型都有保存和加载函数。这些函数为我们完成保存和加载模型的繁重工作。
例如,我们将一个学习模型保存到磁盘中:
带你读《C#神经网络编程》之三:决策树和随机森林

如果我们想重新加载这个模型,只需调用加载的函数:
带你读《C#神经网络编程》之三:决策树和随机森林

加载和保存数据模型非常简单。你也可以使用序列化形式保存模型。我们将需要在XML和二进制格式之间进行选择。SharpLearning的另一个非常好的设计特征是,序列化模型允许我们序列化到IPredictorModel接口。如果每个模型都与接口相符,那么更换模型将变得更加容易。采取如下方式来完成相关操作:
带你读《C#神经网络编程》之三:决策树和随机森林
带你读《C#神经网络编程》之三:决策树和随机森林

表3-1为即时训练误差和测试误差。

带你读《C#神经网络编程》之三:决策树和随机森林

当报告模型的性能时,即使训练误差较低,也应该始终使用测试误差,因为这评估了模型概括新数据误差的程度。
现在介绍超参数。超参数是影响机器学习算法学习过程的参数。你可以通过调整超参数来调整流程,进而提高性能和可靠性。与此同时,你也可以调整不正确的参数,获得一些非预期操作的结果。让我们来看看错误地调整超参数后可能会发生的一些情况:

  • 如果模型过于复杂,可能出现所谓的高方差,或过度拟合。
  • 如果模型过于简单,可能出现所谓的高偏差,或低度拟合。

对于那些没有手动调过参数的人来说(几乎在实践中都会发生这样的过程)可能会占用相当多的时间。随着模型超参数的数量增加,调整时间和工作量也随之增加。解决这一问题的最佳方法是使用优化器,让它为你完成工作。为此,SharpLearning可以给你带来巨大的帮助,因为有许多优化器可供使用。下面列出了其中的一些优化器:

  • 网格搜索
  • 随机搜索
  • 粒子群(我们将在第7章中的7.3节“用粒子群优化算法代替后向传播”中讨论)
  • 贝叶斯优化
  • 全局有界下山单纯形法

让我们举例说明。
创建一个学习器并使用默认参数,尽可能使用好的参数。一旦我们找到参数并创建了学习器,就需要创建模型。然后我们将预测训练和测试集。完成前述所有步骤后,我们将测量测试集上的误差并记录下来:
带你读《C#神经网络编程》之三:决策树和随机森林
带你读《C#神经网络编程》之三:决策树和随机森林

表3-2所示为测试集误差。

带你读《C#神经网络编程》之三:决策树和随机森林

完成该部分后,就确定了基准。我们用随机搜索优化器来调整超参数,看是否能得到更好的结果。为此,需要建立超参数的界限,这样优化器就能知道该如何调整。做法如下:
带你读《C#神经网络编程》之三:决策树和随机森林

你注意到我们用对数变换计算学习率了吗?你知道我们为什么这么做吗?答案是:确保在值的整个范围内分布更加平均。最小值和最大值之间范围差异较大(0.02 -> 0.2),所以对数变换是最好的方式。
现在需要一个验证集帮助我们衡量模型在优化过程中对未知数据的概括程度。因此,我们需要进一步拆分训练数据。在优化过程中我们将不使用当前的测试集。如果不这样做,在最终误差估计上可能存在显著偏差,这不是我们想要的结果:
带你读《C#神经网络编程》之三:决策树和随机森林

优化器还需要一个目标函数。该函数将采用双数组作为输入(包括超参数集),并返回一个包含验证误差和相应超参数集的优化结果:
带你读《C#神经网络编程》之三:决策树和随机森林
带你读《C#神经网络编程》之三:决策树和随机森林

一旦定义了objective函数,我们就可以创建并运行优化器以找到最佳参数集。从运行优化器30次迭代开始,尝试30组不同的超参数:
带你读《C#神经网络编程》之三:决策树和随机森林

一旦运行,优化器就应该能找到一组最佳的超参数。让我们看看具体情况:

  • 树:277
  • 学习率:0.035
  • 最大树深度:15
  • 子样品率:0.838
  • 特征拆分:4

现在我们获得了一组在验证集测量过的最佳超参数,可以用这些参数创建一个学习器,并用整个数据集学习一个新模型:
带你读《C#神经网络编程》之三:决策树和随机森林

获得最后一组完整的超参数后,把这些参数传递给学习器,这样能够显著减少测试误差。而手动操作将会耗费我们大量的时间。表3-3所示为测量误差比较。

带你读《C#神经网络编程》之三:决策树和随机森林

3.4 示例代码和应用程序

在接下来的几节中,我们将看到一段缺少完整注释的代码示例。它是纯C#代码,应该能便于所有人理解。
让我们快速了解一下如何用SharpLearning预测观察值。下面展示为一个完整的没有注释的代码示例:
带你读《C#神经网络编程》之三:决策树和随机森林

3.4.1 保存模型

下面的代码示例将向你展示保存模型有多么容易:
带你读《C#神经网络编程》之三:决策树和随机森林

3.4.2 均方差回归指标

均方差(MSE)是测量平均误差的指标。更具体地说,它能够衡量估计值和期望值之间的平均差距。均方差通常为非负数,接近零将更好。通过SharpLearning计算误差指标非常容易,如以下代码所示:
带你读《C#神经网络编程》之三:决策树和随机森林

3.4.3 F1分数

在讨论F1分数前,必须先讨论准确率和召回率。
准确率是正确预测的正观察值与总预测的正观察值的比率。打个不恰当的比方是:所有说要来的人中,有多少人来了?
召回率(敏感度)是正确预测的正观察值与总观察值的比率。
F1分数是准确率与召回率的加权平均值。
下面是如何用SharpLearning计算F1分数:
带你读《C#神经网络编程》之三:决策树和随机森林

3.4.4 优化

以下是如何用粒子群优化器返回最优结果函数的示例:
带你读《C#神经网络编程》之三:决策树和随机森林

以下是如何用网格搜索优化器通过尝试所提供参数的所有组合进行优化的代码示例:
带你读《C#神经网络编程》之三:决策树和随机森林

以下是如何用随机搜索优化器,在给定的最小值和最大值之间随机初始化参数。最终返回最优结果函数的结果:
带你读《C#神经网络编程》之三:决策树和随机森林

3.4.5 示例应用程序1

掌握了前面的知识后,我们开始编写第一个示例应用程序。该程序本身非常简单,旨在用最少的代码在应用程序中实现这些技术。为了直观呈现,图3-4是程序的输出结果。

带你读《C#神经网络编程》之三:决策树和随机森林

代码
以下是我们的示例程序代码,并输出前面的分析结果。正如你所见,代码非常简单,这些都是我们之前已经浏览过的代码(以之前更简洁)。我们将尽量减少注释,让你更专注代码本身。这个样本将读入我们的数据,将其解析为观察值和目标样本,然后用1000棵树创建一个学习器。随后我们将用学习器学习并创建模型。完成后,我们将计算出均方差,并在屏幕上显示出来:
带你读《C#神经网络编程》之三:决策树和随机森林

3.4.6 示例应用程序2—葡萄酒质量

在接下来的应用程序中,我们将根据创建的模型,运用所学知识来确定葡萄酒最重要的特征。图3-5是完成后的输出结果。

带你读《C#神经网络编程》之三:决策树和随机森林

代码
以下是应用程序的代码。首先我们将数据加载并解析为观察值和目标样本集。由于这是一个回归样本,我们将把数据样本按7 : 3分割,70%用于训练,30%用于测试。我们从这些数据中创建了随机森林学习器和模型。随后,计算出训练误差和测试误差,并按特征重要性进行排序,如模型所发现的情况:
带你读《C#神经网络编程》之三:决策树和随机森林

3.5 小结

在本章中,我们学习了决策树和随机森林。我们还学习了如何使用开源框架Sharp-Learning,并将框架强大的功能添加到应用程序中。在下一章中,我们将学习面部和运动检测,并向你展示如何利用这一激动人心的技术开发应用程序!下章中,你会见到我的宠物—法国斗牛犬,它会出现在大部分示例中。

3.6 参考文献

带你读《C#神经网络编程》之三:决策树和随机森林

上一篇:Java网络编程与NIO详解10:深度解读Tomcat中的NIO模型


下一篇:unix网络编程之简介