周志华深度森林deepforest原理解析,详细解释每一个细节,

深度森林目标

目标:解决深度学习是否可以用不可微模块实现的问题

笔记:

1、什么是可微分模块?

在深度学习中,尤其是基于神经网络的模型中,“可微分”是一个非常重要的概念。它指的是模型的输出相对于其参数的导数是存在的且可以计算的。这个特性使得我们能够利用梯度下降等优化算法来训练模型,即通过不断调整参数,使得模型的输出与真实值之间的误差最小化。

神经网络之所以成功,很大程度上归功于其可微分的特性。 神经网络中的每个神经元都执行一个简单的数学运算,这些运算都是可微分的。通过将这些可微分的运算层层叠加,就构成了一个复杂的神经网络。

2、什么是非可微分模块?

与可微分模块相反,非可微分模块是指其输出相对于输入或参数的导数不存在或难以计算的模块。这些模块通常涉及到一些离散的操作、搜索过程或符号运算,这些操作在数学上是不可微的。

常见的非可微分操作包括:

  • 离散化操作: 例如,将连续值转换为离散值(如量化、硬编码等)。
  • 搜索和优化问题: 许多问题需要通过搜索或优化算法来求解,这些算法通常涉及到非连续的跳跃。
  • 符号运算: 符号运算涉及到对符号进行操作,而不是对数值进行操作,这些操作通常是不可微的。

离散化操作举例:

  • 将人的年龄离散化为"儿童"、"青少年"、"成年"、"老年"等类别。
  • 将颜色特征"红色"、"绿色"、"蓝色"分别编码为[1, 0, 0]、[0, 1, 0]、[0, 0, 1]。
  • 将连续的空间数据(如高程、温度)转换为离散的栅格数据,比如将地形高程数据转换为等高线图。
  • 在时间序列分析中,将连续的时间序列数据分割成固定长度的时间窗口

搜索和优化问题举例:

  • 旅行商问题: 在搜索最优路径的过程中,算法可能会突然从一条路径跳跃到另一条完全不同的路径,以寻找更好的解。
  • 蛋白质折叠问题: 蛋白质的折叠是一个非常复杂的过程,涉及到大量的原子之间的相互作用。搜索算法需要在巨大的搜索空间中寻找能量最低的构象,这可能涉及到大量的非连续跳跃。
  • 遗传算法: 遗传算法通过模拟生物进化过程来求解优化问题。在遗传算法中,种群中的个体通过交叉和变异产生新的个体,这可以看作是一种非连续的跳跃。

符号运算:

符号运算是指对数学表达式中的符号进行操作,而不是对具体的数值进行计算。这些符号可以代表变量、常数、函数等。在符号运算中,我们关注的是表达式的结构和变换,而不是求得一个具体的数值结果。符号代表的是一个概念,而不是一个具体的数值。对于符号的操作,我们很难定义一个连续的、可导的函数。

gcForest

深度神经网络中的表征学习主要通过逐层处理原始数据中的特征来实现。

笔记:

Representation learning (表征学习):

  • 什么是表征? 表征可以理解为对数据的另一种描述方式,或者说是对数据更高层次的抽象。比如,对于一张图片,原始数据是像素值,而表征可以是“这是一只猫”这样的抽象概念。
  • 为什么需要表征学习? 在传统的机器学习算法中,我们通常需要手动提取特征。而表征学习的优势在于,神经网络可以自动从数据中学习到有效的特征,从而提高模型的性能。

Deep neural networks (深度神经网络):

  • 深度神经网络是一种包含多个隐藏层的神经网络。这些隐藏层可以学习到越来越抽象的特征。

Layer-by-layer processing (逐层处理):

  • 深度神经网络中的信息是逐层传递的。每一层的神经元都会对上一层的输出进行处理,提取出更高级的特征。

Raw features (原始特征):

  • 原始特征就是输入数据中最基本、最原始的特征。比如,对于一张图片,原始特征就是每个像素点的数值。

