梯度提升原理

目录


1. 决策树基础

1.1 什么是决策树

决策树是一种基本的机器学习算法,它通过一系列的”是/否”判断来做出预测。想象一个”20个问题”游戏:

问题1:这个因子值是否大于 0.5?
├─ 是 → 问题2:动量因子是否为正?
│   ├─ 是 → 预测:上涨
│   └─ 否 → 预测:持平
└─ 否 → 问题3:波动率是否小于 0.3?
    ├─ 是 → 预测:下跌
    └─ 否 → 预测:持平

决策树的组成:

组成部分说明
根节点树的起点,包含所有样本
内部节点每个节点代表一个特征判断
分支判断的结果(是/否)
叶节点最终的预测结果

1.2 树如何分裂:决策准则

决策树的核心问题是:如何在每个节点选择最佳分裂特征和分裂点?

信息增益(Information Gain)

信息增益基于熵的概念,衡量分裂前后信息不确定性的减少。

熵的公式:

其中 是第 类的比例。

条件熵: 分裂后各子节点的加权熵

信息增益:

选择信息增益最大的特征和分裂点。

import numpy as np
 
def entropy(y):
    """计算标签的熵"""
    _, counts = np.unique(y, return_counts=True)
    p = counts / len(y)
    return -np.sum(p * np.log2(p + 1e-10))
 
def information_gain(y, left_indices, right_indices):
    """计算信息增益"""
    parent_entropy = entropy(y)
    n = len(y)
    n_left, n_right = len(left_indices), len(right_indices)
 
    child_entropy = (n_left / n) * entropy(y[left_indices]) + \
                   (n_right / n) * entropy(y[right_indices])
 
    return parent_entropy - child_entropy
 
# 示例:模拟量化场景
# y = 1 表示上涨,0 表示下跌/持平
np.random.seed(42)
y = np.array([1, 1, 1, 0, 0, 0, 1, 0])
 
# 假设按因子值 > 0.5 分裂
left_idx = np.where(y > 0.5)[0]  # 简化示例
right_idx = np.where(y <= 0.5)[0]
 
gain = information_gain(y, left_idx, right_idx)
print(f"信息增益: {gain:.4f}")

基尼系数(Gini Impurity)

基尼系数是另一种不纯度度量,计算更简单。

基尼系数公式:

选择基尼系数下降最多的分裂。

def gini_impurity(y):
    """计算基尼不纯度"""
    _, counts = np.unique(y, return_counts=True)
    p = counts / len(y)
    return 1 - np.sum(p ** 2)
 
def gini_gain(y, left_indices, right_indices):
    """计算基尼增益"""
    parent_gini = gini_impurity(y)
    n = len(y)
    n_left, n_right = len(left_indices), len(right_indices)
 
    child_gini = (n_left / n) * gini_impurity(y[left_indices]) + \
                 (n_right / n) * gini_impurity(y[right_indices])
 
    return parent_gini - child_gini
 
gain_gini = gini_gain(y, left_idx, right_idx)
print(f"基尼增益: {gain_gini:.4f}")

信息增益 vs 基尼系数:

特性信息增益基尼系数
计算复杂度较高(对数运算)较低(平方运算)
偏向偏向多分支偏向平衡分裂
实际应用ID3/C4.5CART(sklearn 默认)

1.3 决策树的分裂示例

让我们看一个简化的量化场景:

import pandas as pd
import numpy as np
 
# 模拟数据:股票特征和未来收益
np.random.seed(42)
n_samples = 1000
 
# 特征:动量、波动率、换手率
momentum = np.random.randn(n_samples)
volatility = np.random.rand(n_samples) * 0.5 + 0.1
turnover = np.random.rand(n_samples) * 0.2
 
# 标签:未来收益 > 0 为正样本
returns = 0.3 * momentum - 0.5 * volatility + 0.1 * turnover + np.random.randn(n_samples) * 0.3
y = (returns > 0).astype(int)
 
# 创建 DataFrame
df = pd.DataFrame({
    'momentum': momentum,
    'volatility': volatility,
    'turnover': turnover,
    'positive_return': y
})
 
# 手动计算最佳分裂点
def find_best_split(feature, y):
    """寻找特征的最佳分裂点"""
    best_gain = -1
    best_split = None
 
    unique_values = np.unique(feature)
    for i in range(len(unique_values) - 1):
        split = (unique_values[i] + unique_values[i + 1]) / 2
        left = feature <= split
        right = feature > split
 
        if np.sum(left) > 0 and np.sum(right) > 0:
            gain = gini_gain(y, np.where(left)[0], np.where(right)[0])
            if gain > best_gain:
                best_gain = gain
                best_split = split
 
    return best_gain, best_split
 
