深度学习

深度学习

神经网络

神经元

一个接收若干信息,并产生若干结果的一个基本单位。

神经网络定义

神经网络由若干层构成,每层可以包含若干节点,同时从上一层接收信息,并将结果传输给下一层

全连接神经网络

对于朴素的神经网络,需要去考虑每一层怎么设计,每个神经元需要哪些信息,并产生什么样的结果,这样子从网络搭建上来说是很困难的。

因此,可以不用限制神经元接收的数据,让每一层的神经元均连接上一层的所有神经元(或输入层节点)。

即,将输入层数据是为一个特征向量$\vec{x}$,这个向量将被传输到隐藏层的神经元,然后计算出几个激活值(会作为一个新的向量传输到下一层),最后传输到输出层。

激活函数

令$a_{j}^{[l]}$表示第$l$层中第$j$个神经元计算得到的激活值。

则:$a_{j}^{[l]} = g(\vec{w}{j}^{[l]} \cdot \vec{a}{j}^{[l - 1]} + b_{j}^{[l]})$

Tips: 怎么得到这个式子的呢,可以从朴素的逻辑回归模型来看,即输入若干特征,经过运算后得到预测结果,那么此时输入特征是哪里来的呢?必然是从上一层传输过来的,而模型的参数$(\vec{w}{j}, b{j})$则必然是本层的,因此只有向量$\vec{a_j}$的上标是$[l - 1]$,参数$\vec{w_{j}}, b_{j}$的上标均为$[l]$,而每一层的$a_j(j = 1, 2, \ldots, n)$将会组成一个向量$\vec{a_j}$作为输入传入下一层。

前向传播

根据神经网络从输入层一层一层计算最后到输出层得到结果的过程就叫做前向传播。

tensorflow代码实现

如下图,传入向量$\vec{x}$,经过两层运算后得到结果$\vec{a}^{[2]}$

前向传播例1

1
2
3
4
5
6
7
8
9
import tensorflow
import numpy as np
# 以下程序仅为网络计算流程
x = np.array([[200.0, 17.0]])
layer_1 = Dense(units = 3, activation = "sigmoid")
a1 = layer_1(x)

layer_2 = Dense(units = 1, activation = "sigmoid")
a2 = layer_2(a1)

其他tensorflow方法

1
2
3
4
5
6
7
8
# 将层按顺序堆叠,即不需要顺序编写代码进行每层运算
model = Sequential([layer_1, layer_2])
# 配置训练参数:optimizer:优化器,loss:损失函数,metrices:评估指标
model.compile(...)
# 训练模型:x:输入数据,y:训练标签,epochs:训练轮次,batch_size:批次大小
model.fit(x, y)
# 使用训练好的模型对新数据进行预测
model.predict(x_new)

前向传播朴素实现

此时依然以上图模型为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
x = np.array([200, 17])
# 依次计算第一层3个神经元的激活值
w1_1 = np.array([1, 2])
b1_1 = np.array([-1])
z1_1 = np.dot(w1_1, x) + b1_1
a1_1 = sigmoid(z1_1)

w1_2 = np.array([-3, 4])
b1_2 = np.array([1])
z1_2 = np.dot(w1_2, x) + b1_2
a1_2 = sigmoid(z1_2)

w1_3 = np.array([-3, 4])
b1_3 = np.array([1])
z1_3 = np.dot(w1_3, x) + b1_3
a1_3 = sigmoid(z1_3)
# 合并成向量传输给下一层
a1 = np.array([a1_1, a1_2, a1_3])

w2_1 = np.array([-7, 8, 3])
b2_1 = np.array([3])
z2_1 = np.dot(w2_1, a1) + b2_1
a2_1 = sigmoid(z2_1)

前向传播一般实现

一般形式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#传入上一层激活值,神经元两种参数,以及激活函数,返回下一层激活值
def dense(a_in, W, b, g):
units = W.shape[1]
a_out = np.zeros(units)
for j in range(units):
w = W[:, j]
z = np.dot(w, a_in) + b[j]
a_out[j] = g(z)
return a_out

