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 处理结构化数据 的两阶段融合策略作为一种可以考虑的实验方案。

相关推荐
竣雄7 分钟前
计算机视觉:原理、技术与未来展望
人工智能·计算机视觉
救救孩子把17 分钟前
44-机器学习与大模型开发数学教程-4-6 大数定律与中心极限定理
人工智能·机器学习
Rabbit_QL30 分钟前
【LLM评价指标】从概率到直觉:理解语言模型的困惑度
人工智能·语言模型·自然语言处理
呆萌很36 分钟前
HSV颜色空间过滤
人工智能
roman_日积跬步-终至千里1 小时前
【人工智能导论】02-搜索-高级搜索策略探索篇:从约束满足到博弈搜索
java·前端·人工智能
FL16238631291 小时前
[C#][winform]基于yolov11的淡水鱼种类检测识别系统C#源码+onnx模型+评估指标曲线+精美GUI界面
人工智能·yolo·目标跟踪
爱笑的眼睛111 小时前
从 Seq2Seq 到 Transformer++:深度解构与自构建现代机器翻译核心组件
java·人工智能·python·ai
小润nature2 小时前
AI时代对编程技能学习方式的根本变化(1)
人工智能
AI即插即用3 小时前
即插即用系列 | ECCV 2024 WTConv:利用小波变换实现超大感受野的卷积神经网络
图像处理·人工智能·深度学习·神经网络·计算机视觉·cnn·视觉检测
愚公搬代码3 小时前
【愚公系列】《扣子开发 AI Agent 智能体应用》003-扣子 AI 应用开发平台介绍(选择扣子的理由)
人工智能