深度神经网络通过逐层堆叠多个隐藏层,来对原始数据进行逐层处理。每一层都会学习到比上一层更抽象、更复杂的特征。最终,通过这些层层递进的特征提取,神经网络可以学习到对任务有用的高层语义特征,从而实现对数据的准确分类或预测。

举个例子:

假设我们要训练一个神经网络来识别猫的图片。

  • 输入层: 输入的是一张图片的像素值,也就是原始特征。
  • 第一层隐藏层: 这层神经元可能学习到一些简单的边缘特征,比如垂直线、水平线等。
  • 第二层隐藏层: 基于第一层的特征,这层神经元可能学习到更复杂的形状,比如圆形、三角形等。
  • 第三层隐藏层: 这一层的神经元可能学习到猫的耳朵、眼睛、鼻子等局部特征。
  • 输出层: 最终,输出层会根据这些高层特征判断这张图片是否为猫。

接下来讲gcForest的级联森林结构,先补充几个概念。

信息增益

信息增益(Information Gain)用于衡量一个特征对于分类任务的重要性。简单来说,它告诉我们使用某个特征来划分数据集能够带来多少信息增益,也就是能够让数据集变得多“纯”。

举个例子:

你有一堆水果,你需要根据颜色、形状等特征来将它们分类。信息增益就像一个工具,可以帮你找出哪个特征最能有效地将水果分到正确的类别中

信息增益越大,说明使用这个特征进行划分后,数据集的纯度提高得越多,这个特征也就越重要

在决策树算法中,我们通常选择信息增益最大的特征作为节点的划分属性。这样可以保证每次划分都能最大程度地减少数据集的不确定性,从而构建出更准确的决策树。

决策树

决策树通过一系列规则对数据进行分类或回归。其结构就像一棵树,从根节点开始,通过分支节点不断向下延伸,最终到达叶子节点。每个节点代表一个属性测试,每个分支代表一个测试结果,而叶子节点则对应于最终的分类结果或数值。

决策树的工作原理:

  • 特征选择: 从所有特征中选择一个最能区分样本的特征作为节点的划分属性。
  • 决策树生成: 根据选定的特征,将数据集分成若干子集,每个子集对应一个分支。
  • 递归划分: 对每个子集重复上述过程,直到满足停止条件(如节点中的样本都属于同一类,或达到预设的树深)。

举个例子:

假设我们想要根据天气情况来决定是否打球。

我们收集了一些历史数据,包括天气(晴天、阴天、雨天)、温度(高、低)、湿度(高、低)以及是否打球(是、否)。

构建决策树

  • 选择根节点: 我们选择“天气”作为根节点,因为它似乎对是否打球的影响最大。
  • 划分数据集: 根据“天气”的不同取值,将数据集分成三个子集:晴天、阴天和雨天。
  • 计算信息增益或其他指标: 对于每个子集,我们计算其信息增益(或其他指标),选择信息增益最大的特征作为下一个节点的划分属性。
  • 重复步骤2和3: 对于每个子集,继续选择最优特征进行划分,直到满足停止条件(例如,所有样本都属于同一类,或者达到预设的树深)。

最终得到的决策树可能如下:

解释决策树:

  • 根节点(天气): 如果天气是晴天,则继续判断湿度。
  • 分支节点(湿度): 如果湿度高,则不打球;如果湿度低,则打球。
  • 叶子节点(打球): 叶子节点表示最终的决策结果。

随机森林:由决策树构成的强大集成学习算法

什么是随机森林:

随机森林(Random Forest)是一种集成学习方法,它通过构建多棵决策树,并对这些树的预测结果进行投票表决(分类)或取平均值(回归)来实现最终的预测。

随机指的是在构建每棵决策树的过程中,会引入随机性,以减少过拟合的风险并提高模型的泛化能力。

核心思想就是多棵决策树投票表决