# 前向传播
def sequential(x):
a1 = dense(x, W1, b1)
a2 = dense(a1, W2, b2)
a3 = dense(a2, W3, b3)
a4 = dense(a3, W4, b4)
f_x = a4
return f_x
numpy优化
1
2
3
4
5
6
# 注意,此时A_in,W,B均为大写,表明这是个矩阵,而非向量
def dense(A_in, W, B, g):
# 使用numpy中矩阵乘法函数优化程序
Z = np.matual(A_in, W) + B
A_out = g(Z)
return A_out

TensorFlow

基础代码流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import tensorflow as tf
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
# 步骤1:设计模型
model = Sequential([
Dense(units = 25, activation='sigmoid'),
Dense(units = 15, activation='sigmoid'),
Dense(units = 1, activation='sigmoid'),
])
#步骤2:使用指定的损失函数编译模型
from tensorflow.keras.losses import BinaryCrossentropy
model.compile(loss=BinaryCrossentropy())
#步骤3:训练模型(fit函数实现了前向传播,损失计算反向传播,迭代的过程)
model.fit(X, Y, epochs = 100)

激活函数

Sigmoid

  • $\sigma(x) = \frac{1}{1 + e^{-x}}$

优点:

  1. 输出有明确的概率含义,是的作为二分类问题的输出层
  2. 连续性好,适合求导

缺点:

  1. 梯度消失问题:当输入值过大或过小时,函数斜率接近 $0$,导致反向传播时梯度几乎为 $0$,网络难以训练(深层网络中尤为明显)。
  2. 输出均值不是 $0$(偏向 $0.5$),会导致下一层输入的分布偏移,影响训练效率。

适用场景

主要用于二分类问题的输出层,隐藏层中已较少使用(被 ReLU 替代)。

ReLU(Rectified Linear Unit,修正线性单元)

  • $ReLU(x) = max(0, x)$

优点:

  1. 解决梯度消失:$x \gt 0$ 时斜率恒为 $1$,反向传播时梯度不衰减,深层网络能有效训练(这是它成为主流的核心原因)。
  2. 计算速度快(无需指数运算,比 sigmoid 高效)。
  3. 引入 稀疏激活:负数输入直接输出 $0$,相当于部分神经元 “休眠”,减少冗余计算,模拟生物神经元的特性。

缺点:

  1. 死亡 ReLU 问题:当输入长期为负数时,神经元会永久 “休眠”(输出恒为 $0$,梯度也为 $0$,无法更新权重)。
  2. 输出范围不固定($x$ 可无限大),可能导致训练不稳定(可通过批归一化缓解)。

适用场景:

几乎是隐藏层的默认选择,尤其在深层网络(如 CNN、MLP)中广泛使用。

Linear(线性激活函数)

  • $g(z) = z$

此时可以视为无激活函数。

适用场景:

当预测值即可能是正数,也可能是负数时,选择线性激活函数。

多类

多分类问题仍然是个分类问题,此时$y$仍然只能取少量的几个值,而不是任意值。

Softmax

以下为4分类情况下Softmax回归公式。

Softmax_例1

而对于一般情况,则对于$y = 1, 2, 3, \ldots, N$,有:

  • $z_j = \vec{w}{j} \cdot \vec{x} + b{j} \quad j = 1, \ldots, N$

  • $a_j = \frac{e^{z_{j}}}{\sum\limits_{k = 1}^{N}e^{z_{k}}} = P(y = j | \vec{x})$

note: $a_1 + a_2 + \ldots + a_N = 1$

Softmax的代价函数

代价函数

$$
\begin{aligned}
& a_1 = \frac{e^{z_1}}{e^{z_1} + e^{z_2} + \ldots + e^{z_N}} = P(y = 1 | \vec{x}) \\
& \vdots \\
& a_N = \frac{e^{z_N}}{e^{z_1} + e^{z_2} + \ldots + e^{z_N}} = P(y = N | \vec{x})
\end{aligned}
$$

损失函数

$$
loss(a_1, \ldots, a_N, y) = \begin{cases}
-log(a_1) & \text{if } y = 1 \\
-log(a_2) & \text{if } y = 2 \\
\vdots \\
-log(a_N) & \text{if } y = N
\end{cases}
$$