# 测试每个特征
for feature_name in ['momentum', 'volatility', 'turnover']:
    feature = df[feature_name].values
    gain, split = find_best_split(feature, y)
    print(f"{feature_name:12s}: 最佳分裂点 = {split:.4f}, 基尼增益 = {gain:.4f}")

输出示例:

momentum    : 最佳分裂点 = 0.0123, 基尼增益 = 0.0834
volatility  : 最佳分裂点 = 0.3478, 基尼增益 = 0.0256
turnover    : 最佳分裂点 = 0.1024, 基尼增益 = 0.0123

结论: 动量因子的分裂效果最好,说明它对预测收益最有帮助。

1.4 剪枝(Pruning)

决策树容易过拟合,需要剪枝来控制复杂度。

预剪枝(Pre-pruning): 在训练过程中限制树的生长

参数说明
max_depth树的最大深度
min_samples_split节点分裂所需的最小样本数
min_samples_leaf叶节点的最小样本数
max_leaf_nodes最大叶节点数
min_impurity_decrease分裂所需的最小不纯度减少量

后剪枝(Post-pruning): 先让树完全生长,再剪掉不重要的分支

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
 
X = df[['momentum', 'volatility', 'turnover']]
y = df['positive_return']
 
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
 
# 不剪枝:容易过拟合
tree_no_pruning = DecisionTreeClassifier(random_state=42)
tree_no_pruning.fit(X_train, y_train)
print(f"不剪枝 - 训练准确率: {tree_no_pruning.score(X_train, y_train):.4f}")
print(f"不剪枝 - 测试准确率: {tree_no_pruning.score(X_test, y_test):.4f}")
print(f"树深度: {tree_no_pruning.get_depth()}, 叶节点数: {tree_no_pruning.get_n_leaves()}")
 
# 预剪枝:限制复杂度
tree_pruned = DecisionTreeClassifier(
    max_depth=3,
    min_samples_leaf=20,
    random_state=42
)
tree_pruned.fit(X_train, y_train)
print(f"\n预剪枝 - 训练准确率: {tree_pruned.score(X_train, y_train):.4f}")
print(f"预剪枝 - 测试准确率: {tree_pruned.score(X_test, y_test):.4f}")
print(f"树深度: {tree_pruned.get_depth()}, 叶节点数: {tree_pruned.get_n_leaves()}")

2. 集成学习思想

2.1 为什么需要集成

单棵决策树有以下问题:

问题说明影响
高方差数据变化导致树结构剧烈变化不稳定
容易过拟合可以完美记住训练数据泛化差
决策边界不平滑由正交分割组成不够精细

集成学习的核心思想: 组合多个弱学习器,创造一个强学习器。

2.2 Bagging:Bootstrap Aggregating

核心思想: 并行训练多个独立模型,然后平均预测。

流程:

1. 有放回抽样 → 生成 B 个不同的训练集
2. 对每个训练集训练一棵决策树
3. 预测时:对所有树的预测取平均(回归)或投票(分类)

为什么有效: 通过平均降低方差。

from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
 
# Bagging 示例
bagging = BaggingClassifier(
    estimator=DecisionTreeClassifier(max_depth=3),
    n_estimators=100,
    max_samples=0.8,  # 每棵树用 80% 的样本
    max_features=0.8,  # 每棵树用 80% 的特征
    random_state=42,
    n_jobs=-1
)
 
bagging.fit(X_train, y_train)
print(f"Bagging - 训练准确率: {bagging.score(X_train, y_train):.4f}")
print(f"Bagging - 测试准确率: {bagging.score(X_test, y_test):.4f}")

随机森林(Random Forest) 是 Bagging 的经典实现:

from sklearn.ensemble import RandomForestClassifier
 
rf = RandomForestClassifier(
    n_estimators=100,
    max_depth=5,
    min_samples_leaf=20,
    max_features='sqrt',  # 特征随机性
    random_state=42,
    n_jobs=-1
)
 
rf.fit(X_train, y_train)
print(f"随机森林 - 训练准确率: {rf.score(X_train, y_train):.4f}")
print(f"随机森林 - 测试准确率: {rf.score(X_test, y_test):.4f}")

2.3 Boosting:串行改进

核心思想: 串行训练模型,每个新模型专注于纠正前一个模型的错误。

