【吴恩达机器学习】高级学习算法
1 神经网络(Neural Networks)
1.1 神经网络模型
1.1.1 神经元和大脑
神经网络的灵感源自生物神经元。生物神经元通过树突(dendrites)接收输入信号,经细胞体(cell body)处理后,由轴突(axon)输出信号传递给其他神经元。

1.1.2 需求预测
以产品是否为畅销品预测为例,输入特征x是T恤的价格,即学习算法的输入,利用 sigmoid 激活函数,将价格数据转化为产品成为畅销品的概率f(x),a=f(x) 作为逻辑回归算法的输出。
a也被称为激活,它指的是一个神经元发送了多少对下游其它神经元的高输出。
逻辑回归算法可以视为大脑中单个神经元的一个非常简化的模型。

更复杂的需求预测示例,有4个特征来预测一件T恤是否产销
输入层:包含4个特征(价格、运费、营销量、材料),表示为一个向量。
隐藏层:由3个人工神经元(可负担性、意识、感知质量)组成,每个神经元处理输入层的数据并生成一个激活值,形成一个新的向量。
输出层:接收隐藏层的3个激活值,通过逻辑回归单元计算出一个单一的输出值,表示这件T恤成为畅销品的概率。
神经网络的一个好的特性是从数据中训练它时无需明确决定要做什么,神经网络能够自行决定。

下图展示了具有多个隐藏层的神经网络架构,即多层感知机(multilayer perceptron)。

1.1.3 例子:图像识别
1000x1000的网格,也被称为像素强度值的千乘千矩阵。

第一个隐藏层输出一些短边
第二个隐藏层输出一些面部特征
第三个隐藏层输出整个面部

1.1.4 神经网络中的层
上标[1]表示神经网络中隐藏层的第一层输出
下标1,2,3表示该层中的第一个、第二个、第三个神经元

1.2 神经网络的前向传播
1.2.1 前向传播
前向传播是神经网络根据输入数据计算输出结果的过程。
以手写数字识别模型为例,输入图像数据经多层神经网络处理。

1.2.2 TensorFlow中的数据
NumPy 数组的不同创建方式
Tensor 张量
TensorFlow 是广泛使用的深度学习框架,张量(Tensor)是其核心数据结构。在神经网络的计算过程中,数据从输入层经隐藏层到输出层的传递过程里,每一层处理后的输出(即激活向量)通常以张量形式存在。
如图,我们通过a2.numpy()方法将 TensorFlow 张量转换为 NumPy 数组。
1.2.3 构建一个神经网络
1.2.4 在一个单层中的前向传播 
1.2.5 前向传播的一般实现(Numpy)

def dense(a_in, W, b, g):
"""
计算全连接(密集)层的输出
参数:
a_in (形状为 (n,) 的 NumPy 数组) : 单个样本的数据
W (形状为 (n, j) 的 NumPy 数组) : 权重矩阵,每个单元有 n 个特征,该层共有 j 个单元
b (形状为 (j,) 的 NumPy 数组) : 偏置向量,对应 j 个单元
g 激活函数(例如 Sigmoid 函数、ReLU 函数等)
返回值
a_out (形状为 (j,) 的 NumPy 数组) : 该层 j 个单元的输出
"""
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)
1.3 通用人工智能(AGI)
-
窄人工智能(ANI):全称为 “artificial narrow intelligence”。它指的是专注于执行特定任务的人工智能系统。示例包括智能音箱、自动驾驶汽车、网页搜索以及农业和工厂中的人工智能应用。这些系统在各自特定的领域内表现出色,但缺乏人类智能的通用性。
-
通用人工智能(AGI):全称为 “artificial general intelligence”。它是一种假设的人工智能类型,理论上能够执行人类可以完成的任何任务,具备人类水平的智能和理解能力。

最初设想:模拟足够多的神经元就能模拟人的大脑
行不通的原因:
-
逻辑回归模拟的神经元模型实际和任何生物神经元所做的完全不同,它要简单的多
-
直到今天我们仍然不知道大脑的工作原理,我们对大脑的认知完全有限

大脑中的传感器表示
- Seeing with your tongue(用舌头 “看”):图中左上角显示一个人额头佩戴类似摄像头装置,口中含着一个设备。这种技术利用舌头来获取视觉信息,通过将视觉信号转换为舌头能感知的刺激,让使用者产生视觉感知。旁边特写展示了口中含着的设备细节。
- Human echolocation (sonar)(人类回声定位(声纳)):右上角图片展示一个人在户外,可能在通过发出声音并接收回声来定位周围环境,类似于动物(如蝙蝠)使用的声纳系统。
- Haptic belt: Direction sense(触觉腰带:方向感):左下角图片展示了一个触觉腰带设备,佩戴在人的腰部。该设备可通过触觉反馈向使用者传达方向信息,帮助使用者感知方向。
- Implanting a 3rd eye(植入 “第三只眼”):右下角图片展示了一种设想或实验性的技术,即通过植入设备模拟眼睛功能,为使用者提供额外的视觉信息或感知能力。