tensorflow实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import tensorflow as tf
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
# 这里将输出层改为softmax
model = Sequential([
Dense(units = 25, activation='relu'),
Dense(units = 15, activation='relu'),
Dense(units = 10, activation='softmax'),
])
# 这里使用稀疏交叉熵函数
from tensorflow.keras.losses import SparseCategoricalCrossentropy
model.compile(loss=SparseCategoricalCrossentropy())
#步骤3:训练模型
model.fit(X, Y, epochs = 100)

优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import tensorflow as tf
from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense
model = Sequential([
Dense(units = 25, activation='relu'),
Dense(units = 15, activation='relu'),
Dense(units = 10, activation='linear'),
])
from tensorflow.keras.losses import SparseCategoricalCrossentropy
# 将输出层设置为仅使用线性激活函数,并同时设置放置激活函数,
# 以及将交叉熵损失添加到损失函数规范中
# 此时系统会自动调用softmax计算结果,因此输出层只需要输出原始数据即可
model.compile(loss=SparseCategoricalCrossentropy(from_logits=True))
model.fit(X, Y, epochs = 100)

Tips: logits,即未经过激活函数处理的原始分数,而不是概率值

高级优化方法

Adam algorithm(Adaptive Moment estimation)

  • 如果参数在梯度下降过程中一致在接近的方向上移动,那么就增大学习率。

  • 如果参数在梯度下降过程中来回震荡,那么就减小学习率。

使用Adam的代码

1
2
3
4
5
6
7
8
9
10
model = Sequential([
tf.keras.layers.Dense(units = 25, activation='sigmoid'),
tf.keras.layers.Dense(units = 15, activation='sigmoid'),
tf.keras.layers.Dense(units = 10, activation='linear'),
])

model.compile(optimizer = tf.keras.optimizers.Adam(learning_rate = 1e-3),
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True))

model.fit(X, Y, epochs = 100)

卷积神经网络

卷积层(Convolutional Layer)

任何神经元只读取前一层输入信息的一部分。

作用:

  • 加快计算速度
  • 对训练集的需求更小

如下图:第一层包含$9$个神经元,每个神经元只能读取20个特征,第二层
包含$3$个神经元,每个神经元可以读取5个特征。

如何构建机器学习系统

调试方法

如上图,已经实现了正则化线性回归来预测房价,但是该模型在预测中出现了巨大的问题,因此需要按以下步骤进行调试:

  1. 获取更多训练集
  2. 尝试较小的特征集
  3. 尝试更多的特征集
  4. 尝试增加更多的多项式特征$(x_1^{2}, x_{2}^{2}, x_{1} x_{2}, etc)$
  5. 尝试减少$\lambda$
  6. 尝试增加$\lambda$

hint: 1,2,6主要用于解决高方差(过拟合);3,4,5主要用于解决高偏差(欠拟合)

模型评估方法

一、通过以下函数计算的结果可以判断模型是否优秀

线性回归问题

  1. 训练模型使用的代价函数 $J(\vec{w}, b)$
  • $J(\vec{w}, b) = \mathop{min}\limits_{\vec{w}, b}[\frac{1}{2m_{train}}\sum\limits_{i = 1}^{m_{train}}(f_{\vec{w}, b}(\vec{x}^{(i)}) - y^{(i)})^2 + \frac{\lambda}{2m_{train}}\sum\limits_{j = 1}^{n}w_{j}^{2}]$
  1. 计算测试集误差
  • $J_{test}(\vec{w}, b) = \frac{1}{2m_{test}}[\sum\limits_{i = 1}^{m_{test}}(f_{\vec{w}, b}(\vec{x}{test}^{(i)}) - y{test}^{(i)})^{2}]$
  1. 计算训练集误差
  • $J_{train}(\vec{w}, b) = \frac{1}{2m_{train}}[\sum\limits_{i = 1}^{m_{train}}(f_{\vec{w}, b}(\vec{x}{train}^{(i)}) - y{train}^{(i)})^{2}]$