Bagging vs Boosting 对比:

特性BaggingBoosting
训练方式并行串行
模型权重相等根据性能加权
目标降低方差降低偏差和方差
对异常值鲁棒敏感
代表算法随机森林GBDT, XGBoost, LightGBM

Boosting 工作流程:

1. 训练第一个弱学习器 h₁(x)
2. 计算残差/误差 r₁ = y - h₁(x)
3. 训练第二个弱学习器 h₂(x) 去预测 r₁
4. 计算新的残差 r₂ = r₁ - h₂(x)
5. 重复步骤 3-4,直到达到预设数量
6. 最终预测:H(x) = h₁(x) + h₂(x) + ... + h_T(x)

3. GBDT 原理

3.1 前向分步加法模型

GBDT(Gradient Boosting Decision Tree)是 Boosting 思想与决策树的结合。

数学表达:

给定损失函数 ,GBDT 通过以下方式构建模型:

其中:

  • 是前 m-1 轮的累积模型
  • 是第 m 棵决策树
  • 是学习率(shrinkage)

核心问题: 如何找到每棵树的最佳拟合方向?

3.2 负梯度拟合(伪残差)

GBDT 的关键创新:用损失函数的负梯度作为残差。

对于平方损失

负梯度 = 残差:

对于一般损失函数,第 m 棵树拟合的目标是:

这就是为什么叫”梯度”提升!

def pseudo_residual(y, pred, loss='square'):
    """计算伪残差"""
    if loss == 'square':
        # 平方损失的负梯度就是残差
        return y - pred
    elif loss == 'log':
        # LogLoss 的负梯度
        return y - 1 / (1 + np.exp(-pred))
    else:
        raise ValueError(f"Unknown loss: {loss}")
 
# 示例
y_true = np.array([1, 0, 1, 1])
pred = np.array([0.7, 0.3, 0.6, 0.9])
 
residuals = pseudo_residual(y_true, pred)
print("伪残差:", residuals)

3.3 GBDT 算法流程

完整算法:

  1. 初始化:

  2. 对于 m = 1 到 M:

    • 计算伪残差:
    • 用残差训练决策树:拟合
    • 计算叶节点的最佳值:
    • 更新模型:
  3. 输出:

其中 是学习率,通常取 0.01 - 0.1。

3.4 GBDT 简单实现

import numpy as np
from sklearn.tree import DecisionTreeRegressor
 
class SimpleGBDT:
    """简化的 GBDT 实现,仅用于理解原理"""
 
    def __init__(self, n_estimators=100, learning_rate=0.1, max_depth=3):
        self.n_estimators = n_estimators
        self.learning_rate = learning_rate
        self.max_depth = max_depth
        self.trees = []
        self.init_pred = None
 
    def fit(self, X, y):
        """训练模型"""
        # 初始化:预测均值
        self.init_pred = np.mean(y)
        F_m = np.full(len(y), self.init_pred)
 
        for m in range(self.n_estimators):
            # 计算负梯度(残差)
            residual = y - F_m
 
            # 训练决策树拟合残差
            tree = DecisionTreeRegressor(max_depth=self.max_depth)
            tree.fit(X, residual)
 
            # 更新预测
            F_m += self.learning_rate * tree.predict(X)
 
            self.trees.append(tree)
 
    def predict(self, X):
        """预测"""
        F_m = np.full(X.shape[0], self.init_pred)
        for tree in self.trees:
            F_m += self.learning_rate * tree.predict(X)
        return F_m
 
# 测试
X = df[['momentum', 'volatility', 'turnover']].values
y = df['positive_return'].values
 
gbdt = SimpleGBDT(n_estimators=50, learning_rate=0.1, max_depth=3)
gbdt.fit(X, y)
 
predictions = gbdt.predict(X)
print(f"预测范围: [{predictions.min():.4f}, {predictions.max():.4f}]")
print(f"真实均值: {y.mean():.4f}, 预测均值: {predictions.mean():.4f}")

3.5 学习率的作用

学习率(shrinkage)是 GBDT 的重要超参数:

学习率效果树数量需求过拟合风险
大(0.1-0.3)收敛快
小(0.01-0.05)收敛慢

原则: 学习率越小,需要更多的树,但泛化性能更好。


4. XGBoost 创新

XGBoost(eXtreme Gradient Boosting)是 GBDT 的高效实现,在竞赛和工业界广受欢迎。

4.1 二阶泰勒展开

传统 GBDT 只用一阶导数(梯度),XGBoost 使用二阶导数(Hessian)。