1.4 神经网络如何高效实现
循环实现
-
第 1 个神经元 (j=0):
w = W[:, 0] = [1, -2]z = np.dot(w, x) + b[0] = 1*200 + (-2)*17 + (-1) = 165
- 第 2 个神经元 (j=1):
w = W[:, 1] = [-3, 4]z = np.dot(w, x) + b[1] = -3*200 + 4*17 + 1 = -531
- 第 3 个神经元 (j=2):
w = W[:, 2] = [5, -6]z = np.dot(w, x) + b[2] = 5*200 + (-6)*17 + 2 = 900
向量化实现
- 计算过程为: \( \begin{align*} &\begin{bmatrix}200&17\end{bmatrix} \times \begin{bmatrix}1& -3&5\\-2&4& -6\end{bmatrix}\\ =&\begin{bmatrix}200\times1 + 17\times(-2)&200\times(-3)+17\times4&200\times5 + 17\times(-6)\end{bmatrix}\\ =&\begin{bmatrix}166&-532&898\end{bmatrix} \end{align*} \)
- 然后将上述结果加上偏置向量
B,即: \( \begin{bmatrix}166&-532&898\end{bmatrix}+\begin{bmatrix}-1&1&2\end{bmatrix}=\begin{bmatrix}165&-531&900\end{bmatrix} \) 所以Z的值为[[165, -531, 900]]。

def dense_v(A_in, W, b, g):
"""
计算全连接(密集)层的输出
参数:
A_in (形状为 (m, n) 的 NumPy 数组) : 输入数据,包含 m 个样本,每个样本有 n 个特征
W (形状为 (n, j) 的 NumPy 数组) : 权重矩阵,每个单元接收 n 个特征的输入,该层共有 j 个单元
b (形状为 (j, 1) 的 NumPy 数组) : 偏置向量,对应该层的 j 个单元
g 激活函数(例如 Sigmoid 函数、ReLU 函数等)
返回值:
A_out (形状为 (m, j) 的 NumPy 数组) : 输出结果,包含 m 个样本经过该层计算后得到的 j 个单元的输出
"""
Z = np.matmul(A_in,W) + b
A_out = g(Z)
return(A_out)
2 神经网络训练
2.1 TensorFlow实现
第一步:构建神经网络模型结构
第二步:编译模型(指定损失函数和优化器)
第三步:训练模型(调用 fit 函数,指定训练的轮数)
2.1.1 训练细节

2.1.2 选择损失函数
- 逻辑损失(logistic loss),也称为二元交叉熵(binary cross - entropy):用于二分类问题,衡量模型预测概率与真实标签之间的差异。
from tensorflow.keras.losses import BinaryCrossentropy
model.compile(loss=BinaryCrossentropy())
- 均方误差(mean squared error):用于回归问题,衡量预测值与真实值之间的平均平方误差。
from tensorflow.keras.losses import MeanSquaredError
model.compile(loss=MeanSquaredError())
2.2 激活函数
2.2.1 sigmoid的替代品
- 线性激活函数(Linear Activation Function),也被标注为 “无激活函数”(No activation function)
- Sigmoid 激活函数
- ReLU激活函数(Rectified Linear Unit)

2.2.2 选择激活函数
输出层
- 二分类任务:使用 Sigmoid 函数
- 回归任务:
- 输出值范围无限制:使用线性激活函数
- 输出值非负:使用 ReLU函数

隐藏层
通常选择ReLU激活函数
为什么不选择Sigmoid函数?
- Sigmod函数比较复杂,运行时间较慢。ReLU函数比较简单,运行时间较快。
- ReLU函数只有左边是平的,而sigmoid函数左右两边都是平的,成本函数使用梯度下降算法的时候会比较慢。

隐藏层推荐使用ReLU函数,输出层推荐使用Sigmod函数。
2.2.3 为什么需要激活函数
如果神经网络中的每一层都只是输入数据的线性组合(即加权和加上偏置),那么无论网络有多少层,最终的效果等同于一个单层的线性模型。这是因为多个线性变换可以合并为一个单一的线性变换。