分类问题

  1. 代价函数 $J(\vec{w}, b)$
  • $J(\vec{w}, b) = -\frac{1}{m} \sum\limits_{i = 1}^{m}[y^{(i)}log(f_{\vec{w}, b}(\vec{x}^{(i)})) + (1 - y^{(i)})log(1 - f_{\vec{w}, b}(\vec{x}^{(i)}))] + \frac{\lambda}{2m}\sum\limits_{j = 1}^{n}w_{j}^{2}$
  1. 计算测试集误差
  • $J_{test}(\vec{w}, b) = -\frac{1}{m_{test}} \sum\limits_{i = 1}^{m_{test}}[y_{test}^{(i)}log(f_{\vec{w}, b}(\vec{x}{test}^{(i)})) + (1 - y{test}^{(i)})log(1 - f_{\vec{w}, b}(\vec{x}_{test}^{(i)}))]$
  1. 计算训练集误差
  • $J_{train}(\vec{w}, b) = -\frac{1}{m_{train}} \sum\limits_{i = 1}^{m_{train}}[y_{train}^{(i)}log(f_{\vec{w}, b}(\vec{x}{train}^{(i)})) + (1 - y{train}^{(i)})log(1 - f_{\vec{w}, b}(\vec{x}_{train}^{(i)}))]$

模型选择

交叉验证集

在不接触测试集的前提下,为模型优化提供 “客观反馈”,确保模型不仅能拟合训练数据,还能适应未见过的数据(即提升泛化能力)。

即: 不在将数据集仅划分为训练集,测试集两部分,而是将数据集划分为训练集,交叉验证集,测试集三部分。

三个数据集的误差

训练集误差:

  • $J_{train}(\vec{w}, b) = \frac{1}{2m_{train}}[\sum\limits_{i = 1}^{m_{train}}(f_{\vec{w}, b}(\vec{x}^{(i)}) - y^{(i)})^{2}]$

交叉验证集误差:

  • $J_{cv}(\vec{w}, b) = \frac{1}{2m_{cv}}[\sum\limits_{i = 1}^{m_{cv}}(f_{\vec{w}, b}(\vec{x}{cv}^{(i)}) - y{cv}^{(i)})^{2}]$

测试集误差:

  • $J_{test}(\vec{w}, b) = \frac{1}{2m_{test}}[\sum\limits_{i = 1}^{m_{test}}(f_{\vec{w}, b}(\vec{x}{test}^{(i)}) - y{test}^{(i)})^{2}]$

Tips: 训练集误差用于训练模型,交叉验证集误差用于选择训练好的若干模型,而测试集误差用于检查模型泛化能力。

模型选择过程

  1. 依次计算出各个模型在交叉验证集上的误差。

  2. 选择交叉验证集误差最小的模型。

  3. 使用测试集检查模型泛化能力。

诊断偏差和方差

如下图所示:

  • 出现高偏差的情况下,往往模型存在欠拟合的问题。
  • 出现高方差的情况下,往往存在过拟合的问题。
  • 高偏差和高方差如果同时存在,则此时模型对于任何数据表现都是很差的。

Hint:

  • 如果模型出现高偏差,那么仅仅增加训练集是无法改善误差率,需要对模型进行调整。
  • 如果模型出现高方差,那么增加训练集往往可以使得模型更加拟合。

$\lambda$的选择

对于正则化参数$\lambda$的选择,可以通过多次尝试的方式,找到模型表现最好的$\lambda$值。

例:

依次尝试以下$\lambda$值:

  • $\text{Try } \lambda = 0$
  • $\text{Try } \lambda = 0.01$
  • $\text{Try } \lambda = 0.02$
  • $\text{Try } \lambda = 0.04$
  • $\text{Try } \lambda = 0.08$
  • $\vdots$
  • $\text{Try } \lambda = 10$

找到交叉验证误差最小的一个$\lambda$值

确立表现的基准水平

为了评估模型的误差是否高时,往往需要建立一个基准水平用于比较。

以下是几种常见的基准水平取值来源:

  1. 人类的表现能力
  2. 竞争者的算法表现(比如以前的算法,竞争对手的算法等)
  3. 根据以往的经验进行猜测