随机森林的工作原理:

  • Bootstrap抽样: 对于每棵决策树,从原始数据集中有放回地随机抽取一部分样本(Bootstrap),作为这棵树的训练集。这样,每棵树的训练集都不同,且有些样本可能在多棵树中重复出现,而有些则可能从未被选中。
  • 特征随机选择: 在构建每棵决策树的过程中,在每个节点上,不是考虑所有的特征,而是随机选择一部分特征,然后从这些特征中选择最佳分裂特征。
  • 决策树生长: 每棵决策树都独立地生长,直到达到预设的终止条件,如树的深度、节点中的样本数等。
  • 预测: 当有新的样本需要预测时,将其输入到每棵决策树中,得到一个预测结果。对于分类问题,多数投票决定最终的类别;对于回归问题,取所有树的预测结果的平均值作为最终预测。

随机森林的优点:

  • 准确率高: 随机森林通常具有很高的准确率,尤其在处理高维数据和噪声数据时表现出色。(详细解释见下文(1))
  • 不易过拟合: 通过Bootstrap抽样和特征随机选择,随机森林能有效地减少过拟合的风险。(详细解释见下文(2))
  • 可处理高维数据: 随机森林对特征数量不敏感,能有效处理高维数据。(详细解释见下文(3))
  • 能处理多种数据类型: 随机森林可以处理数值型和类别型数据。(详细解释见下文(4))
  • 具有较强的鲁棒性: 随机森林对异常值和噪声数据具有较强的鲁棒性。(详细解释见下文(5))
  • 可以评估特征的重要性: 通过计算每个特征在所有树中被选为分裂特征的次数,可以评估特征的重要性。

(1)为什么随机森林准确率高?

比如,你想要预测明天的天气。 你可以问一个气象学家,他可能会根据他的经验和模型给出一个预测。但是,如果你问100个气象学家,然后把他们的预测结果综合起来,是不是会更准确呢?

随机森林就是这么做的。 它不是只用一棵决策树来做预测,而是造了一片森林,里面有很多棵决策树。每棵树都是根据不同的数据样本和特征训练出来的。当有新的数据需要预测时,这些树会各自给出一个预测结果,然后大家一起投票,票数最多的那个结果就是最终的预测。

总结一下,随机森林之所以准确率高,是因为它将多个“弱分类器”(单棵决策树)结合起来,形成了一个强大的“强分类器”。 这种集成学习的方法,不仅提高了模型的准确率,还增强了模型的稳定性和泛化能力。

(2)随机森林为什么不容易过拟合?
  • Bootstrap抽样:随机森林在训练每棵决策树时,都会从原始数据中随机抽取一部分数据来训练。这样,每棵树看到的都是不同的数据,这就增加了模型的多样性。
  • 特征随机选择: 每棵树在生长过程中,并不是考虑所有的特征,而是随机选择一部分特征来进行分裂。这样可以防止模型过分依赖某一个特征,从而降低过拟合的风险。

总结一下,随机森林通过Bootstrap抽样和特征随机选择,让每一棵决策树都学到了一些不同的东西,这样就可以有效地降低过拟合的风险,提高模型的泛化能力。

(3)随机森林为什么能处理高维数据?
  • 特征随机选择: 每棵决策树在生长过程中,并不是考虑所有的特征,而是随机选择一部分特征来进行分裂。
  • 多棵树的集成: 随机森林由很多棵决策树组成,每棵树都基于不同的样本和特征进行训练。这样,即使有些特征对预测结果的影响不大,或者甚至是噪音,也不会对最终的预测结果产生太大的影响。

为什么这样做就能处理高维数据呢?

  • 降低维度: 通过特征随机选择,随机森林实际上是在对数据进行降维。这样可以有效地避免维度灾难。

理解:

随机森林就像是一个由很多侦探组成的团队,每个侦探都只关注一部分线索(特征)。虽然每个侦探可能只掌握了部分信息,但是通过他们的共同努力,就可以破获一个复杂的案件(高维数据)。

(4)随机森林为什么能处理多种数据类型?

想象一下,你想要根据一个人的身高、体重、性别、爱好等信息来判断他喜欢什么类型的运动。

  • 身高和体重数值型数据,我们可以直接用数值来表示。
  • 性别和爱好类别型数据,需要用文字或者编码来表示。

