本文为图解机器学习笔记
决策树
决策树核心思想:
- 基于已知各种特征取值,构建树型决策结构,内部节点表示特征测试,叶子节点表示输出类别
决策树生长与最优特征选择:
-
信息熵:是消除不确定性所需信息量的度量,是未知事件可能含有的信息量
\[Ent(D)=-\sum_{K=1}^{|y|}p_k\log _2 p_k \]- \(D\) 是数据集,\(D\) 中有 \(y\) 类,第 \(k\) 类样本占比 \(p_k\)
- \(p_k = 1\) 或 \(p_k = 0\) 时,是确定事件,没有不确定性,信息熵最小,信息熵为零
- \(p_k\) 均匀分布时,不确定性最大,信息熵最大,信息熵为 \(\log |y|\)
-
信息增益:当选择某个特征进行划分时,划分前和划分后的信息熵差值
\[Gain(D,a) = Ent(D) - \sum_{v=1}^V \frac{|D^v|}{|D|} Ent(D^v) \]- \(a\) 是 \(D\) 的一个特征,\(a\) 有 \(V\) 种取值,\(D^v\) 是 \(D\) 中在 \(a\) 上取值全为 \(a^v\) 的样本
- 例如:色泽是 \(D\) 的一个特征,色泽有青绿、乌黑、浅白 3 种取值,\(D^{青绿}\) 是 \(D\) 中色泽为青绿的样本
- 应当选择信息增益最大的特征进行划分 (ID3)
-
信息增益率:解决信息增益偏向取值较多的特征的问题
\[\begin{align} Gain\_ratio(D,a) &= \frac{Gain(D,a)}{IV(a)} \\ IV(a) &= -\sum_{v=1}^V \frac{|D^v|}{|D|} \log_2 \frac{|D^v|}{|D|} \end{align} \]- \(v\) 越大,\(IV(a)\) 通常越大
- 应当选择信息增益率最大的特征进行划分 (C4.5)
-
基尼指数:随机抽取两个样例,类别不一致的概率
\[\begin{align} Gini(D) &= \sum_{k=1}^{|y|} \sum_{k'\neq k} p_k p_{k'} = 1 - \sum_{k=1}^{|y|} p_k^2 \\ Gini\_index(D,a) &= \sum_{v=1}^V \frac{|D^v|}{|D|}Gini(D^v) \end{align} \]- 基尼指数越小,纯度越高
- 应当选择使划分后基尼指数最小的特征 (CART)
过拟合与剪枝:
- 预剪枝:在决策树生长过程中,对每个结点在划分前进行估计,若当前结点的划分不能带来决策树泛化性能的提升,则停止划分并将当前结点标记为叶结点
- 后剪枝:先从训练集生成一颗完整的决策树,然后自底向上地对非叶结点进行考察,若将该结点对应的子树替换为叶结点能带来决策树泛化性能的提升,则将该子树替换为叶结点
- 为评估泛化性能是否提升,需要划分出一部分数据作为验证集
- 预剪枝、后剪枝与不剪枝的比较
- 训练时间开销:预剪枝降低,后剪枝增加
- 测试时间开销:均降低
- 欠拟合风险:预剪枝增加,后剪枝基本不变
- 过拟合风险:均降低
连续值与缺失值:
- 连续值
- 选择一个特征,寻找最优阈值将该特征二分,不保证全局最优
- 已被划分过的连续特征,仍可作为后代结点的划分特征
- 缺失值
- 特征划分选择
- 使用特征 \(a\) 无缺失值的样本,计算信息增益 \(Gain(\tilde D,a)\),将其乘以权重 \(p^a\),作为特征划分选择依据
- \(p^a\) 是特征 \(a\) 无缺失值的样本,占总样本的比例
- 给定特征划分 \(a\),该特征为缺失值的样本 \(x\) 的划分方式
- 将 \(x\) 以权重 \(r^v\) 划分到所有子节点
- \(r^v\) 是特征 \(a\) 的取值为 \(a^v\) 的样本,占特征 \(a\) 无缺失值的样本的比例
- 特征划分选择
回归树
回归树核心思想:
- 构建二叉树,内部结点特征的取值为 "是" 或 "否"
- 将输入空间划分为有限个区域,每个区域的输出值是该区域所有训练样本的标签的平均值
- 二叉树内部节点数量 \(+1=\) 二叉树叶子节点数量 \(=\) 输入空间被划分的区域数量
启发式切分与最优特征选择:
-
理想情况
\[RSS=\sum_{j=1}^J \sum_{x_i\in R_j} (y_i - \tilde y_{R_j})^2 \]- 将输入空间划分为 \(J\) 个区域,每个区域记作 \(R_j\),\(R_j\) 中所有训练样本的标签的平均值为 \(\tilde y_{R_j}\)
-
递归二分
\[RSS = \sum_{x_i\in R^{(1)}} (y_i - \tilde y_{R^{(1)}})^2 + \sum_{x_i\in R^{(2)}} (y_i - \tilde y_{R^{(2)}})^2 \]- 每次划分,选择一个特征 \(a\),寻找最优阈值 \(s\),将该特征二分,得到区域 \(R^{(1)} = \{x|x_a < s\}\) 和区域 \(R^{(2)} = \{x|x_a \geq s\}\)
- 只考虑当前最优,不考虑之前划分,不保证全局最优
过拟合与正则化:
-
过拟合的解决方法
- 限制树的深度
- 限制叶子节点最少样本数
- 分类误差法:当树继续生长无法使分类误差减小,就停止生长
- 剪枝
-
正则化
\[\sum_{j=1}^{|T|} \sum_{x_i \in R_j} (y_i - \tilde y_{R_j})^2 + \alpha|T| \]- \(|T|\) 是二叉树叶子节点数量,即输入空间被划分的区域数量
随机森林 RF
集成学习:
- 训练一系列个体学习器,通过结合策略将它们集成起来,形成更强的学习器
Bagging:
- Bootstrap 采样:有放回抽样,得到含有 \(n\) 个样本的采样集
- Bagging
- 是 Bootstrap aggregating 的缩写,是在 Boostrap 采样基础上构建的
- 有放回抽样 \(T\) 次,得到 \(T\) 个含有 \(n\) 个样本的采样集,使用每个采样集训练一个学习器,然后将这些学习器集成起来
- 分类任务使用简单投票法,回归任务使用简单平均法,可以并行训练
- 关注降低方差
随机森林:
- 有放回抽样 \(T\) 次,得到 \(T\) 个采样集,使用每个采样集训练一个决策树
- 在训练决策树时,对于决策树的每个节点,先随机选取一部分特征,再从这部分特征中选择最优特征
参数与调优:
- 每个树节点分裂时考虑的特征数
max_features
- 增加
max_features
一般能提高单个决策树的性能,但降低了树与树的差异性,且可能降低算法的速度 - 太小的
max_features
会影响单颗树的性能,进而影响整体集成效果
- 增加
- 决策树的棵树
n_estimators
- 较大的
n_estimators
可以增加稳定性和泛化能力,但会降低算法的速度
- 较大的
- 树深
max_depth
- 太大的
max_depth
可能会有过拟合问题
- 太大的
- 内部节点再划分所需最小样本数
min_samples_split
- 叶子节点最少样本数
min_samples_leaf
梯度提升决策树 GBDT
Boosting:
- 训练一系列个体学习器,采用串行的方式将它们层层叠加,每一层训练时,对前一层分类错误的样本给予更高权重
- 关注降低偏差
GBDT:
-
每次以当前预测为基准,下一个分类器拟合预测值与真实值之间的误差 (残差),所有分类器的结果相加等于最终预测值
-
当损失函数选用 MSE 时,预测值与真实值之间的误差 (残差),等于损失函数的负梯度
\[l(y_i,\hat y_i) = \frac{1}{2}(y_i-\hat y_i)^2, \quad -\frac{\partial l(y_i,\hat y_i)}{\partial \hat y_i} = (y_i-\hat y_i) \]
GBDT 的优缺点:
- 优点
- 预测时,每棵树的结构已确定,可并行化计算,计算速度快
- 适用稠密数据,泛化能力强,可解释性好
- 缺点
- 训练时,无法并行
- 在高维稀疏数据上效果差
- 适合数值型特征,在 NLP 或文本特征上效果差
- 相对于 RF,对异常值敏感
XGBoost
XGBoost:
- 相比于 GBDT
- 使用泰勒展开改进损失函数,加入树的复杂度作为正则项
- 使用随机森林中每次节点分裂前进行随机采样的做法
- 使用稀疏感知处理稀疏 0 和缺失值
- 在工程设计方面优化,可以在特征层面并行
目标函数:
-
树的定义
\[\begin{align} \hat y_i^{(t)} &= \sum_{k=1}^t f_k(x_i) = \hat y_i^{(t-1)} + f_t(x_i) \\ f_t(x) &= w_{q(x)}, \quad w\in \mathbb{R}^{\Tau}, \quad q: \mathbb{R}^d \rightarrow \{1,2,...,T\} \end{align} \]- XGBoost 由 \(t\) 颗树组成,\(f_t(x_i)\) 是第 \(t\) 颗树,\(\hat y_i^{(t)}\) 是 \(t\) 颗树的预测结果
- \(T\) 是叶子节点数量,\(w\) 是 \(T\) 维向量,代表每个叶子节点的值,\(q\) 将样本从特征映射到叶子节点编号
-
树的复杂度
\[\Omega(f_t) = \gamma T + \frac{1}{2}\lambda \sum_{j=1}^T w_j^2 \]- 树的复杂度由叶子节点数量和 \(L_2\) 范数共同组成
-
泰勒展开
\[\begin{align} f(x) &= \sum_{i=0}^n \frac{f^{(i)}(x_0)}{i!} (x - x_0)^i + R_n(x) \\ f(x + \Delta x) &\approx f(x) + f'(x)\Delta x + \frac{1}{2}f''(x)\Delta x^2 \end{align} \]- \(R_n(x)\) 是泰勒公式的余项,是 \((x - x_0)^n\) 的高阶无穷小
- XGBoost 中使用二阶泰勒展开
-
目标函数
\[\begin{align} Obj &= \sum_{i=1}^n l(y_i, \hat y_i) + \sum_{i = 1}^t \Omega(f_i) \\ &= \sum_{i=1}^n [l(y_i, \hat y_i^{(t-1)} + f_t(x_i))] + \Omega(f_t) + constant \\ &\approx \sum_{i=1}^n [g_if_t(x_i)+\frac{1}{2}h_if^2_t(x_i)] + \Omega(f_t) \\ &= \sum_{j=1}^T [(\sum_{i \in I_j} g_i)w_j + \frac{1}{2}(\sum_{i \in I_j}h_i + \lambda)w_j^2] + \gamma T \\ &= \sum_{j=1}^T [G_jw_j + \frac{1}{2}(H_j + \lambda)w_j^2] + \gamma T \end{align} \]- \(l\) 是损失函数,\(\Omega\) 是抑制树的复杂度的正则项
- 训练第 \(t\) 颗树时,前 \(t - 1\) 颗树已知,其复杂度可以用常量表示
- 将损失函数泰勒展开并省略常数,展开时,\(\hat y_i^{(t-1)}\) 是 \(x\),\(f_t(x_i)\) 是 \(\Delta x\),\(g_i\) 是一阶导,\(h_i\) 是二阶导,求导是对前 \(t-1\) 颗树 \(\hat y_i^{(t-1)}\) 求导,是常量
- 每个样本会被划入一个叶子节点,\(i \in I_j\) 代表样本 \(x_i\) 被划入第 \(j\) 个叶子节点,因此,对每个样本求目标函数再相加,等价于对每个叶子节点求目标函数再相加
- \(G_j\) 是第 \(j\) 个叶子节点所包含样本的一阶导之和,\(H_j\) 是第 \(j\) 个叶子节点所包含样本的二阶导之和,是常量
-
优化目标函数
\[\begin{align} w_j^* &= -\frac{G_j}{H_j + \lambda} \\ Obj &= -\frac{1}{2} \sum_{j=1}^T \frac{G_j^2}{H_j + \lambda} + \gamma T \end{align} \]- 目标函数是关于 \(w_j\) 的一元二次方程,向量 \(w\) 的每个元素相互独立,可以求导得到最优解
节点分裂准则:
-
贪心算法
\[Gain = \frac{1}{2}[\frac{G_L^2}{H_L+\lambda}+\frac{G_R^2}{H_R+\lambda}-\frac{(G_L+G_R)^2}{H_L+H_R+\lambda}]-\gamma \]- \(Gain\) 是未分裂前的目标函数,减去分裂后的目标函数
- \(Gain\) 可能是负数,因为分裂会使树的复杂度增加
- 对每个节点枚举所有特征,对每个特征按值排序,线性扫描决定该特征的最佳分裂点,采用所有特征中的最佳分裂点
-
近似算法
- 将分位数作为最佳分裂点的候选点
- 分位数的选取策略
- global:在全体样本的特征值中选取,在根节点分裂之前进行一次即可
- local:在待分裂节点包含的样本特征值中选取,每个节点分裂前都要进行
-
加权分位数
\[\begin{align} Obj &\approx \sum_{i=1}^n [g_if_t(x_i)+\frac{1}{2}h_if^2_t(x_i)] + \Omega(f_t) \\ &= \sum_{i=1}^n \frac{1}{2} h_i[f_t(x_i) - (-\frac{g_i}{h_i})]^2 + \Omega(f_t) - constant \end{align} \]- 将目标函数配方整理,可以将得到的新目标函数理解为以 \(h_i\) 为权重,\(-g_i/h_i\) 为标签的损失函数,因此近似算法以 \(h_i\) 为权重取分位数
其他优化:
- 列采样:与 RF 相同,每次节点分裂时,先随机选取一部分特征,再从这部分特征中选择最优特征
- 学习率:为不让单颗树太激进地拟合,在每个子模型前乘以一个系数
- 稀疏感知
- 稀疏 0 和缺失值被等同视作缺失值,节点分裂选择最佳分裂点时会跳过缺失值整体
- 缺失值会分两种情况讨论:小于最小值、大于最大值
工程设计:
- 并行列块设计
- 将每一列特征提前排序,以块的形式储存在缓存中,以索引将特征值和一阶导 \(g_i\)、二阶导 \(h_i\) 对应,每次节点分裂时重复调用排好序的块
- 多个特征之间互不干涉,可以在特征层面并行
- 缓存访问优化
- 排序后通过索引取一阶导 \(g_i\)、二阶导 \(h_i\) 会导致访问的内存空间不一致,降低缓存命中率
- 为每个线程分配一个单独的连续缓存区,用来存放梯度信息
- 核外块计算
- 数据量非常大时,数据无法同时全部载入内存
- 使用一个独立线程专门从磁盘读数据到内存,实现计算和读数据的同时进行
- 压缩块,用解压缩开销换磁盘读取开销
- 将块分散在多个磁盘,提高磁盘吞吐量
XGBoost 的缺点:
- XGBoost 节点分裂所用的贪心算法,需要保存数据的特征值和特征排序的结果,计算量大、空间消耗大、容易过拟合
- XGBoost 采用 Level-wise 生长方式,基于层生长,直到达到停止条件,可能产生不必要的结点分裂
- XGboost 将每一列特征提前排序,导致排序后通过索引取梯度的访问是随机访问,且不同特征访问的顺序不通,对缓存优化不友好
LightGBM
LightGBM:
- 相比于 XGBoost
- 使用基于直方图的决策树算法,减小空间消耗
- 使用带深度限制的 Leaf-wise 生长方式,减少不必要的节点分裂
- 使用单边梯度采样算法 (GOSS),减少数据量,提高训练速度
- 使用互斥特征捆绑算法 (EFB),减少特征数量,提高训练速度
- 直接支持类别特征,可以特征并行、投票并行、数据并行,缓存访问优化
基于直方图的决策树算法:
- 算法流程
- 将连续的浮点特征离散成 \(k\) 个离散值,构造宽度为 \(k\) 的直方图
- 遍历训练数据,统计每个离散值在直方图中的累计统计量
- 在进行节点分裂时,只需要根据直方图的离散值,遍历寻找最优的分裂点
- 差加速:一个叶子节点的直方图,可以由它的父亲节点的直方图,与它兄弟的直方图做差得到
- 注意:直方图的分桶相当于正则化,桶越少,惩罚越严重,欠拟合风险越高
带深度限制的 Leaf-wise 生长方式:
- 算法流程:每次从当前所有叶子节点中,找到分裂增益最大的叶子节点分裂
- 注意
- 在分裂次数相同时,可以降低误差
- 可能会长出较深的决策树,产生过拟合,因此需要增加最大深度限制
单边梯度采样算法 (GOSS):
- 算法思想:梯度大的样本对节点分裂的信息增益有更大的影响,可以通过采样保留较多梯度大的样本和少量梯度小的样本,从而减少数据量,提高训练速度
- 算法流程
- 对于要进行节点分裂的特征,将梯度的绝对值按降序排序
- 选取绝对值最大的 \(a\) 个数据
- 在其余数据中,随机选取 \(b\) 个数据,为不过多改变数据的原始分布,将这部分数据乘以 \((1-a)/b\)
互斥特征捆绑算法 (EFB):
- 算法思想:一些特征是互斥的 (很少同时出现非零值),例如 One-hot 特征,可以把这些特征捆绑在一起形成一个新特征,从而减少特征数量,提高训练速度
- 算法流程:使用贪心算法得到图着色问题的近似解
- 构造一个加权无向图,顶点是特征,边是特征间互斥度
- 根据节点的度降序排序,度越大,与其他特征的冲突越大
- 遍历每个特征,尝试将它分配给现有特征捆绑包,使总体冲突最小
- 如果该特征与任何现有特征捆绑包的互斥度都超出阈值允许范围,则新建特征捆绑包
工程设计:
-
直接支持类别特征
-
算法思想:One-hot 编码会使样本切分不平衡,或将样本切分到很多零散的小空间上,LightGBM 直接支持类别特征,不需要使用 One-hot 编码
-
算法流程:对于某个特征,对于直方图的每个 bin,计算一阶导之和除以二阶导之和,根据该值对 bin 排序,线性扫描决定该特征的最佳分裂点
\[\frac{\sum_{x_i\in bin} g_i}{\sum_{x_i\in bin} h_i} + 正则项 \]
-
-
特征并行、投票并行、数据并行
-
缓存访问优化
CatBoost
CatBoost:
- 相比于 XGBoost 和 LightGBM
- 使用对称决策树
- 直接支持类别特征
- 克服梯度偏差
对称决策树:
- 相同的分割准则在树的整个一层上使用
- 是平衡的,不易过拟合
支持类别特征:
- 目标变量统计:当类别特征的数量很大时,使用 One-hot 编码会造成维度灾难,可以将类别分组成有限个的群体再进行 One-hot 编码,目标变量统计 (Target Statistics) 可以用于将类别分组,或直接将类别特征变为数值特征
- 特征组合
- 对于树的第一个分割,不考虑任何组合
- 对于树的下一个分割,将当前树的所有组合、类别型特征,与数据集中的所有类别型特征相结合,得到新的特征组合,将新的特征组合通过目标统计量转换为数值型特征
- 当需要组合的类别型特征变多时,只考虑一部分组合
克服梯度偏差:
- 梯度偏差:在每一步迭代中,损失函数使用相同的数据集求得当前模型的梯度,然后训练得到基学习器,这会导致梯度估计偏差,进而导致模型产生过拟合的问题,CatBoost 使用排序提升法克服梯度偏差
- 排序提升算法:对每一个样本 \(x_i\),训练一个单独的模型 \(M_i\) ,即模型 \(M_i\) 是由使用不包含样本 \(x_i\) 的训练集训练得到,使用 \(M_i\) 得到关于样本梯度的估计,并使用该梯度训练基学习器并得到最终的模型
参考
- 个人博客:Decision Tree 决策树
- 知乎:深入理解 XGBoost
- 知乎:深入理解 LightGBM
- 知乎:深入理解 CatBoost
- 知乎:详解 LightGBM 两大利器:基于梯度的单边采样 (GOSS) 和互斥特征捆绑 (EFB)
- 博客园:初学 CatBoost 模型——特性、原理、目标编码、调参
- B 站:GBDT 面试八股文 xgboost lightgbm catboost 横向对比