LightGBM 量化实战篇(上):金融数据特性、截面处理与保守调参
前六篇文章聚焦于 LightGBM 的算法本身——树的分裂机制、GBDT 的残差拟合框架、XGBoost 引入二阶导数的意义,以及 LightGBM 通过 Histogram 和 Leaf-wise 策略实现的效率提升。那些内容属于算法原理的范畴。
但当 LightGBM 被部署到真实的股票市场中时,算法本身的精巧并不能保证结果的可靠。数据是否被正确地喂入模型、标签如何定义、回测切分如何避免未来信息泄露、模型表现异常时如何诊断——这些问题在 Kaggle 等标准竞赛中鲜少遇到,但在量化投资中却是决定成败的关键环节。
本系列共三篇,围绕一个核心问题展开:如何在量化场景中正确地使用 LightGBM。第一篇讨论金融数据的特殊性质、截面预处理方法和保守的超参数调优策略——这些是模型训练之前必须解决的输入端问题。
一、金融数据与普通机器学习数据的差异
有过机器学习实践经验的读者或许熟悉这样的工作流:在猫狗图片分类、房价预测等任务中,完成特征工程、选择合适的模型、调优超参数,性能指标通常就能稳步提升。然而,将同样的流程移植到股票市场中,往往会出现一种令人困惑的现象——回测阶段表现优异,实盘阶段却大幅失效。
这一落差的根源并不在于 LightGBM 算法本身,而在于金融数据区别于一般机器学习数据的特殊性质。
1. 信噪比极低
在图像分类任务中,猫的视觉特征是稳定且可辨识的;房价与面积之间的关系也具有较好的统计稳定性。但股票收益率的构成远为复杂——宏观消息、资金流向、散户情绪、政策变动、短期流动性冲击、纯粹的随机波动交织在一起。其中真正具有预测价值的成分,仅占收益率总体波动的很小一部分。信号微弱而噪声强大,这是金融数据最本质的特征。
因此,量化建模的评估标准不应聚焦于模型在历史数据上的拟合精度,而应关注其在未见数据上的预测稳定性。
2. 分布不稳定(概念漂移)
图像分类的决策边界不会因为日历翻页而改变,但金融市场的运行规律始终处于动态漂移之中。小市值风格可能在今年有效而明年失效;动量策略可能连续三年盈利,随后进入长达一年半的回撤期;某个量价规律一旦被市场参与者广泛识别,拥挤交易效应便会迅速侵蚀其超额收益。
这就是所谓的 Concept Drift(概念漂移)。金融市场中的规律并非物理定律,它是参与者博弈的产物。当参与者的结构和行为模式发生变化时,原本有效的规律也会随之改变。
因此,量化模型的设计应当趋于保守。对于那些缺乏坚实经济学解释、仅在特定时段表现出统计显著性的规律,应当审慎对待。模型应当优先捕捉那些更为普适、更经得起时间检验的模式。
3. 排序比绝对值重要
在量化选股场景中,模型并不需要精确预测某只股票明天的涨幅是 2.1% 还是 2.3%。假设市场中有 5000 只股票,投资组合最终可能只持有排名前 100 只。模型的核心价值在于能否准确地将这 100 只股票从全部标的中识别出来——具体的绝对收益预测值并非关键,排序的正确性才是核心。
这一认知对后续目标函数的选择具有直接的指导意义。
二、截面处理:量化数据预处理的灵魂
在标准机器学习流程中,特征工程的常规做法是对整个数据集进行统一的标准化处理——对所有样本减去均值、除以标准差。然而,股票数据的结构决定了这种方法并不适用。
股票数据本质上是面板数据(Panel Data):横轴为某一天的全部上市股票,纵轴为时间序列。在任意一个交易日,所有股票的数据集合构成一个截面(Cross-Section)。许多量化因子在绝对数值层面的含义并不稳定,真正具有信息量的是截面内的相对位置。
1. 为什么绝对数值靠不住?
以市盈率(PE)为例。假设有两只股票,A 的 PE 为 15,B 的 PE 为 100。表面上看 A 似乎更便宜,但实际情况远比这复杂。牛市中流动性充裕,市场整体估值中枢上移,PE=100 并不罕见;熊市中估值中枢下移,PE=15 也未必代表低估。此外,不同行业天然具有不同的合理估值区间——同一年内,电子行业与银行行业的 PE 量级差异极大。如果直接将绝对数值输入模型,模型很容易学到表面化的规律,例如"某年 PE 低的股票表现好",并将低 PE 泛化为一条通用规则。然而,当宏观环境切换后,这类规律往往会迅速失效。
因此,截面处理的核心原则可以概括为:不要让模型学习"PE 等于多少",而是让它理解"在同一天的所有股票中,这只股票处于什么相对位置"。
2. 去极值:先处理异常值
金融因子数据中频繁出现极端值是常态。公司利润骤然转负、停牌股票复牌后波动剧烈、小市值标的因成交量极低导致量价因子失真——这些情况在实际数据中屡见不鲜。虽然 LightGBM 相较于线性模型对异常值具有更强的鲁棒性,但极端值仍可能干扰分裂阈值的选择,因此去极值处理仍然必要。
方法一:3σ 原则
对某天截面内的因子值 $x_{i,t}$($i$ 是股票,$t$ 是日期),先算均值 $\mu_t$ 和标准差 $\sigma_t$,然后把所有值裁剪到 $[\mu_t - 3\sigma_t,\ \mu_t + 3\sigma_t]$ 范围内。超过上界截到上界,低于下界截到下界。简单直白,但均值和标准差本身就被极端值污染了,所以效果有限。
方法二:MAD 去极值
更为稳健的做法是采用中位数代替均值,以绝对中位差(MAD, Median Absolute Deviation)代替标准差。
截面因子值的中位数:
$$m_t = \text{median}(x_{1,t}, x_{2,t}, …, x_{N_t,t})$$
绝对中位差:
$$MAD_t = \text{median}(|x_{i,t} - m_t|)$$
乘以 1.4826 使其尺度接近标准差:
$$\sigma_{MAD,t} = 1.4826 \times MAD_t$$
上下界设为 $m_t \pm k \sigma_{MAD,t}$,$k$ 常取 3 或 5。中位数具有天然的抗干扰特性——少数极端值对其影响极为有限。因此,基于 MAD 的去极值方法在面对厚尾分布时,表现远优于基于普通标准差的方法。
3. 截面标准化:Z-score
完成去极值处理后,下一步是在每个交易日的截面内进行 Z-score 标准化:
$$z_{i,t} = \frac{x_{i,t} - \mu_t}{\sigma_t}$$
其中 $x_{i,t}$ 是经过异常值处理的因子值,$\mu_t$ 和 $\sigma_t$ 分别是当日截面的均值和标准差。处理后,因子在每个交易日近似满足零均值、单位方差的分布。模型的输入从"这只股票的 PE 是多少"转变为"它在当日所有股票中处于什么水平"。
不过,实战中还有一种更为简洁且更为稳健的处理方式——横截面 Rank。
4. 横截面 Rank:量化中最常用的处理方式
Rank 的实现方式直观明了:在每个交易日,将所有股票按某因子值从小到大排序,并映射为标准化的排名值。常见形式为:
$$r_{i,t} = \frac{\text{rank}(x_{i,t}) - 1}{N_t - 1}$$
其中 $N_t$ 是当日股票数量。经过这一变换,因子值被压缩至 $[0, 1]$ 区间(也可进一步平移至 $[-0.5, 0.5]$)。
Rank 具有多方面的优势:完全消除绝对数值的影响、对异常值具有极强的鲁棒性、不受宏观经济环境变化的干扰、对因子分布的形态不敏感,且天然契合量化选股"比较相对强弱"的逻辑。以动量因子为例:牛市中所有股票普遍上涨,熊市中则普遍下跌,若使用绝对收益率作为因子值,模型会被市场整体涨跌所干扰。转换为 Rank 后,模型关注的是"这只股票在当日是否强于大多数股票",市场系统性涨跌的影响被大幅削弱。
对于 LightGBM 这类树模型而言,Rank 同样非常友好。树的分裂本质上是按阈值对排序进行切割,Rank 保留了完整的相对顺序信息,同时将极端值和不稳定的分布形态有效压缩。
5. 行业中性化和市值中性化
Rank 能够解决大部分截面标准化的问题,但如果目标是获取更纯净的 Alpha 信号,通常还需进一步进行风格中性化处理。部分因子天然具有小市值偏好或行业偏向,若不加处理,模型看似在选股,实则在赌某个风格因子的暴露。中性化的做法是:在截面上对行业哑变量和对数市值进行回归,取残差作为中性化后的因子值:
$$x_{i,t}^{neutral} = x_{i,t} - \hat{\beta}{size,t} \times \log(MktCap{i,t}) - \hat{\beta}{industry,t} \times Industry{i,t}$$
先进行 Rank 再进行中性化,或先中性化再 Rank,两种顺序均可,取决于具体的策略设计。
对于初学者而言,优先掌握截面去极值、Z-score 标准化和 Rank 变换即可。待整体框架稳定后,再逐步引入行业、市值、风格等维度的中性化处理。
三、保守调参:量化中的生存法则
在 Kaggle 等数据竞赛中,参赛者往往倾向于将树深度设为 10 层甚至不限深度、学习率设置的极低、并大量引入特征交叉。这种激进的调参策略在竞赛场景中可能有效,但直接移植到量化投资中往往适得其反。
一个自然的疑问是:为什么竞赛中可以使用的深树策略,在量化场景中却不适用?
1. 比赛和实盘是两码事
Kaggle 的数据是静态的——训练集和测试集均固定不变,参赛者的目标是在给定的测试集上最大化评分。即便模型过拟合了一部分噪声,只要测试集中存在类似的噪声模式,分数依然能够提升。在这种设定下,为了 0.001 的指标改善而增加模型复杂度,是完全合理的。
量化实盘的环境截然不同。市场的"测试集"是持续生成的,今天有效的规律明天可能就不再成立。量化投资追求的并非某次回测中的极限分数,而是长期的生存能力——低回撤、稳定复利、可持续性。简而言之,Kaggle 是一次性考试,量化是长期经营。因此,量化场景中的调参策略必须显著趋于保守。
2. max_depth 与 num_leaves:控制模型复杂度
LightGBM 默认采用 Leaf-wise 生长策略,每次选择增益最大的叶子节点进行分裂,效率很高但容易导致树过深。在量化场景中,必须通过参数设置主动加以限制。
| 参数 | 普通机器学习 | 量化中更常见的保守范围 |
|---|---|---|
max_depth |
8、10 甚至不限 | 3~6 |
num_leaves |
63、127、255 | 7~63 |
min_data_in_leaf |
10~30 | 100~1000 |
这里需要特别说明的是,num_leaves 对树复杂度的控制比 max_depth 更为直接。例如,max_depth=4, num_leaves=15 与 max_depth=6, num_leaves=63 之间的复杂度差异是显著的。
金融市场中真正有效的非线性交互往往并不复杂:低估值叠加强动量、低波动叠加热钱流入、小市值标的具备足够流动性、高动量伴随换手率未出现异常。这些模式通常通过两三层交互即可表达。树过深反而容易将特定日期、特定股票、特定行情下的偶然现象记忆下来——这属于过拟合,而非真正的预测能力。
3. min_data_in_leaf:让规律有代表性
min_data_in_leaf(亦称 min_child_samples)控制每个叶子节点所需的最少样本数量。若该值设置过小(如 10 或 20),模型可能学到"某天恰好有 30 只股票满足某条件且表现良好"这类过度特异化的规则,而这些规则大概率是偶然现象的反映。将该值提高至 200、500 甚至更高,可以迫使模型寻找覆盖面更广的规律,避免为少数几只股票生成专属的叶子节点。
当然,该值也不宜设置过大,否则会导致欠拟合。经验性的参考范围如下:样本量仅数万条时设为 50~200,数十万至数百万条时设为 200~1000,日频全市场选股场景下 500 左右是一个较为稳健的起点。
4. 学习率与树数量:小步慢走
在一般机器学习任务中,学习率通常从 0.1 起步,配合几百棵树即可。量化场景中的参数设置则有所不同:
|
|
采用较小的学习率配合较多的树数量,其背后的逻辑并不复杂:金融数据噪声含量高,若每棵树的步长过大,模型很容易将某段历史时期的偶然波动误认为稳定规律。通过降低单棵树的影响幅度,整体预测曲线会更加平滑。在 LightGBM 中,学习率也被称为 shrinkage(收缩系数),其作用是对每棵树的预测输出进行缩放:
$$F_m(x) = F_{m-1}(x) + \eta h_m(x)$$
其中 $F_m(x)$ 是第 $m$ 轮迭代后的累积预测值,$h_m(x)$ 是第 $m$ 棵树的输出,$\eta$ 是学习率。当 $\eta$ 较小时,单棵树的影响被有效抑制,模型的整体稳定性随之提升。
需要特别注意的是:early stopping 所使用的验证集必须选取时间上靠后的数据,不能通过随机打乱来划分。随机划分仍然会导致未来信息泄露。
5. 小学习率会不会陷入局部最优?
这个问题值得深入讨论。在神经网络的训练中,局部最优确实是一个需要关注的问题,因此才引入了动量、学习率调度、模拟退火等优化策略。但对于树模型,情况有所不同。对于 GBDT、XGBoost、LightGBM 这类梯度提升树,在树结构确定的前提下,叶子节点输出值的优化是一个凸优化问题。
以第 $m$ 棵树为例,目标函数近似为:
$$\mathcal{L}^{(m)} = \sum_i \left[ g_i f_m(x_i) + \frac{1}{2} h_i f_m^2(x_i) \right] + \Omega(f_m)$$
其中 $g_i$ 为一阶导数,$h_i$ 为二阶导数,$f_m(x_i)$ 为第 $m$ 棵树对样本 $i$ 的输出,$\Omega(f_m)$ 为正则项。当树结构固定后,每个样本所属的叶子节点已经确定。记叶子 $j$ 内所有样本的一阶导数之和为 $G_j = \sum_{i \in j} g_i$,二阶导数之和为 $H_j = \sum_{i \in j} h_i$。引入 L2 正则化后,叶子节点的最优权重具有唯一解析解:
$$w_j^* = -\frac{G_j}{H_j + \lambda}$$
与神经网络中可能存在的大量局部极值点不同,梯度提升树的叶子权重优化不存在这类问题。当然,整棵梯度提升树的构建过程是贪心的,并非全局最优,但上述分析至少说明:较小的学习率并非为了"跳出局部最优",而是为了通过降低单棵树的影响幅度来增强模型的稳定性。
在量化实践中,真正需要关注的风险并非局部最优,而是树深度过大、叶子样本数不足、特征维度过多、训练区间包含未来信息、验证方式不当以及过度优化回测指标等问题。
6. 随机性:样本采样与特征采样
为了避免模型过度依赖少数强因子或少数特殊样本,LightGBM 提供了采样机制:
|
|
其中 bagging_fraction 控制每棵树使用的样本比例,feature_fraction 控制每棵树使用的特征比例,bagging_freq 指定每隔多少轮进行一次 bagging 采样。上述设置意味着每棵树仅使用约 80% 的样本和 80% 的特征进行训练。其优势在于:降低模型对个别样本和个别强因子的依赖,增加树与树之间的多样性,从而有效降低过拟合风险。
特征采样在量化场景中尤为重要。因子之间往往存在高度相关性,若每棵树都能观测到全部因子,模型容易反复围绕少数因子进行分裂,最终导致过拟合。
7. 一组保守的量化风格参数示例
以下是一组保守的量化风格参数示例,仅供参考,不应视为标准答案:
|
|
如果使用回归目标,也可以把目标函数改成:
|
|
但在量化选股中,排序目标往往更贴近实际投资需求。排序目标的具体原理和使用方法将在本系列第二篇中详细讨论。
小结
本文讨论了量化 LightGBM 实践中的三个基础环节:理解金融数据的特殊性质、掌握截面预处理方法、采用保守的超参数调优策略。
核心要点回顾:金融数据信噪比低、分布不稳定,模型设计应趋于保守;截面处理的核心是将绝对数值转化为相对位置,Rank 是最简洁有效的选择;调参应控制树深度、提高叶子样本数、降低学习率,让模型学习普适规律而非记忆噪声。
数据和参数准备就绪后,下一步需要解决的问题是:目标函数如何选择(回归还是排序)、选股得到的相对强弱如何转化为实际收益、以及如何通过严格的交叉验证确保模型没有偷看未来。这些内容将在本系列第二篇中展开。
下一篇预告:【量化】从零到LGBM | 8 | LGBM的金融应用(中):排序学习、对冲与交叉验证——讨论 LambdaRank 目标函数、NDCG 指标、Beta 与 Alpha 的分离,以及 Purged K-Fold 交叉验证方法。