在更复杂的神经网络示例中,即使输出层使用 Sigmoid 函数,但隐藏层均为线性激活,整个网络仍等同于逻辑回归,无法发挥神经网络处理复杂问题的能力。
不要在隐藏层使用线性激活函数,推荐使用 ReLU 函数。

3 多类
3.1 多类问题(Multiple classes)
多类问题仍然是分类问题,是指数据集中存在两个以上类别的分类任务。

3.2 Softmax
3.2.1 Softmax 回归
Softmax 回归是一种多类分类算法,用于处理具有两个以上类别的分类任务。它使用 Softmax 函数对多个线性组合的结果进行处理,将神经网络的输出转换为概率分布,使得所有类别的概率之和为 1 。
假设存在 \(k\) 个类别,对于输入 \(\vec{x}\) ,Softmax 函数计算每个类别 \(i\) 的概率 \(p_i\) 为 \(p_i=\frac{e^{z_i}}{\sum_{j = 1}^{k}e^{z_j}}\) ,其中 \(z_i\) 是对应类别 \(i\) 的线性组合结果。

def softmax(z):
"""
Softmax 函数将一个向量的值转换为概率分布。
参数:
z (形状为 (N,) 的 NumPy 数组) : 输入数据,包含 N 个特征
返回值:
a (形状为 (N,) 的 NumPy 数组) : 对 z 应用 Softmax 函数后的结果
"""
ez = np.exp(z) #element-wise exponenial 逐元素操作
a = ez/np.sum(ez)
return a
3.2.2 Softmax 代价
稀疏范畴交叉熵损失函数(Sparse Categorical Crossentropy)是处理多类别分类问题的一种损失函数。与标准的范畴交叉熵损失函数(Categorical Crossentropy)不同,稀疏范畴交叉熵损失函数适用于真实标签为整数索引的情况,而不是独热编码形式的标签。这使得它在某些情况下更加方便和高效。

from tensorflow.keras.losses import SparseCategoricalCrossentropy
model.compile(loss=SparseCategoricalCrossentropy())
3.2.3 神经网络的Softmax输出
3.2.4 Softmax的改进实现
参数from_logits=True:表示模型的最后一层未使用Softmax激活函数(直接输出原始分数,即logits),损失函数内部会自动应用Softmax。

输出不是概率,其取值在整个实数域。在进行期望有概率的预测时,输出必须通过softmax处理。

同样的,关于逻辑回归,在预测时,先获取模型的 logits 输出,然后通过 sigmoid 函数将其转换为概率值。

3.3 多标签问题(Multi - label Classification)
多标签分类(Multi - Label Classification)是机器学习中的一类分类任务,与传统单标签分类不同,它允许一个样本同时属于多个类别。


4 额外的神经网络概念
4.1 高级优化方法 Adam
Adam:Adaptive Moment estimation 自适应矩估计
Adam算法可以自动调整学习速率

4.2 其他的网络层类型
4.2.1 卷积层
密集层(全连接层):每个神经元的输出都是上一层所有激活输出的函数。

卷积层:每个神经元只查看前一层输入的一部分。
优势:
- 计算效率高:由于每个神经元只处理局部输入,相比全连接层,计算量大幅降低,能够更快地完成训练和推理过程。
- 需要更少的训练数据:减少了过拟合的风险,提高了模型的泛化能力。

卷积神经网络:神经网络中有多个卷积层

5 应用机器学习的建议
5.1 诊断
诊断是一种测试,其目的是深入了解学习算法中哪些部分有效、哪些部分无效,进而为改进算法性能提供指导。
虽然实施诊断可能需要花费时间,但这样做是非常值得的,它有助于更好地理解和优化机器学习算法。

5.2 模型评估
图中的曲线表明模型对训练数据拟合得很好,但存在的问题是它无法很好地推广到训练集之外的新样本。
我们需要一些更系统的方法来评估模型,可以将训练集拆分为两个子集:训练集和测试集,使用训练数据来拟合模型的参数,使用测试数据来评估模型。

5.2.1 线性回归
对于线性回归的训练/测试程序(使用平方误差损失函数),通过最小化代价函数来拟合参数,和
不包括正规化术语。

def eval_mse(y, yhat):
"""
计算数据集上的均方误差。
参数:
y : (NumPy 数组,形状为 (m,) 或 (m, 1)) 每个样本的真实目标值
yhat : (NumPy 数组,形状为 (m,) 或 (m, 1)) 每个样本的预测值
返回值:
err: (标量) 均方误差值
"""
m = len(y)
err = 0.0
for i in range(m):
err_i = ( (yhat[i] - y[i])**2 )
err += err_i
err = err / (2*m)
return(err)