泰勒展开近似损失函数:

目标函数(忽略常数项):

其中:

  • 一阶导
  • 二阶导
  • 是正则化项

优势: 更准确地逼近损失函数,收敛更快。

4.2 正则化

XGBoost 在目标函数中显式加入正则化项:

其中:

  • :叶节点数量的惩罚系数
  • :叶节点数量
  • :L2 正则化系数
  • :第 j 个叶节点的预测值

作用: 控制模型复杂度,防止过拟合。

4.3 列采样(Column Subsampling)

XGBoost 借鉴随机森林,引入列采样:

采样方式参数说明
按树采样colsample_bytree每棵树随机选择特征子集
按层采样colsample_bylevel每层随机选择特征子集
按分裂采样colsample_bynode每次分裂随机选择特征子集

作用: 降低过拟合风险,加速训练。

4.4 缺失值处理

XGBoost 可以自动处理缺失值:

import xgboost as xgb
 
# 创建包含缺失值的数据
X_missing = df[['momentum', 'volatility', 'turnover']].copy()
X_missing.loc[np.random.choice(len(X_missing), 50), 'momentum'] = np.nan
 
dtrain = xgb.DMatrix(X_missing, label=y)
 
# XGBoost 自动学习缺失值的分裂方向
params = {
    'max_depth': 3,
    'eta': 0.1,
    'objective': 'binary:logistic'
}
 
bst = xgb.train(params, dtrain, num_boost_round=100)
print("XGBoost 自动处理了缺失值!")

原理: 对每个分裂点,XGBoost 分别计算缺失值去左右分支的增益,选择更好的方向。

4.5 XGBoost 使用示例

from xgboost import XGBClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
 
X_train, X_test, y_train, y_test = train_test_split(
    df[['momentum', 'volatility', 'turnover']],
    df['positive_return'],
    test_size=0.3,
    random_state=42
)
 
# XGBoost 分类器
xgb_model = XGBClassifier(
    n_estimators=200,
    max_depth=4,
    learning_rate=0.05,
    min_child_weight=10,
    subsample=0.8,
    colsample_bytree=0.8,
    reg_lambda=1.0,  # L2 正则化
    reg_alpha=0.1,   # L1 正则化
    random_state=42,
    n_jobs=-1,
    eval_metric='logloss'
)
 
xgb_model.fit(
    X_train, y_train,
    eval_set=[(X_test, y_test)],
    verbose=False
)
 
y_pred = xgb_model.predict(X_test)
print(f"XGBoost 测试准确率: {accuracy_score(y_test, y_pred):.4f}")

5. LightGBM 创新

LightGBM 是微软推出的梯度提升框架,专注于效率和内存优化。

5.1 GOSS:基于梯度的单边采样

问题: 所有样本都参与训练,计算成本高。

GOSS 策略:

  1. 根据梯度的绝对值对样本排序
  2. 保留梯度大的样本(a%):这些样本训练误差大,更重要
  3. 随机采样梯度小的样本(b%):这些样本训练误差小
  4. 对小梯度样本乘以一个常数 来补偿

优势: 用更少的样本达到相似的精度,加速训练。

import lightgbm as lgb
 
# LightGBM 默认使用 GOSS
lgb_model = lgb.LGBMClassifier(
    n_estimators=200,
    max_depth=4,
    learning_rate=0.05,
    min_child_samples=20,
    subsample=0.8,  # GOSS 采样
    colsample_bytree=0.8,
    reg_alpha=0.1,
    reg_lambda=1.0,
    random_state=42,
    n_jobs=-1,
    verbose=-1
)
 
lgb_model.fit(X_train, y_train)
print(f"LightGBM 测试准确率: {lgb_model.score(X_test, y_test):.4f}")

5.2 EFB:互斥特征捆绑

问题: 特征维度高时,分裂点寻找成本高。

EFB 策略:

  1. 识别互斥特征(很少同时取非零值的特征)
  2. 将互斥特征捆绑为一个特征
  3. 用特征值偏移来区分不同特征

优势: 减少特征数量,加速分裂寻找。

示例:

原始特征:F1, F2, F3, F4
互斥分析:F1 和 F3 互斥,F2 和 F4 互斥
捆绑结果:
- Bundle1: {F1, F3} → 新特征 B1
- Bundle2: {F2, F4} → 新特征 B2
特征数量:4 → 2

5.3 Leaf-wise 生长策略

传统算法是 Level-wise(按层生长),LightGBM 使用 Leaf-wise(按叶生长)。

