Week 27: 机器学习补遗:XGBoost

文章目录

  • [Week 27: 机器学习补遗:XGBoost](#Week 27: 机器学习补遗:XGBoost)
    • 摘要
    • Abstract
    • [1. 数学原理:二阶泰勒展开与目标函数](#1. 数学原理:二阶泰勒展开与目标函数)
      • [1.1 概要](#1.1 概要)
      • [1.2 代码实现](#1.2 代码实现)
      • [1.3 效果分析](#1.3 效果分析)
    • [2. 结构打分与正则化](#2. 结构打分与正则化)
      • [2.1 概要](#2.1 概要)
      • [2.2 代码实现](#2.2 代码实现)
      • [2.3 关键特性分析](#2.3 关键特性分析)
    • [3. 时序预测中的应用](#3. 时序预测中的应用)
      • [3.1 概要](#3.1 概要)
      • [3.2 代码实现](#3.2 代码实现)
      • [3.3 效果与对比](#3.3 效果与对比)
    • 总结

Week 27: 机器学习补遗:XGBoost

摘要

本周继续回归经典机器学习领域,对XGBoost 进行了学习。本周重点推导了 XGBoost 基于二阶泰勒展开的目标函数,并结合时序预测场景进行学习。

Abstract

This week we continued our return to the classic field of machine learning, focusing on XGBoost. The primary emphasis was on deriving XGBoost's objective function based on a second-order Taylor expansion, alongside its application within a time series forecasting scenario.

1. 数学原理:二阶泰勒展开与目标函数

1.1 概要

XGBoost (Extreme Gradient Boosting) 的核心优势在于其对目标函数的二阶近似和显式的正则化项。与传统 GBDT 只利用一阶导数不同,XGBoost 利用了泰勒展开保留了二阶导数信息,使得目标函数的下降更加精准。

设 y i y_i yi 为真实值, y ^ i ( t ) \hat{y}i^{(t)} y^i(t) 为第 t t t 轮的预测值。目标函数定义为:
L ( t ) = ∑ i = 1 n l ( y i , y ^ i ( t − 1 ) + f t ( x i ) ) + Ω ( f t ) \mathcal{L}^{(t)} = \sum
{i=1}^n l(y_i, \hat{y}_i^{(t-1)} + f_t(x_i)) + \Omega(f_t) L(t)=i=1∑nl(yi,y^i(t−1)+ft(xi))+Ω(ft)

其中 f t ( x i ) f_t(x_i) ft(xi) 是第 t t t 棵树的预测结果, Ω ( f t ) \Omega(f_t) Ω(ft) 是正则化项。

对损失函数 l l l 进行二阶泰勒展开:
L ( t ) ≈ ∑ i = 1 n [ l ( y i , y ^ ( t − 1 ) ) + g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + Ω ( f t ) \mathcal{L}^{(t)} \approx \sum_{i=1}^n [l(y_i, \hat{y}^{(t-1)}) + g_i f_t(x_i) + \frac{1}{2}h_i f_t^2(x_i)] + \Omega(f_t) L(t)≈i=1∑n[l(yi,y^(t−1))+gift(xi)+21hift2(xi)]+Ω(ft)

其中 g i = ∂ y ^ ( t − 1 ) l ( y i , y ^ ( t − 1 ) ) g_i = \partial_{\hat{y}^{(t-1)}} l(y_i, \hat{y}^{(t-1)}) gi=∂y^(t−1)l(yi,y^(t−1)) 为一阶梯度, h i = ∂ y ^ ( t − 1 ) 2 l ( y i , y ^ ( t − 1 ) ) h_i = \partial^2_{\hat{y}^{(t-1)}} l(y_i, \hat{y}^{(t-1)}) hi=∂y^(t−1)2l(yi,y^(t−1)) 为二阶梯度。由于 l ( y i , y ^ ( t − 1 ) ) l(y_i, \hat{y}^{(t-1)}) l(yi,y^(t−1)) 是常数,优化目标简化为最小化:
L ~ ( t ) = ∑ i = 1 n [ g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + Ω ( f t ) \tilde{\mathcal{L}}^{(t)} = \sum_{i=1}^n [g_i f_t(x_i) + \frac{1}{2}h_i f_t^2(x_i)] + \Omega(f_t) L~(t)=i=1∑n[gift(xi)+21hift2(xi)]+Ω(ft)

1.2 代码实现

python 复制代码
import numpy as np
import xgboost as xgb
from typing import Tuple

def custom_logloss_objective(preds: np.ndarray, dtrain: xgb.DMatrix) -> Tuple[np.ndarray, np.ndarray]:
    """
    手动实现基于LogLoss的一阶(grad)和二阶(hess)梯度计算
    Preds: 模型的原始输出 (Logits),未经过Sigmoid
    """
    labels = dtrain.get_label()
    
    # Sigmoid变换: 1 / (1 + exp(-x))
    preds_prob = 1.0 / (1.0 + np.exp(-preds))
    
    # 一阶梯度 grad = p - y
    grad = preds_prob - labels
    
    # 二阶梯度 hess = p * (1 - p)
    hess = preds_prob * (1.0 - preds_prob)
    
    return grad, hess

# 使用示例
# model = xgb.train(params, dtrain, obj=custom_logloss_objective)

1.3 效果分析

通过引入二阶导数 h i h_i hi,XGBoost 相当于在优化过程中利用了牛顿法(Newton's Method)的思想,比单纯的一阶梯度下降收敛速度更快。同时,自定义目标函数赋予了模型极强的灵活性,能够适应不对称损失等复杂场景。

2. 结构打分与正则化

2.1 概要

为了防止过拟合,XGBoost 将树的复杂度显式加入目标函数:
Ω ( f ) = γ T + 1 2 λ ∣ ∣ w ∣ ∣ 2 \Omega(f) = \gamma T + \frac{1}{2}\lambda ||w||^2 Ω(f)=γT+21λ∣∣w∣∣2

其中 T T T 是叶子节点数量, w w w 是叶子节点的权重向量。

将所有样本按照叶子节点归组,令 I j = { i ∣ q ( x i ) = j } I_j = \{i|q(x_i)=j\} Ij={i∣q(xi)=j} 为属于第 j j j 个叶子节点的样本集合。目标函数可重写为关于叶子权重 w j w_j wj 的一元二次方程。求解后,可得第 t t t 棵树的最优结构分数(Structure Score):

O b j ∗ = − 1 2 ∑ j = 1 T ( ∑ i ∈ I j g i ) 2 ∑ i ∈ I j h i + λ + γ T Obj^* = -\frac{1}{2} \sum_{j=1}^T \frac{(\sum_{i\in I_j} g_i)^2}{\sum_{i\in I_j} h_i + \lambda} + \gamma T Obj∗=−21j=1∑T∑i∈Ijhi+λ(∑i∈Ijgi)2+γT

这个分数类似于决策树中的 Gini 系数或信息增益,用于评价树结构的优劣。分裂收益(Gain)计算公式为:
G a i n = 1 2 [ G L 2 H L + λ + G R 2 H R + λ − ( G L + G R ) 2 H L + H R + λ ] − γ Gain = \frac{1}{2} \left[ \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} \right] - \gamma Gain=21[HL+λGL2+HR+λGR2−HL+HR+λ(GL+GR)2]−γ

2.2 代码实现

python 复制代码
class XGBNodeSplitter:
    def __init__(self, reg_lambda=1.0, gamma=0.0):
        self.reg_lambda = reg_lambda
        self.gamma = gamma

    def calculate_score(self, G, H):
        """
        计算单个叶子节点的分数
        G: 该节点所有样本的一阶梯度之和
        H: 该节点所有样本的二阶梯度之和
        """
        return -0.5 * (G**2) / (H + self.reg_lambda)

    def calculate_split_gain(self, G_left, H_left, G_right, H_right):
        """
        计算分裂增益 Gain
        """
        # 分裂前的梯度和
        G_total = G_left + G_right
        H_total = H_left + H_right
        
        # 分裂前的分数 (Root)
        score_before = self.calculate_score(G_total, H_total) # 注意:公式中常省略前面的负号用于求最大值,这里保持一致
        # 但Gain公式通常是:Split后分数和 - Split前分数 - 代价
        
        term_L = (G_left**2) / (H_left + self.reg_lambda)
        term_R = (G_right**2) / (H_right + self.reg_lambda)
        term_Total = (G_total**2) / (H_total + self.reg_lambda)
        
        gain = 0.5 * (term_L + term_R - term_Total) - self.gamma
        return gain

# 模拟数据
splitter = XGBNodeSplitter(reg_lambda=1.0, gamma=0.1)
gain = splitter.calculate_split_gain(G_left=10, H_left=5, G_right=20, H_right=8)
print(f"Split Gain: {gain:.4f}")

2.3 关键特性分析

公式中的 λ \lambda λ 充当了平滑项,当某个叶子节点样本极少( H H H 很小)时, λ \lambda λ 避免了权重 w w w 过大,起到了抑制过拟合的作用。而 γ \gamma γ 则是分裂的"最低门槛",只有当分裂带来的增益大于 γ \gamma γ 时,节点才会分裂,这相当于自动进行了预剪枝(Pre-pruning)。

3. 时序预测中的应用

3.1 概要

在时序预测中,XGBoost 不能像 RNN/Transformer 那样直接处理序列依赖,需要将时序问题转化为监督学习问题(Supervised Learning)。核心在于特征工程 ,即将时间步 t t t 的预测依赖转化为 t − 1 , t − 2... t-1, t-2... t−1,t−2... 的特征输入。

3.2 代码实现

python 复制代码
import pandas as pd

def create_time_series_features(df: pd.DataFrame, target_col: str, lags: list, window: int):
    """
    构造时序特征:Lag特征 和 滚动统计特征
    """
    df_feat = df.copy()
    
    # 1. 构造滞后特征 (Lag Features)
    # 捕捉原本的序列依赖:相当于 AR 模型
    for lag in lags:
        df_feat[f'lag_{lag}'] = df_feat[target_col].shift(lag)
        
    # 2. 构造滚动统计特征 (Rolling Features)
    # 捕捉局部趋势和波动:相当于 MA 模型思想的扩展
    df_feat[f'rolling_mean_{window}'] = df_feat[target_col].shift(1).rolling(window=window).mean()
    df_feat[f'rolling_std_{window}'] = df_feat[target_col].shift(1).rolling(window=window).std()
    
    # 3. 时间特征
    df_feat['month'] = df_feat.index.month
    df_feat['day_of_week'] = df_feat.index.dayofweek
    
    # 去除因shift产生的NaN
    return df_feat.dropna()

# 假设 df 是以时间为索引的 DataFrame
# df_processed = create_time_series_features(df, 'sales', lags=[1, 7, 14, 30], window=7)

3.3 效果与对比

与Transformer 相比,XGBoost 在时序任务上的优势在于:

  1. 训练速度极快:无需像 LSTM/ViT 那样进行 BPTT。
  2. 对缺失值不敏感:XGBoost 自带稀疏感知算法(Sparsity Aware Split Finding),自动学习缺失值的默认分裂方向。
  3. 可解释性强:可以通过 Feature Importance 明确知道是"上周销量"还是"促销活动"主导了预测。

但缺点在于无法捕捉超长期的依赖(Long-term dependencies)以及无法外推(Extrapolation)到未见过的数值范围。

总结

本周重新审视了 XGBoost 这一机器学习界的基本算法,通过手推公式和模拟代码,重新尝试理解传统机器学习算法在时序应用上的独特优越之处。在 接触多模态风控数据后,发现对于数值型和类别型密集的表格数据,Transformer等深度模型往往需要极其复杂的 Embedding 设计才能匹敌 XGBoost 的简单暴力。在后续的学习实验中,我将进一步尝试深度学习 处理非结构化数据 + XGBoost 处理结构化数据 的两阶段融合策略作为一种可以考虑的实验方案。

相关推荐
玖日大大1 小时前
Mobile-Agent-基于多模态大模型(MLLM)的视觉驱动型GUI智能体
人工智能
Blossom.1181 小时前
基于知识图谱+LLM的工业设备故障诊断:从SQL日志到可解释推理的实战闭环
人工智能·python·sql·深度学习·算法·transformer·知识图谱
t梧桐树t1 小时前
spring AI都能做什么
java·人工智能·spring
lpfasd1231 小时前
AI 时代,编程语言战争会终止吗?
人工智能
WLJT1231231231 小时前
芯片与电流:点亮生活的科技力量
大数据·人工智能·科技·生活
syounger2 小时前
德军 SAP 迁移受阻:S4/HANA 系统功能不稳定,全面上线再度推迟
大数据·人工智能
声网2 小时前
全球首个语音 AI 广告平台问世;Sam Altman 与 Jony Ive:合作新硬件将「如湖畔山间小屋般平静」丨日报
人工智能
Yeats_Liao2 小时前
CANN Samples(七):视频与流媒体:RTSP与多路输入实战
人工智能·机器学习·音视频
玖日大大2 小时前
X-AnyLabeling-实践使用AI驱动的图像
人工智能