5.2.2 分类
在分类问题中,将机器学习应用于实际任务时,我们通常关注的是模型对新数据(即测试集)的预测准确度,而不是仅仅依赖于逻辑损失(即交叉熵损失)来评估模型性能。对于二元分类任务或多类分类任务,一个更直观和常用的评估方法是计算模型在测试集和训练集上的分类错误率(或准确率)。

具体来说,在处理如手写数字0/1这样的二元分类任务时,我们可以让算法对每一个测试实例做出明确的1或0的预测。这样做之后,我们可以通过以下步骤来评估模型性能:
-
进行预测:模型对每个测试样本输出预测类别(0或1),而非连续概率值。
-
设定阈值(如0.5):将概率输出
转换为离散预测
-
比较预测值与真实标签:对于测试集中的每个实例,比较模型的预测值 y^和实际标签 y。
-
计算
:定义为测试集中被误分类的比例。计算方法是将测试集中所有样本中 y^≠y的样本数量除以测试集的总样本数。
-
计算
:定义为训练集中被误分类的比例。 计算方法是将训练集中所有样本中 y^≠y的样本数量除以训练集的总样本数。

这里使用的分类模型的评价函数只是错误预测的分数:
def eval_cat_err(y, yhat):
"""
计算分类误差
参数:
y : (NumPy数组,形状为 (m,) 或者 (m, 1)) 每个样本的真实类别标签
yhat : (NumPy数组,形状为 (m,) 或者 (m, 1)) 每个样本的预测类别标签
返回值:
cerr: (标量) 分类误差率
"""
m = len(y)
incorrect = 0
for i in range(m):
if yhat[i] != y[i]: # @REPLACE
incorrect += 1 # @REPLACE
cerr = incorrect/m # @REPLACE
return(cerr)
def eval_cat_err(y, yhat):
return np.mean(yhat != y)
5.3 模型选择和交叉验证集
模型选择:过程包括训练多个不同阶数的模型,并选择测试误差最小的模型。
潜在问题:使用测试集选择模型可能导致对模型性能的过度乐观估计,因为它可能会过拟合测试集。

我们可以将数据分为三个不同的子集:训练集、交叉验证集和测试集。交叉验证集是额外的数据集,用于对不同模型进行检查评估。


模型选择:通过训练多个不同阶数的多项式模型,并在验证集上评估它们的性能(交叉验证误差),选择表现最好的模型。
测试集评估:最终使用测试集评估选定模型的泛化能力,以确保模型在未见过的数据上的表现良好。

选择神经网络时同样适用
5.4 偏差和方差

下图为训练误差和交叉验证误差随模型复杂度(多项式次数)的变化情况。
正则化参数
通过调整正则化参数 ,可以在偏差和方差之间进行权衡,找到更优的模型。
下图为训练误差和交叉验证误差随正则化参数的变化情况。

5.5 建立表现基准
在机器学习中,建立性能基线水平对评估模型表现至关重要,以下是一些常见的建立方法:
- 人类水平性能:人类在处理非结构化数据(如音频、图像、文本)方面具有卓越能力。以图像识别为例,人类可凭借视觉感知和经验精准识别图像内容,所以在相关任务中,人类的表现常作为性能基线,用于判断模型是否达到或超越人类水平。
- 竞争算法性能:可参考他人或团队先前实现的、在类似任务中表现优异的竞争算法。这些算法在实际应用或竞赛中已得到验证,其性能可作为新模型的参照基线,有助于评估新模型的优劣及创新程度。
- 基于经验的猜测:领域专家依据自身经验和对任务的理解,对合理的误差水平和性能表现进行预估。尽管该方法具有一定主观性,但在缺乏明确参照时,也能为模型性能评估提供大致参考范围。

查看性能的基线水平和训练误差、交叉验证误差来判断模型存在的偏差或方差问题。
5.6 学习曲线

5.6.1 高偏差
如果一个学习算法存在高偏差问题,仅靠获取更多的训练数据并不能带来太大帮助。这是因为高偏差通常意味着模型过于简单,无法捕捉数据中的复杂模式,增加训练数据量并不能从根本上解决模型表达能力不足的问题。
5.6.2 高方差
如果一个学习算法存在高方差问题,获取更多的训练数据很可能会有所帮助。因为高方差通常意味着模型过于复杂,对训练数据中的噪声过度拟合,增加训练数据量可以使模型学习到更具普遍性的模式,从而减少过拟合,降低方差。