对比:

Level-wise(XGBoost):           Leaf-wise(LightGBM):
       0                                0
     /   \                            /   \
    1     2                          1     2
   / \   / \                              |
  3   4 5   6                            3
                                           |
                                           4
特性Level-wiseLeaf-wise
生长方式按层平衡生长选择增益最大的叶节点分裂
优势不容易过拟合收敛更快,精度更高
劣势有些无用分裂容易过拟合(需控制深度)
# LightGBM 使用 leaf-wise,需要限制 max_depth
lgb_leafwise = lgb.LGBMClassifier(
    n_estimators=200,
    max_depth=6,           # 必须限制深度
    num_leaves=31,         # 叶节点数限制(2^depth - 1)
    learning_rate=0.05,
    min_child_samples=20,
    boosting_type='gbdt',  # 默认就是 leaf-wise
    random_state=42,
    n_jobs=-1,
    verbose=-1
)

重要参数关系: num_leaves 应该小于 ,否则会过拟合。

5.4 LightGBM 完整示例

import lightgbm as lgb
from sklearn.metrics import roc_auc_score
 
# 创建 Dataset
train_data = lgb.Dataset(X_train, label=y_train)
valid_data = lgb.Dataset(X_test, label=y_test, reference=train_data)
 
# 参数
params = {
    'boosting_type': 'gbdt',
    'objective': 'binary',
    'metric': ['binary_logloss', 'auc'],
    'num_leaves': 31,
    'max_depth': 6,
    'learning_rate': 0.05,
    'min_child_samples': 20,
    'subsample': 0.8,
    'colsample_bytree': 0.8,
    'reg_alpha': 0.1,
    'reg_lambda': 1.0,
    'verbose': -1
}
 
# 训练(带早停)
gbm = lgb.train(
    params,
    train_data,
    num_boost_round=1000,
    valid_sets=[train_data, valid_data],
    callbacks=[
        lgb.early_stopping(stopping_rounds=50),
        lgb.log_evaluation(period=100)
    ]
)
 
# 预测
y_pred_prob = gbm.predict(X_test, num_iteration=gbm.best_iteration)
print(f"LightGBM AUC: {roc_auc_score(y_test, y_pred_prob):.4f}")

6. CatBoost 简介

CatBoost(Category Boosting)是 Yandex 推出的梯度提升框架,专注于类别特征。

6.1 核心创新

创新点说明
Ordered Boosting减少预测偏移
类别特征处理基于 Target Statistics 的编码
对称树所有树结构相同,加速预测

6.2 类别特征处理

CatBoost 可以直接处理类别特征,不需要手动 one-hot 编码。

from catboost import CatBoostClassifier, Pool
 
# 模拟带类别特征的数据
df_cat = df.copy()
df_cat['sector'] = np.random.choice(['科技', '金融', '医疗', '消费'], len(df))
df_cat['market_cap_group'] = np.random.choice(['大', '中', '小'], len(df))
 
# 定义类别特征索引
cat_features = [3, 4]  # sector, market_cap_group 的列索引
 
# 创建 Pool
train_pool = Pool(
    data=X_train,
    label=y_train,
    cat_features=cat_features
)
 
# CatBoost 训练
cat_model = CatBoostClassifier(
    iterations=200,
    depth=6,
    learning_rate=0.05,
    loss_function='Logloss',
    random_seed=42,
    verbose=False
)
 
cat_model.fit(train_pool)
print("CatBoost 自动处理类别特征!")

6.3 Ordered Boosting

问题: 传统 Boosting 使用目标统计值时会有数据泄漏。

CatBoost 方案: 使用类似 “留一法” 的策略计算目标统计值。


7. 四种模型对比

7.1 功能对比表

特性GBDTXGBoostLightGBMCatBoost
核心创新梯度提升二阶导+正则化GOSS+EFB类别特征处理
训练速度很快
预测速度很快
内存占用
精度很高很高
类别特征需手动编码需手动编码需手动编码自动处理
缺失值需处理自动处理自动处理自动处理
并行支持有限很好
适用数据规模小-中超大

7.2 选择建议

场景推荐模型理由
快速原型验证LightGBM训练快,API 简洁
竞赛刷分XGBoost精度通常最高
超大数据集LightGBM内存效率高
类别特征多CatBoost自动处理
生产部署LightGBM预测快,模型小
研究实验XGBoost文档完善,社区活跃

7.3 性能对比(模拟)

import time
from sklearn.metrics import roc_auc_score
 