学习曲线

根据模型训练的过程绘制出以下学习曲线。

观察下图可以发现:

经过越多的数据训练,交叉验证集的误差是原来越小的。

而训练集的误差反而是从$0$开始不断增加的,这看起来很反常识,但实际上,对于越小的训练集,想要拟合是越容易的,此时预测的误差也会比较小(实际上就是欠拟合),而随着训练数据的增加,尽管训练集误差在不管增加,但实际上模型的泛化能力在不断加强。

神经网络模型调试流程

如上图所示:

  1. 在搭建模型时,先检查训练好的模型在训练集上的误差,如果对比基准水平偏差更高,那么可以尝试更大的神经网络,比如增加隐藏层的层数,或者每层增加隐藏单元。
  2. 当模型在训练集上的误差已经接近基准水平后,继续检查模型在交叉验证集上的表现,如果表现不好,那么增加训练集的数量继续训练模型。
  3. 增加数据集训练后回到第$1$步。
  4. 当交叉验证集的误差也接近基准水平后,那么就表示当前模型已经训练完成。

模型正则化

未正则化的MNIST模型(手写数字识别模型)

1
2
3
4
layer_1 = Dense(units = 25, activation='relu')
layer_2 = Dense(units = 15, activation='relu')
layer_3 = Dense(units = 1, activation='sigmoid')
model = Sequential([layer_1, layer_2, layer_3])

正则化的MNIST模型

1
2
3
4
5
layer_1 = Dense(units = 25, activation='relu', kernel_regularizer = L2(0.01))
layer_2 = Dense(units = 15, activation='relu', kernel_regularizer = L2(0.01))
layer_3 = Dense(units = 1, activation='sigmoid', kernel_regularizer = L2(0.01))
model = Sequential([layer_1, layer_2, layer_3])

注:

  1. 如果对大模型进行合适的正则化,那么大模型可以得到和小模型一样,或是更好的表现,而不是出现过拟合。
  2. kernel_regularizer = L2(0.01)的含义是为该层设置一个$\lambda = 0.01$

开发机器学习系统的过程

机器学习开发的迭代循环

机器学习系统的开发往往是按以下步骤不断循环迭代:

  1. 决定系统架构(模型,数据,以及其他)
  2. 训练模型
  3. 实现和查看一些诊断根据

误差分析

通过手动检查一组算法错误分类和标记错误的示例,往往能够激发下一步可能尝试的有效办法,也能帮助筛选掉一些比较罕见不值得投入太多的错误.

例:以下为垃圾邮件分类器的误差降低方法:

  1. 收集更多数据
  2. 基于电子邮件路由(来自电子邮件头)开发复杂的特性
  3. 从电子邮件正文定义复杂的特性
  4. 设计算法来检查拼写错误

添加数据技巧

计算机视觉

  1. 可以对图像进行旋转,放大,缩小,改变对比度,镜像

  2. 也可以将图像放入网格中,并进行扭曲

  3. 使用电脑上的不同字体去生成类似的数据

音频识别

  1. 添加嘈杂的背景音

注: 修改后的数据需要保证仍然于测试集中的内容相似

迁移学习

复制已经训练好的模型的隐藏层所有参数,仅对输出层根据自己的需求进行修改,然后对模型进行训练

主要有以下几种训练方案:

  1. 仅对输出层参数进行训练
  2. 对所有参数均进行训练

即,总体训练流程为:

  1. 有监督预训练(先在一个较大数据集上训练神经网络,可以是下载别人训练好的模型,也可以是自己训练的)
  2. 微调(从有监督预训练中初始化获得的参数,然后进一步运行梯度下降以微调权重以适应你可能有的手写数字识别的特定应用)

hint: 预训练和微调的数据集必须是相同类型的(如相同尺寸的图像)

机器学习项目完整周期

  1. 确定项目范围
  2. 收集数据
  3. 训练模型
  4. 部署系统

倾斜数据集的误差指标

对于模型效果的评估,仅仅对误差率进行评估可能会出现模型恰好对训练集拟合的较好,导致误差率较低,但不具备泛化能力.