随机森林是如何同时处理这两种类型的数据的呢?

  • 决策树的节点: 决策树在分裂节点时,既可以根据数值型特征进行分裂(比如身高大于180cm的人),也可以根据类别型特征进行分裂(比如性别为男的人)。
  • 特征编码: 对于类别型特征,随机森林会对它们进行编码,比如用0和1来表示性别。
  • 集成学习: 随机森林由很多棵决策树组成,每棵树都会对不同类型的特征进行处理。最终,通过投票的方式,得到一个综合的预测结果。

理解:

随机森林就像是一个由很多不同专长的侦探组成的团队。有些侦探擅长分析人的身高体重(数值型数据),有些侦探擅长分析人的性别爱好(类别型数据)。通过他们的共同努力,就可以根据一个人的各种信息,推断出他喜欢什么类型的运动。

(5)为什么随机森林对异常值和噪声数据这么“免疫”?
  • 多棵树的集成: 随机森林由很多棵决策树组成。每棵树都是基于随机抽样得到的训练数据构建的。因此,即使有一些训练数据包含异常值或噪声,它们的影响也会被分散到不同的树上。
  • 投票机制: 在进行预测时,随机森林会对所有决策树的预测结果进行投票。这样,即使有一些树的预测结果受到了异常值或噪声的影响,只要大多数树的预测结果是正确的,最终的预测结果就不会受到太大的影响。
  • 特征随机选择: 每棵决策树在生长过程中,并不是考虑所有的特征,而是随机选择一部分特征。这样可以减少异常特征对模型的影响。

理解:

随机森林就像是一个由很多医生组成的团队。每个医生都会根据患者的病历(数据)来诊断病情。即使有一些病历记录有错误(异常值或噪声),只要大多数医生都能做出正确的诊断,那么最终的诊断结果就不会有太大的问题。

完全随机树森林

完全随机树森林(Fully Random Forest,FRF)是随机森林(Random Forest,RF)的一种变体。它在构建决策树时引入了更强的随机性,使得模型具有更强的泛化能力,同时也降低了过拟合的风险。

特征随机森林完全随机树森林
节点分裂标准基于信息增益、基尼指数等,从所有特征中选择最佳分裂特征随机选择一个特征,并随机选择一个分裂点
特征选择在每个节点上,从所有特征中随机选择一部分特征进行考虑在每个节点上,从所有特征中随机选择一个特征

级联森林结构

级联森林结构示意图

原文:假设级联的每一层由两个随机森林(黑色)和两个完全随机树森林(蓝色)组成。假设有三个类别需要预测;因此,每个森林将输出一个三维类别向量,然后将其连接起来,重新表示原始输入。


级联森林是一种层次化的集成模型,它结合了随机森林和完全随机树森林的优点,通过多层决策来提高分类和回归性能。


过程:

  • 输入数据:原始输入数据被馈送到级联的第一层。
  • 逐层处理
    • 特征提取:随机森林和完全随机树森林都处理输入数据并输出一个三维类别向量。该向量表示输入属于每个类别的可能性。
    • 连接:来自两个随机森林和两个完全随机树森林的输出被连接起来,创建一个新的、更具信息量的输入数据表示。
  • 下一层:这个新的表示被馈送到级联的下一层,重复该过程。
  • 最终输出:级联的最后一层产生最终预测,它是所有层预测的加权组合。

级联森林的工作原理:

  • 级联结构:

    • 级联森林由多层组成,每一层都包含多个决策树森林。
    • 每一层的输入是上一层的输出,或者原始数据。
    • 每一层中的决策树森林对输入数据进行特征提取和分类。
    • 最终的输出是最后一层的分类结果。
  • 特征提取和分类:

    • 每一层的决策树森林通过学习数据中的特征,生成新的特征表示。
    • 这些新的特征表示可以看作是原始数据的更高层次的抽象。
    • 随着层数的增加,特征表示的抽象程度也越来越高。
  • 多样性:

    • 每一层中的决策树森林可以是随机森林,也可以是完全随机树森林。
    • 不同类型的决策树森林有助于提高模型的多样性,从而提高模型的泛化能力。