models = {
    'XGBoost': XGBClassifier(
        n_estimators=200, max_depth=4, learning_rate=0.05,
        random_state=42, n_jobs=-1, eval_metric='logloss'
    ),
    'LightGBM': lgb.LGBMClassifier(
        n_estimators=200, max_depth=4, learning_rate=0.05,
        random_state=42, n_jobs=-1, verbose=-1
    ),
    'CatBoost': CatBoostClassifier(
        iterations=200, depth=4, learning_rate=0.05,
        random_seed=42, verbose=False
    )
}
 
results = []
 
for name, model in models.items():
    start_time = time.time()
    model.fit(X_train, y_train)
    train_time = time.time() - start_time
 
    start_time = time.time()
    y_pred = model.predict_proba(X_test)[:, 1]
    pred_time = time.time() - start_time
 
    auc = roc_auc_score(y_test, y_pred)
 
    results.append({
        'Model': name,
        'AUC': f"{auc:.4f}",
        'Train Time': f"{train_time:.2f}s",
        'Predict Time': f"{pred_time:.4f}s"
    })
 
results_df = pd.DataFrame(results)
print(results_df)

预期输出(类似):

      Model     AUC Train Time Predict Time
0   XGBoost  0.6834      1.23s       0.0123s
1  LightGBM  0.6812      0.45s       0.0034s
2  CatBoost  0.6798      3.56s       0.0234s

8. 为什么树模型适合量化

8.1 数据特点匹配

量化数据特点树模型优势说明
表格结构天然适合因子就是表格特征
稀疏性自动处理树模型可以处理稀疏特征
非线性关系自动捕捉树模型能发现复杂模式
特征交互自动学习不需要手动构造交互项
异常值多鲁棒性强对异常值不敏感
缺失值自动处理XGBoost/LightGBM 原生支持

8.2 实战优势

# 示例:量化因子的一些典型场景
import numpy as np
import pandas as pd
 
# 场景1:特征交互(因子A只在因子B高时有效)
np.random.seed(42)
n = 10000
 
factor_a = np.random.randn(n)
factor_b = np.random.rand(n)
 
# 只在 factor_b > 0.5 时,factor_a 才有用
returns = np.where(
    factor_b > 0.5,
    0.3 * factor_a + np.random.randn(n) * 0.5,
    np.random.randn(n) * 0.5
)
 
# 线性模型难以捕捉这种交互
from sklearn.linear_model import LinearRegression
linear = LinearRegression()
X_interaction = pd.DataFrame({'A': factor_a, 'B': factor_b})
linear.fit(X_interaction, returns)
print(f"线性模型 R²: {linear.score(X_interaction, returns):.4f}")
 
# 树模型自动学习交互
from sklearn.tree import DecisionTreeRegressor
tree = DecisionTreeRegressor(max_depth=3)
tree.fit(X_interaction, returns)
print(f"树模型 R²: {tree.score(X_interaction, returns):.4f}")

8.3 量化特定优势

1. 自动分组和选股

树模型可以自动学习因子阈值,不需要手动划分:

传统方法:
if momentum > 0.5 and volatility < 0.3:
    score = 1
elif momentum > 0.3:
    score = 0.5
else:
    score = 0

树模型:自动学习最佳分裂点

2. 处理离散特征

行业、板块等离散特征可以直接使用。

3. 稳定性好

相比神经网络,树模型对数据变化更稳健。


核心知识点总结

决策树核心

  1. 分裂准则:信息增益、基尼系数
  2. 剪枝策略:预剪枝(限制复杂度)、后剪枝(修剪)
  3. 单树问题:高方差、容易过拟合

集成学习

  1. Bagging:并行训练,降低方差(随机森林)
  2. Boosting:串行训练,降低偏差和方差(GBDT)

GBDT 核心

  1. 前向分步
  2. 负梯度拟合:用损失函数的梯度作为残差
  3. 学习率:控制收敛速度和过拟合

XGBoost 创新

  1. 二阶泰勒展开:更准确的梯度近似
  2. 正则化:显式惩罚复杂度
  3. 列采样:随机森林式的特征采样

LightGBM 创新

  1. GOSS:基于梯度的采样
  2. EFB:互斥特征捆绑
  3. Leaf-wise:按叶生长,更快收敛

模型选择

场景推荐模型
通用/竞赛XGBoost
大数据/生产LightGBM
类别特征多CatBoost

下一节: 02-时序数据划分.md - 学习如何正确划分量化数据的训练集和测试集。