例:存在一个罕见病,得病率仅$0.5%$,那么对于数据集中,含该病的数据也是极小的,那么,哪怕我们的模型仅为print(0),即所有情况均输出不患病,那么此时模型预测的准确率就能高达$99.5%$,而我们通过训练得出的模型误差率可能会达到$2%$,此时如果光从误差率对模型效果进行判断,是无法确定到底哪个模型是更优的.

因此,如下图有以下两个指标:

  • 精确率:对于所有预测为真的例子中,真实情况确实为真的比例
  • 召回率:对于所有实际为真的例子中,预测为真的比例

hint: 如果一个算法连一个正例也不预测,此时认为该算法精确率为$0$.

精确率和召回率的权衡

对于二分类问题,可以通过调整预测结果的阈值来调整模型的精确率和召回率,往往会选择一个使得精确率和回归率相对平衡的值.

F1分数: 评价模型准确率和召回率的一个指标(调和平均值)

  • $F1 score = \frac{1}{\frac{1}{2}(\frac{1}{P} + \frac{1}{Q})} = 2\frac{PR}{P + R}$

其中,$P$为精确率,$Q$为召回率

决策树

猫咪分类

决策树-猫咪分类

以上两张图片给出了猫咪分类的特征以及构建的决策树.

对于决策树,完成分类策略的方式为从根节点出发,判断是否满足当前情况,并沿着对应路径走向下一个决策节点,直到到达叶节点,则叶节点的值表明当前的预测情况.

hint: 非叶节点均为决策节点,叶节点均为预测节点.

学习过程

  1. 决策树算法中”如何选择每个节点的分裂特征”的核心逻辑:通过最大化子组的纯度(或最小化 “不纯度”),来挑选最能区分类别的特征。

  1. 何时停止决策树节点分裂?
  • 当一个节点的样本完全属于同一类别(如已经全是猫咪,或全不是猫咪)
  • 当分裂一个节点会导致树的深度超过最大深度(即预设一个最大深度限制树的扩张)
  • 当纯度分数的提升低于某个阈值(即再分裂提升的收益太低时放弃)
  • 当一个节点中的样本数量低于某个阈值(即样本量少,避免再分裂导致模型过拟合)

测量纯度(熵函数)

  1. 使用熵函数来衡量样本的纯度,下图为一些样本对应熵函数的值.

Tips: 信息论中的熵用来度量信息的不确定性(或”平均信息量”),即熵越大,信息约不确定,熵越小,信息越确定.

  1. 下图给出了熵函数的实际方程

$$
p_{0} = 1 - p_{1}
$$

$$
\begin{aligned}
H(p_{1}) &= -p_{1}log_{2}(p_{1}) - p_{0}log_{2}(p_{0}) \\
&= -p_{1}log_{2}(p_{1}) - (1 - p_{1})log_{2}(p_{0})
\end{aligned}
$$

注: $p_1$表示样本中猫咪的比例,$H(p_1)$为对应的熵函数的值,这里虽然$0log(0)$是个无定义点,但为了便于表示,我们默认在该算法中$0log(0)$的值为$0$

选择拆分信息

每次需要进行节点分裂时,实际上需要选择的是能将熵减少最多的一个特征进行分裂。

如下图,选择耳朵形状作为分裂节点的特征能够使得熵减少最多,因此应该选择耳朵形状来进行节点分裂。

信息增益

针对前面描述的选择方案,如下图有以下公式表示:

  • $H(p_{1}^{root}) - (w^{left} H(p_{1}^{left}) + w^{right} H(p_{1}^{right}))$

其中,$p_{1}^{left}, p_{1}^{right}$分别表示左右孩子中猫咪占该节点样本的比例,$w^{left}, w^{right}$则分别表示左右孩子中样本数量占当前样本总数的比例。

决策树整合