特征级联森林深度神经网络
基本单元决策树神经元
学习方式基于树的结构学习基于梯度下降优化
可解释性
超参数调优较少较多

举例:

假设我们想要训练一个模型来识别手写数字(0-9)。

级联森林的方法:

  • 第一步: 和传统方法一样,我们准备相同的数据集。
  • 第二步: 我们构建一个级联森林模型:
    • 第一层: 将手写数字图片输入到多个随机森林中。每个随机森林会提取一些基本的特征,比如数字的笔画粗细、形状等。
    • 第二层: 将第一层所有随机森林的输出结果(也就是提取到的特征)作为输入,输入到下一层的随机森林中。这一层会基于上一层提取到的特征,学习更高级的特征,比如数字的整体结构等。
    • 第三层: 重复第二步,直到达到预设的层数或者模型性能不再提升。
  • 第三步: 最终,最后一层的随机森林会输出一个分类结果,即输入图片代表的数字。

级联森林方法为什么效果好:

  • 深层特征提取: 级联森林通过逐层提取特征,能够学习到更深层次、更抽象的特征。就像我们识别一个数字,不仅要看它的笔画,还要看它的整体形状。
  • 信息逐步丰富: 每一层随机森林都会为下一层提供更丰富的信息,使得模型的表达能力更强。
  • 提高准确率: 由于学习到了更深层次的特征,级联森林在复杂分类任务上往往能取得比单个随机森林更高的准确率。

应用级联森林分析"鸢尾花数据集"的代码实例:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn import tree
from sklearn.inspection import DecisionBoundaryDisplay
from matplotlib.animation import FuncAnimation
from sklearn.tree import plot_tree  # 导入更直观的决策树可视化函数

# 加载鸢尾花数据集
"""
load_iris() 加载鸢尾花数据集,这是一个经典的分类数据集。
X 存储特征,即鸢尾花的各种测量值。
y 存储标签,即鸢尾花的种类。
"""
iris = load_iris()
X = iris.data
y = iris.target

# 划分训练集和测试集
"""
train_test_split 将数据集随机分为训练集和测试集,其中测试集占20%。
random_state=42 用于保证每次运行时划分结果一致,方便复现。这个参数的作用是 设置随机数生成器的种子,从而使得每次运行代码时,产生的随机数序列都是相同的。
"""
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建级联森林
def create_cascade_forest(X_train, y_train, n_estimators=3, max_depth=5, n_cascade_layers=3):
    """
    创建一个级联森林分类器

    参数:
        X_train: 训练集特征
        y_train: 训练集标签
        n_estimators: 每个随机森林中的树的数量
        max_depth: 每棵树的最大深度
        n_cascade_layers: 级联层的数量

    返回:
        一个列表,包含每一层的随机森林分类器
    """
    cascade_forest = []
    for i in range(n_cascade_layers):
        rf = RandomForestClassifier(n_estimators=n_estimators, max_depth=max_depth, random_state=i)
        """
        RandomForestClassifier: 这是一个随机森林分类器。
        n_estimators: 每个随机森林中树的数量。
        max_depth: 每棵树的最大深度。
        random_state=i: 每个随机森林的随机种子设置为 i,保证每次创建的随机森林都不完全相同。
        """
        rf.fit(X_train, y_train)
        """
        使用训练数据 X_train 和 y_train 来训练当前层的随机森林。
        """
        cascade_forest.append(rf)
        """
        将训练好的随机森林添加到 cascade_forest 列表中,这个列表用来存储每一层的随机森林。
        """
        X_train = rf.predict_proba(X_train)
        """
        rf.predict_proba(X_train): 使用当前层的随机森林对 X_train 进行预测,得到每个样本属于各个类别的概率。
        X_train = ...: 将上一层随机森林的预测概率作为下一层的输入特征。
        也就是说,下一层的随机森林并不是直接对原始特征进行训练,而是对上一层模型预测得到的概率分布进行训练。
        """
    return cascade_forest