5.7 调试学习算法
- 获取更多训练样本:有助于解决高方差问题。更多的数据可以让模型学习到更具普遍性的模式,减少过拟合。
- 尝试更小的特征集:比如只选取部分特征。这可以降低模型复杂度,解决高方差问题。
- 尝试获取额外特征:增加特征数量,为模型提供更多信息,有助于解决高偏差问题,使模型能够捕捉到数据中更复杂的关系。
- 尝试添加多项式特征:通过增加模型的复杂度来解决高偏差问题,提升模型拟合能力。
- 尝试减小
:减小正则化强度,使模型更加灵活,有助于解决高偏差问题,让模型更好地拟合训练数据。
- 尝试增大
:增强正则化强度,限制模型复杂度,有助于解决高方差问题,防止模型过拟合训练数据。

5.8 神经网络优化
5.8.1 神经网络与偏差 - 方差
核心观点:大型神经网络是低偏差机器,这意味着它们能够很好地拟合训练数据。
流程图:
- 检查模型是否在训练集上表现良好。
- “Yes”,继续下一步。
- “No”,则需要构建一个更大的网络,并可能使用GPU加速计算。
- 检查模型是否在交叉验证集上表现良好。
- “Yes”,表示模型已经完成。
- “No”,则需要更多的数据。
5.8.2 神经网络与正则化
只要选择合适的正则化,大型神经网络通常表现与小型神经网络一样好或更好。这是因为大型网络有更强的表达能力,正则化可防止其过拟合。

5.8.3 神经网络正则化

6 机器学习开发过程
6.1 机器学习开发的迭代循环
- 选择架构: 选择合适的模型、数据集和其他参数。
- 训练模型: 使用选定的数据集训练模型。
- 诊断分析: 分析模型性能,识别偏差、方差和错误。

6.2 误差分析
误差分析的一个局限性在于它更容易识别和处理人类擅长的问题,而对于人类本身也不擅长的问题,错误分析可能会有点困难。

6.3 添加数据
6.3.1 数据增强
数据增强是对现有的训练样本进行修改,以创建新的训练样本。

数据增强也同样适用于语音识别

几何失真:通过改变图像的几何形状(如旋转、缩放、平移等)来生成新的训练样本。
像素强度扰动:通过在像素强度上添加随机噪声来生成新的训练样本。
在音频数据中,可以通过引入背景噪声或模拟手机连接不良的情况来生成新的训练样本。
在进行数据增强时,添加的扭曲不能是随意的,而要与实际测试数据可能遇到的噪声或变形情况相符。

6.3.1 数据合成
数据合成是使用人工数据输入来创建新的训练实例。

对你的系统所使用的数据进行工程化处理
- 传统模型中心化方法: 主要关注算法和模型的优化。
- 数据中心化方法: 主要关注数据的质量和预处理。