综上所述,决策树的完整构建过程为:

  • 开始时所有样本均在跟节点中
  • 计算所有可能特征的信息增益,然后选择信息增益最高的那个特征
  • 根据所选特征划分数据集,并创建树的左右分支
  • 持续重复划分过程,直到满足以下停止条件之一:
    • 当一个节点$100%$属于某一类时
    • 当划分一个节点会导致树超过最大深度时
    • 额外划分带来的信息增益小于阈值时
    • 当一个节点中的样本数量低于阈值时

独热编码

当某个特征具有多个值时,就需要将样本划分到多个子分支上去。

而对于这种情况,就可以使用独热编码来解决,即:

  • 如果一个分类特征有$k$个可能的值,那么可以创建$k$个新的特征(此时每个特征仅有$0, 1$两种值)来替代原有特征

连续的有价值特征

当某个特征的值是个连续的数字,即非固定的几个选项,此时就可以考虑取一个阈值来约束该特征,将样本划分为两部分:

  • 低于或等于阈值的一部分
  • 高于阈值的一部分

当然,此时要想选择一个合适的阈值是无法直接确定的,那么该怎么选择呢?

一种常用的方法是根据权重对所有样本进行排序,然后依次选择排序后相邻两数的中点作为阈值选择,并以此计算该点作为阈值产生的信息增益,取信息增益最大的点。

回归树

当问题需要扩展到回归问题时,就需要对决策树进行修改,即划分数据集时不再依靠信息增益的大小,而是改为方差减少。

如下图,3种方案中,选择耳朵形状作为划分特征时,可以使得方差减小最大,因此应该选择耳朵形状作为划分特征。

假如需要预测的为体重,那么如下图所示,实际上预测的体重即位当前叶节点中的样本体重均值。

树集成

实际上哪怕仅修改数据集中的一个样本,就很可能构造出两种不同的决策树,同时对于一个数据,两棵不同样本构造出的决策树也可能做出不同的判断。

如下图,对于同一个数据,3棵决策树做出了判定:2棵树认为是猫咪,1棵树认为不是猫咪

那么该怎么解决该问题呢?

一种解决方法就是构造多棵决策树用于判断,取选择结果较多的作为最后的答案,那么对于前面的判定,由于认为是猫咪的有两棵树,而认为不是猫咪的仅有一棵树,此时认为是猫咪的票数更高,则判定该样本是猫咪。

放回抽样

为了构建一棵决策树,可以通过放回抽样来构造数据。

即,将数据集放入一个黑箱中,有放回的进行抽取,将抽取出的数据用于训练模型。

如下图,对于10个样本,通过放回抽样,取出了$10$个样本。

随机森林算法

  • 给出一个大小为$m$的训练集
  • 重复执行以下操作$B$次(For b = 1 to B):
    • 使用放回抽样创建一个新的大小为$m$的训练集,并用于训练一棵决策树

随机特征选择:

对于任意节点,在选择特征进行划分时,如果当前有$n$个特征可以选择,则随机的从里面取出$k(k \lt n)$个特征的子集,仅允许算法从该子集中选取特征进行划分。

XGBoost(eXtreme Gradient Boosting)

  • 是一个快速且高效的提升树的开源实现
  • 效率非常高
  • 提供了默认的分裂标准和停止分裂的标准
  • 内置了正则化防止过拟合
  • 在机器学习竞赛中有很强的竞争力

分类问题

1
2
3
4
5
form xgboost import XGBClassifier
model = XGBClassifier()

model.fit(X_train, Y_train)
y_pred = model.predict(X_test)

回归问题

1
2
3
4
5
form xgboost import XGBRegressor
model = XGBRegressor()

model.fit(X_train, Y_train)
y_pred = model.predict(X_test)

决策树与神经网络的对比

决策树和集成树

  • 在结构化(表格)的数据上表现较好
  • 对非结构化(图片,音频,文本)的数据上不推荐使用
  • 训练非常快
  • 一个小的决策树对人类来说比较容易理解

神经网络

  • 对于所有数据表现都很好,包含结构化和非结构化数据
  • 比决策树要慢一些
  • 可以结合迁移学习
  • 更容易将多个神经网络串联使用,结合构建一个更大的机器学习模型。

深度学习
http://example.com/2025/07/08/深度学习/
Author
John Doe
Posted on
July 8, 2025
Licensed under