# 创建一个三层级联森林
cascade = create_cascade_forest(X_train, y_train)

# 可视化所有层的所有决策树
"""
enumerate(cascade):对 cascade 列表进行枚举,同时返回索引 layer_idx 和对应的随机森林 rf。

plt.subplots():创建一个新的绘图区域。
nrows=1, ncols=len(rf.estimators_):设置绘图区域的行数为1,列数等于当前层随机森林中的树的数量。
figsize=(20, 10):设置绘图区域的大小。

enumerate(rf.estimators_):对当前层随机森林中的所有树进行枚举,同时返回索引 tree_idx 和对应的决策树 estimator。

plot_tree():使用 sklearn.tree 模块中的 plot_tree 函数绘制决策树。
feature_names=iris.feature_names:设置特征的名称。
class_names=iris.target_names:设置类别的名称。
filled=True:用颜色填充节点。
ax=axes[tree_idx]:将决策树绘制到指定的子图中。

axes[tree_idx].set_title 设置标题: 为每个子图设置标题,表示这是第几层中的第几棵树。


"""
def visualize_all_trees(cascade):
    for layer_idx, rf in enumerate(cascade):
        fig, axes = plt.subplots(nrows=1, ncols=len(rf.estimators_), figsize=(20, 10))
        for tree_idx, estimator in enumerate(rf.estimators_):
            plot_tree(estimator, feature_names=iris.feature_names,
                       class_names=iris.target_names, filled=True, ax=axes[tree_idx])
            axes[tree_idx].set_title(f"Tree {tree_idx+1} in Layer {layer_idx+1}")
    plt.show()

# 可视化决策边界动画(仅适用于二维数据)
def visualize_boundary_animation(cascade, X, y):
    fig, ax = plt.subplots()
    ax.scatter(X[:, 0], X[:, 1], c=y, s=30, edgecolor="k")

    def update(frame):
        clf = cascade[frame]
        disp = DecisionBoundaryDisplay.from_estimator(
            clf, X, response_method='predict', alpha=0.5, ax=ax
        )
        disp.ax_.set_title(f"Decision Boundary of Layer {frame+1}")
        return disp,

    anim = FuncAnimation(fig, update, frames=len(cascade), interval=1000)
    plt.show()

# 可视化所有层的所有决策树
visualize_all_trees(cascade)

# 可视化决策边界动画(将X限制为二维数据)
X_2d = iris.data[:, :2]  # 只取前两个特征
visualize_boundary_animation(cascade, X_2d, y)

每个随机森林中树的数量为3时,分类结果:

每个随机森林中树的数量为100时,分类结果:

构建级联森林

每一层级由决策树森林的集成构成。

多样性对于集成构建至关重要,引入不同类型的森林以促进多样性。

简化情况,使用两种完全随机树森林和两种随机森林。

每个完全随机树森林包含500棵完全随机树,通过在树的每个节点随机选择一个特征进行分裂,并一直生长树直到每个叶子节点仅包含同一类实例。

每个随机森林包含500棵树,通过随机选择√d个特征作为候选(d为输入特征的数量)并选择具有最佳基尼值的特征进行分裂。

每个森林中的树的数量是一个超参数。

为什么集成学习中多样性至关重要?

  • 在集成学习中,多样性指的是个体模型之间的差异性。
  • 减少过拟合: 不同的模型对训练数据有不同的拟合方式,这样可以减少过拟合的风险。
  • 提高泛化能力: 多样性可以帮助模型更好地捕捉数据的本质特征,从而提高模型在未知数据上的泛化能力。
  • 降低方差: 通过组合多个模型的预测,可以降低整体模型的方差,使其更加稳定。

比喻:你想要预测明天的天气。如果你只听取了一个气象专家的意见,那么预测的准确性可能不高。但是,如果你听取了多个气象专家的意见,综合考虑他们的观点,那么预测的准确性就会大大提高。