6.4 迁移学习(Transfer learning)
6.4.1 迁移学习的概念
对于数据量有限的应用程序而言,迁移学习是一项非常有用的技术。它使得我们能够在相关任务中利用预先训练的模型,从而帮助提升自身应用的性能。
预训练阶段(Supervised pretraining):
- 图片上方显示了一个预训练的神经网络,该网络在包含 1000 个类别的大规模数据集(100 万张图像)上进行训练,这些类别包括猫、狗、汽车、人等。
- 网络的输出层有 1000 个输出单元,对应的权重和偏置分别标记为
和
。
微调阶段(Fine tuning):
- 图片下方展示了在新任务上对预训练模型进行微调的过程。新任务可能是一个简单的分类任务,比如识别数字 0 - 9,输出层只有 10 个输出单元。
- 如何训练神经网络参数有两种选择:
- Option 1:只训练输出层的参数(绿色标记的
和
)。
- Option 2:训练所有层的参数。
- Option 1:只训练输出层的参数(绿色标记的
- 如果有一个小规模的数据集,选择 Option 1。如果有一个大规模的数据集,选择 Option 2。

6.4.2 为什么迁移学习有效
当训练神经网络用于检测图像中的不同物体时,第一层通常学习检测低级特征,如边缘;第二层将这些边缘组合起来以检测角点;第三层可以学习识别更复杂但仍较为通用的形状,比如基本曲线。这些特征在不同但相关的任务中具有通用性,因此可以在新任务中进行迁移。

预训练阶段是在相同类型的输入上进行的,例如对于图像分类任务,会在所需尺寸的图像数据集上训练神经网络。如果你正在构建一个语音识别系统来处理音频,那么预先在图像数据上训练的神经网络可能不会对你有很大帮助,因为图像和音频的数据特征空间差异较大。相反,使用一个已经在类似音频数据上预训练的神经网络,并针对你自己的音频数据集进行微调,将会更加有效。
同样的原则适用于其他类型的数据和任务。如果你的应用程序涉及文本数据,你应该选择在一个大型文本数据集上预先训练的神经网络,然后根据你的具体需求(输入为文本数据 x)对其进行微调。通过这种方式,你可以利用预训练模型已经学到的知识,同时适应特定于你应用程序的需求。
6.4.3 迁移学习总结
- 下载在大型数据集上预训练的神经网络参数,其输入类型(如图像、音频、文本)与你的应用程序相同(或者训练你自己的参数)。
- 在你自己的数据上进一步训练(微调)网络。

6.5 机器学习项目的完整周期
- 规划项目范围:明确项目的范围和目标
- 收集数据:定义所需数据并进行收集
- 训练模型:训练模型,并进行错误分析和迭代改进
- 部署到生产环境:部署模型到生产环境,并对系统进行监控和维护

7 倾斜数据集
在研发机器学习应用程序时,如果正面例子和负面例子的比例严重失衡(偏差远超过 50%),那么像准确率这样的常规误差度量指标往往就不太有效了。
以训练一个用于检测患者是否患有罕见疾病的二分类器为例,规定y=1表示患有疾病,y=0表示未患疾病。在测试集上,该分类器的误差为 1%,这意味着其正确诊断率为 99%。然而,由于这是一种罕见疾病,y=1的情况非常少见。假设人群中仅有 0.5% 的患者患有该疾病,若编写一个程序始终预测y=0,那么它实际上能达到 99.5% 的准确率,即误差仅为 0.5%。这就导致了一种看似反常的现象:一个极为简单(甚至可以说有些愚蠢)的算法,其 0.5% 的误差表现比具有 1% 误差的学习算法还要好。不过,显然这个总是输出 y=0的程序并不能作为一个有效的诊断工具。

当存在一个误差为 0.5% 的算法、一个误差为 1% 的算法以及一个误差为 1.2% 的算法时,很难判断哪一个算法是最优的。因为误差最小的算法(比如总是预测y=0的算法),其预测结果可能并不具备实际价值。因此,在处理倾斜数据集时,我们通常使用不同的度量误差,而不仅仅是分类误差。
7.1 倾斜数据集的误差指标——准确率和召回率
一对常见的误差度量标准是精确率和召回率。
当存在我们想要检测的罕见类别时,y = 1。
一个罕见的类将有助于构造所谓的混淆矩阵。
行和列:行表示预测类别,列表示实际类别,分别有 0 和 1 两个取值。
四个单元格:
- True positive(真阳性/真正例,TP):表示实际为 1 且预测也为 1 的样本数量。
- False positive(假阳性/假正例,FP):表示实际为 0 但预测为 1 的样本数量。
- False negative(假阴性/假负例,FN):表示实际为 1 但预测为 0 的样本数量。
- True negative(真阴性/真负例,TN):表示实际为 0 且预测也为 0 的样本数量。
精确率是指在所有预测为正例(y = 1)的样本中,实际患有罕见疾病的比例。
召回率是指在所有实际患有罕见疾病的样本中,被正确检测出患有该疾病的比例。

计算精确率与召回率,有助于发现总是预测为负例的学习算法。在评估模型时,需确保其不仅准确率较高,召回率也表现良好。只有当精确率和召回率均处于较高水平时,才能充分确信该学习算法是有用的。
7.2 准确率与召回率的权衡
- 假设我们希望预测 y=1(罕见疾病)只有在非常自信的情况下:
- 高精确率,低召回率: 提高阈值(例如从0.5提高到0.7),这样只有非常高的概率才会被预测为阳性。
- 假设我们希望避免错过太多罕见疾病的病例(当不确定时预测 y=1):
- 低精确率,高召回率:降低阈值(例如从0.5降低到0.3),这样更多的样本会被预测为阳性。

7.2.1 F1 score
F1分数:是一种综合评估精确率和召回率的方法,特别适用于需要同时考虑两者的情况。
计算方法:通过调和平均值计算,确保精确率和召回率的平衡。
Algorithm 1精确率和召回率都相对平衡,因此F1分数较高。

8 决策树(Decision Trees)
8.1 决策树学习
- 从根节点包含所有样本开始。
- 计算所有可能特征的信息增益,选择信息增益最高的特征。
- 根据所选特征分割数据集,并创建树的左分支和右分支。
- 不断重复分割过程,直到满足停止条件:
- 当一个节点 100% 属于同一类别时。
- 当分割一个节点会导致树超过最大深度时。
- 当额外分割带来的信息增益小于阈值时。
- 当一个节点中的样本数量低于阈值时。

8.1.1 熵(Entropy)
熵作为不纯度的一种度量。
为猫的样本比例,
为非猫的样本比例

当为 0 或 1 时(即样本全部为非猫或全部为猫,节点纯度最高),熵
为 0;当
为 0.5时(即猫和非猫的样本各占一半,节点纯度最低,不确定性最大),熵
达到最大值 1。
Note:“0log(0)”=0,说明当或
为 0 时(即样本全部为猫或全部为非猫的极端情况),0log(0)这一项的值被定义为 0。

def compute_entropy(y):
"""
计算节点处样本集合的熵
参数:
y (ndarray): 一个NumPy数组,用于表示节点处每个样本的类别。例如,可用 `0` 和 `1` 分别代表两个不同的类别。
返回:
entropy (float): 该节点处的熵值
"""
# 初始化熵为 0
entropy = 0.
# 检查数组 y 是否为空,避免对空数组进行计算
if len(y) != 0:
# 计算类别标签为 1 的样本在整个样本集合中所占的比例
p1 = np.sum(y == 1) / len(y)
# 处理特殊情况:当 p1 为 0 或 1 时,样本集合完全纯净,熵为 0
if p1 != 0 and p1 != 1:
# 根据熵的公式计算熵值
entropy = -p1 * np.log2(p1) - (1 - p1) * np.log2(1 - p1)
else:
# 若样本集合完全纯净,熵值为 0
entropy = 0
return entropy
8.1.2 信息增益(Information Gain)
信息增益表示在使用某个特征对数据集进行划分前后,数据集的信息熵的减少量。

是根节点中猫的比例,
和
分别是左右子节点中猫的比例,
和
分别是左右子节点的权重。

def split_dataset(X, node_indices, feature):
"""
将给定节点处的数据划分为左右两个分支
参数:
X (ndarray): 形状为 (样本数量, 特征数量) 的数据矩阵
node_indices (ndarray): 包含有效索引的列表,即当前步骤正在考虑的样本索引
feature (int): 用于进行划分的特征的索引
返回:
left_indices (ndarray): 特征值等于 1 的样本的索引
right_indices (ndarray): 特征值等于 0 的样本的索引
"""
# 初始化左右分支的索引列表
left_indices = []
right_indices = []
# 遍历当前节点所包含的样本索引
for i in node_indices:
# 检查样本在指定特征上的值是否为 1
if X[i][feature] == 1:
# 如果值为 1,将该样本的索引添加到左分支索引列表中
left_indices.append(i)
else:
# 如果值不为 1(即为 0),将该样本的索引添加到右分支索引列表中
right_indices.append(i)
return left_indices, right_indices
def compute_information_gain(X, y, node_indices, feature):
"""
计算在给定节点上基于指定特征进行划分的信息增益
参数:
X (ndarray): 形状为 (样本数量, 特征数量) 的数据矩阵
y (array like): 包含 n_samples 个元素的列表或 ndarray,代表目标变量
node_indices (ndarray): 包含有效索引的列表,即当前步骤正在考虑的样本索引
feature (int): 用于进行划分的特征的索引
返回:
information_gain (float): 计算得到的信息增益
"""
# 调用 split_dataset 函数将数据集划分为左右两个分支
left_indices, right_indices = split_dataset(X, node_indices, feature)
# 提取当前节点、左分支和右分支的数据和标签
X_node, y_node = X[node_indices], y[node_indices]
X_left, y_left = X[left_indices], y[left_indices]
X_right, y_right = X[right_indices], y[right_indices]
# 初始化信息增益为 0
information_gain = 0
# 计算当前节点的熵
node_entropy = compute_entropy(y_node)
# 计算左分支的熵
left_entropy = compute_entropy(y_left)
# 计算右分支的熵
right_entropy = compute_entropy(y_right)
# 计算左分支样本在当前节点样本中的比例
w_left = len(left_indices) / len(node_indices)
# 计算右分支样本在当前节点样本中的比例
w_right = len(right_indices) / len(node_indices)
# 计算划分后的加权熵
weighted_entropy = w_left * left_entropy + w_right * right_entropy
# 计算信息增益,即当前节点的熵减去划分后的加权熵
information_gain = node_entropy - weighted_entropy
return information_gain
def get_best_split(X, y, node_indices):
"""
返回用于分裂节点数据的最优特征索引
参数:
X (ndarray): 形状为 (样本数量, 特征数量) 的数据矩阵
y (array like): 包含 n_samples 个元素的列表或 ndarray,代表目标变量
node_indices (ndarray): 包含有效索引的列表,即当前步骤正在考虑的样本索引
返回:
best_feature (int): 用于分裂的最优特征的索引
"""
# 获取特征的数量
num_features = X.shape[1]
# 初始化最优特征索引,-1 表示尚未找到合适的特征
best_feature = -1
# 初始化最大信息增益为 0
max_info_gain = 0
# 遍历所有特征
for feature in range(num_features):
# 调用 compute_information_gain 函数计算基于当前特征分裂所获得的信息增益
info_gain = compute_information_gain(X, y, node_indices, feature)
# 如果当前特征的信息增益大于之前记录的最大信息增益
if info_gain > max_info_gain:
# 更新最大信息增益
max_info_gain = info_gain
# 更新最优特征索引
best_feature = feature
return best_feature
8.1.3 递归分割(Recursive Splitting)
基本思想:
- 从根节点开始,使用某个特征对数据集进行分割。
- 对每个子节点重复上述过程,直到满足某个停止条件
8.1.4 独热编码(One-Hot)
独热编码是将类别型变量转换为二进制向量的一种编码方式。
- Ear shape :耳朵形状,有 “Pointy(尖的)”“Oval(椭圆形的)”“Floppy(耷拉的)” 三种取值。
- Face shape :脸型,有 “Round(圆形的)” 和 “Not round(非圆形的)” 两种取值。
- Whiskers :胡须,有 “Present(有)” 和 “Absent(无)” 两种取值。

如果分类特征可以采用K个值,请创建K个二进制特征(值为0或1)。
独热编码也适用于训练神经网络。
8.1.5 连续值特征的拆分

如果你有10个训练例子,你将为此阈值测试9个不同的可能值,然后选择给你信息增益最高的那一个。

8.1.6 回归树
使用决策树进行回归:预测一个数值
根据特征x来预测体重y而不是试图预测动物是否是猫

通过这个决策树模型,可以根据动物的耳朵形状和脸型特征,来预测其体重数值。
每个叶子节点代表一个预测值,即该类别的平均体重。

Variance:方差
选择一个能给你最大的方差减少的特征

8.2 树集成 (Tree ensemble)
8.2.1 使用多个决策树
决策树对数据的微小变化高度敏感。

三棵树的预测结果分别为 “Cat”、“Not cat”、“Cat”,通过投票,最终预测结果为 “Cat”。
8.2.2 有放回抽样
每次抽取后样本被放回,因此可以多次抽取到相同的样本。
使用替换进行抽样的过程能够构建一个新的训练集,这是构建树集成模型的关键步骤。

8.2.3 随机森林
给定大小为m的训练集,对于b从1到B(B为设定的循环次数),每次执行以下操作:
-
使用有放回抽样创建一个大小同样为m的新训练集。
-
在新的数据集上训练一棵决策树。
树集成的这种特定实例化有时也称为装袋决策树。
随机化特征选择
在每个节点选择用于分裂的特征时,如果有n个可用特征,那么随机选取一个大小为k(k<n)的特征子集,并且算法只能从这个子集中选择特征进行分裂。换句话说,选择k个特性作为允许的特性,选择信息增益最高的一个进行分裂,当n很大时,k的典型取值是。
通过引入带替换的取样,我们进一步改进了算法,从而得到随机森林算法。这种取样方法会导致训练数据集产生大量小的变化,进而训练出不同的决策树。由于采用的是带替换的取样方式,任何微小的训练集变化对整体模型的影响都被减小,这有助于增加模型的多样性和稳定性。

8.2.4 XGBoost
提升树算法通过迭代训练一系列决策树,每次训练时都增加对之前模型误分类样本的关注,使得后续的树能够逐步纠正前面树的错误,最终将这些树的结果进行组合,以获得一个性能更好、预测更准确的集成模型。

XGBoost是一种极端梯度提升算法。
- 是一个开源的梯度提升树实现。
- 具有快速高效的实现,能够处理大规模数据集。
- 提供了良好的默认分裂标准以及何时停止分裂的标准,这有助于提高模型的性能和效率。
- 内置了正则化机制,以防止过拟合,从而提高模型的泛化能力。
- 在机器学习竞赛中表现出色,特别是在Kaggle等竞赛中经常被使用并取得优异成绩。


8.2.5 什么时候使用决策树
决策树和树集成
- 适用于表格数据
- 适用于非结构化数据(图像、音频、文本)
- 速度快
- 小型决策树可能具有人类可解释性
神经网络
- 适用于所有类型的数据,包括表格(结构化)和非结构化数据
- 可能比决策树慢
- 支持迁移学习
- 当构建多个模型协同工作的系统时,将多个神经网络组合在一起可能更容易

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐












所有评论(0)