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

相关推荐
那个村的李富贵9 小时前
光影魔术师:CANN加速实时图像风格迁移,让每张照片秒变大师画作
人工智能·aigc·cann
腾讯云开发者10 小时前
“痛点”到“通点”!一份让 AI 真正落地产生真金白银的实战指南
人工智能
CareyWYR10 小时前
每周AI论文速递(260202-260206)
人工智能
hopsky11 小时前
大模型生成PPT的技术原理
人工智能
禁默12 小时前
打通 AI 与信号处理的“任督二脉”:Ascend SIP Boost 加速库深度实战
人工智能·信号处理·cann
心疼你的一切12 小时前
昇腾CANN实战落地:从智慧城市到AIGC,解锁五大行业AI应用的算力密码
数据仓库·人工智能·深度学习·aigc·智慧城市·cann
AI绘画哇哒哒12 小时前
【干货收藏】深度解析AI Agent框架:设计原理+主流选型+项目实操,一站式学习指南
人工智能·学习·ai·程序员·大模型·产品经理·转行
数据分析能量站12 小时前
Clawdbot(现名Moltbot)-现状分析
人工智能
那个村的李富贵12 小时前
CANN加速下的AIGC“即时翻译”:AI语音克隆与实时变声实战
人工智能·算法·aigc·cann
二十雨辰12 小时前
[python]-AI大模型
开发语言·人工智能·python