如何实现多样性?

  • 数据采样: 通过不同的采样方法(如Bootstrap采样)来生成不同的训练数据集。
  • 特征选择: 对于每个模型,随机选择不同的特征子集。
  • 算法参数调整: 对于每个模型,调整不同的算法参数。
  • 使用不同的基学习器: 比如,同时使用决策树、神经网络等。


文章中的例子实现多样性的方式:

使用了两种不同类型的决策树森林:

  • 完全随机树森林

    • 每个树在节点分裂时随机选择一个特征,而不考虑特征的重要性。
    • 这种方法可以生成高度多样化的树,因为它们不太可能产生相似的结构。
  • 随机森林

    • 每个树在节点分裂时随机选择一个特征子集,然后选择最佳特征进行分裂。
    • 这种方法可以平衡探索和利用,生成准确性较高的树。

随机森林举例:
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn import tree
import seaborn as sns

# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target

# 分割数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建随机森林分类器
rf = RandomForestClassifier(n_estimators=100, max_depth=3, random_state=42)

# 训练模型
rf.fit(X_train, y_train)

# 进行预测并评估
y_pred = rf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy:", accuracy)

# 可视化混淆矩阵
sns.heatmap(confusion_matrix(y_test, y_pred), annot=True, fmt='d')
plt.xlabel('Predicted')
plt.ylabel('True')
plt.title('Confusion Matrix')
plt.show()

# 可视化第一棵决策树
plt.figure(figsize=(12,8))
tree.plot_tree(rf.estimators_[0], filled=True)
plt.show()

test集混淆矩阵

随机森林中的一棵决策树

决策树解释:

  • x[i]。鸢尾花数据集有四个特征:萼片长度、萼片宽度、花瓣长度、花瓣宽度。因此,x[3]就代表了所有样本的花瓣宽度。
  • gini指数。随机森林中的每棵决策树在分裂节点时,都会计算不同特征的Gini指数,选择Gini指数增益最大的特征作为分裂特征。Gini指数衡量了节点中样本的纯度,Gini指数的取值范围在0到1之间。Gini指数越小,表示节点的纯度越高,纯度越高的节点,分裂的意义就越小。通过最小化Gini指数,随机森林可以构建出更准确的分类模型。
  • samples。随机森林在构建每棵决策树时,会从原始数据集中有放回地随机抽取一部分样本作为训练集。这个随机抽取的过程被称为bootstrap sampling。samples=74,这意味着在构建这棵特定的决策树时,算法随机抽取了74个鸢尾花样本作为初始训练集。
  • value。???value数组就是用来记录每个节点中不同类别样本数量的。???为什么74个样本,value里面样本和为120,即为总的训练集数量。为什么从根节点就分类好了???

完全随机森林举例:
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.tree import plot_tree

# 直接从sklearn加载鸢尾花数据集
iris = load_iris()
X = iris.data
y = iris.target

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建完全随机森林分类器
model = ExtraTreesClassifier(n_estimators=100, random_state=42)

# 训练模型
model.fit(X_train, y_train)

# 进行预测
y_pred = model.predict(X_test)

# 评估模型性能
print("Accuracy:", accuracy_score(y_test, y_pred))
print("\nClassification Report:\n", classification_report(y_test, y_pred))

# 混淆矩阵
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt="d")
plt.title('Confusion Matrix')
plt.xlabel('Predicted')
plt.ylabel('True')
plt.show()


# 特征重要性
importances = model.feature_importances_
indices = np.argsort(importances)[::-1]
feature_names = iris.feature_names

# 强制转换为整数,确保长度一致
indices = indices.astype(int)

# 可视化特征重要性
plt.figure(figsize=(12,8))
plt.title("Feature Importances")
plt.bar(range(X.shape[1]), importances[indices],
       color="r", align="center")
plt.xticks(range(X.shape[1]), [feature_names[i] for i in indices])  # 使用列表推导式
plt.xlim([-1, X.shape[1]])
plt.show()


# 可视化随机森林中的第一棵决策树
plt.figure(figsize=(20,10))
plot_tree(model.estimators_[0], feature_names=iris.feature_names,
          class_names=iris.target_names, filled=True)
plt.show()

test集混淆矩阵

特征重要性

完全随机森林中的一棵决策树

级联

构建过程:

图1

图2  类别向量生成过程示例。

叶节点中不同类别的样本比例反映在类别向量中,作为下一层级分类器的输入

首先,根据训练集,生成了一个森林,假设森林里有500棵决策树。

对于训练集里的一个样本A,假设A落在了决策树1的一个叶子节点里,该叶子节点的类别分布是[0.2 0.5 0.3]。A也落在了决策树2的一个叶子节点里,该叶子节点的类别分布是[0.3 0.4 0.3]。...... A也落在了决策树500的一个叶子节点里,该叶子节点的类别分布是[1.0 0.0 0.0]。

那么,对于森林来说,样本A的类别向量就等于它所在的决策树的叶子节点的类别分布的平均值,为[0.5 0.3 0.2]。

类别分布的含义:

假设一个叶子节点中包含了10个样本,其中有6个属于类别A,3个属于类别B,1个属于类别C。那么,这个叶子节点的类别分布就是:

  • 类别A:6/10 = 60%
  • 类别B:3/10 = 30%
  • 类别C:1/10 = 10%

类别向量的含义:

例如样本A在某个森林的类别向量为[0.5 0.3 0.2],即认为该森林认为样本A有50%的概率是1类,30%的概率是2类,20%的概率为3类。

特征增强:

假设样本A原始特征有m个

第一级的一个森林给出样本A的一个类别向量[0.5 0.3 0.2],则在下一级中,该类别向量[0.5 0.3 0.2]会成为样本A的新的3个特征,即第二级样本A有m+3个特征。

同理,第一级有4个森林,则第一级会给样本A增加4*3=12个新的特征。每一级都产生12个新特征,也就是说,从第二级开始,样本A的输入特征变为m+12个特征

自动确定级联层级:

在扩展新层级后,整个级联的性能将在验证集上进行评估,如果性能没有显著提升,则训练过程将终止;因此,级联层级的数量自动确定。

多粒度扫描

图3  使用滑动窗口扫描的特征重新表示。

假设有三个类,原始特征是400-dim,滑动窗口是100-dim。

图4  gcForest的整个过程。

假设有三个类要预测,原始特征是400-dim,并且使用三种大小的滑动窗口。

1、特征变换(进入级联森林前)

如图3所示。

  • 对于一维的,400个特征,用大小为100个特征的窗口,可以将其转换为301个特征向量。
  • 每个特征向量视为一个样本,即301个样本。
  • 这301个样本,放入两个森林中训练。对于三分类任务,一个森林给一个样本生成一个三维类别向量。301个样本,两个森林,则生成3*301*2=1806个特征。
  • 1806个特征作为原始特征,进入第一级的森林中开始训练。
  • 对于二维的,如20*20的像素板,400个特征,则用10*10的窗口,可以转换为121个特征向量。后续同上。
  • 若变换后的特征向量太长时,可以进行特征采样。

2、多粒度特征变换+级联训练

如图4所示。

  • 用3个不同粒度进行特征变换。则在原来的级联森林基础上,将每级,再分为三级。
  • 粒度1生成的原始特征,与1A级生成的类别向量结合,进行特征增强。输入下一级。
  • 粒度2生成的原始特征,与1B级生成的类别向量结合,进行特征增强。输入下一级。
  • 粒度3生成的原始特征,与1C级生成的类别向量结合,进行特征增强。输入下一级。
  • 粒度1生成的原始特征,与2A级生成的类别向量结合,进行特征增强。输入下一级。
  • .............
  • 经过测试机验证,性能不再增加,停止,聚合最后一层中的四个三维类别向量。
  • 根据聚合后的三维类别向量,给出分类结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值