第 9 章 · 02 随机森林调参与日本股票多空


文档摘要

第 9 章 · 02 随机森林调参与日本股票多空 本节摘要:本节把上一节的 Bagging 升级成随机森林,并落到一个完整的多空策略——日本大盘股。随机森林在 Bagging 的「样本随机」之上再加「特征随机」:每个分裂点只考虑部分特征,强制让不同的树走不同的切分路径,把树与树的相关性压下来,方差随之进一步下降。本节讲清四件事:随机森林相对 Bagging 的增量价值与 OOB(袋外)评估;如何在 Quandl 美股数据上用 + 调参;如何用 Stooq 日本股票数据做特征工程(动量、波动、TA-Lib 指标);以及如何用 LightGBM 生成多空信号,用 Zipline 回测一个市场中性策略,并用 Alphalens 看信号质量。

第 9 章 · 02 随机森林调参与日本股票多空

本节摘要:本节把上一节的 Bagging 升级成随机森林,并落到一个完整的多空策略——日本大盘股。随机森林在 Bagging 的「样本随机」之上再加「特征随机」:每个分裂点只考虑部分特征,强制让不同的树走不同的切分路径,把树与树的相关性压下来,方差随之进一步下降。本节讲清四件事:随机森林相对 Bagging 的增量价值与 OOB(袋外)评估;如何在 Quandl 美股数据上用 GridSearchCV + MultipleTimeSeriesCV 调参;如何用 Stooq 日本股票数据做特征工程(动量、波动、TA-Lib 指标);以及如何用 LightGBM 生成多空信号,用 Zipline 回测一个市场中性策略,并用 Alphalens 看信号质量。读完本节,你能跑通一个从特征工程到绩效报告的非线性多空策略。

内容来源:原项目 11_decision_trees_random_forests/03_random_forest_tuning.ipynb04_japanese_equity_features.ipynb05_random_forest_return_signals.ipynb06_alphalens_signals_quality.ipynb07_backtesting_with_zipline.ipynb,汉化并套用体系化模板。

⚠️ 学习提示:树模型易过拟合,样本外 IC 与夏普普遍衰减。这里的多空回测仅作流程示范,直接照搬到实盘几乎一定亏损。

学习目标

阅读完本节,你应当能够:

  1. 解释随机森林在 Bagging 基础上的「特征随机化」增量。
  2. OOB error 做不依赖额外验证集的模型评估。
  3. GridSearchCV + 时序 CV 搜索随机森林超参。
  4. 用 TA-Lib + 滞后收益为日本股票构造特征集
  5. LightGBM 生成多空信号,并接入 Zipline 回测与 Alphalens 评估。

一、随机森林:Bagging + 特征随机

随机森林在 Bagging 的两处随机化之上,再加第三处:

随机化来源 Bagging 随机森林
行抽样(bootstrap)
树之间独立性 部分 强制
每个分裂点特征随机

具体做法:在每个节点分裂时,只从全部 p 个特征里随机选 m(m \ll p,典型 m = \sqrt{p}),只在这 m 个里找最优切分。这强制让「最强特征」不会出现在每棵树的每个分裂点——不同的树被迫用不同的次强特征,树与树的相关性显著下降。

💡 核心心法:随机森林的关键不在「训更多树」,而在「让树各想各的」。如果所有树都在同一个最强特征上做同一个切分,再平均也没用——降不了多少方差。特征随机化就是打破这种「思维趋同」。

OOB:免费的内嵌验证

bootstrap 抽样有放回,每棵树大约 37% 的训练样本没被抽中——这些叫「袋外(OOB)样本」。对每棵树,用它没见过的 OOB 样本评估它,再把所有树的 OOB 评估聚合,就得到一个不依赖额外验证集的泛化估计。这是随机森林相对普通 Bagging 的额外红利,尤其样本稀缺时极其有用。

二、在美股数据上调参

notebook 03_random_forest_tuning.ipynb 用 Quandl 月度数据:

with pd.HDFStore('data.h5') as store: data = store['us/equities/monthly'] y = data.target y_binary = (y > 0).astype(int) X = pd.get_dummies(data.drop('target', axis=1))

随后用 GridSearchCV 配合自定义的 MultipleTimeSeriesCV(时序交叉验证)搜索 n_estimatorsmax_depthmax_features 等关键超参:

from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import GridSearchCV rf = RandomForestRegressor(random_state=42, n_jobs=-1, oob_score=True) param_grid = {'n_estimators': [50, 100, 250], 'max_depth': [None, 10, 20], 'max_features': ['sqrt', 'log2', None]} grid = GridSearchCV(rf, param_grid, cv=mts_cv, scoring=ic_scorer)
超参 调参方向
n_estimators 越多越稳,边际收益递减,通常 100~500 够用
max_features 越小越随机,降方差但提偏差,sqrt 是经典默认
max_depth 限制深度可抗过拟合,但太浅又欠拟合
min_samples_leaf 调大可抗过拟合
oob_score 开启,获取免费泛化估计

⚠️ 时序 CV 必须:金融数据有强时间结构,普通 K-fold 会把未来泄漏到训练集。MultipleTimeSeriesCV 保证训练段永远在测试段之前,且 purge 掉标签重叠的样本——这是评估金融模型不可省的一步。

三、日本股票特征工程

notebook 04_japanese_equity_features.ipynb 用 Stooq 提供的日本东证股票数据(2010-2019):

prices = (pd.read_hdf(DATA_DIR / 'assets.h5', 'stooq/jp/tse/stocks/prices') .loc[idx[:, '2010': '2019'], :])

特征工程围绕「动量 + 波动 + 技术指标」三类:

  • 滞后收益:return_1mreturn_3mreturn_6mreturn_12m(经典动量)。
  • 波动率:历史收益的标准差,衡量风险。
  • TA-Lib 指标:RSI、MACD、ATR、随机指标等。
  • 横截面排名:rank(axis=1) 把绝对值转成横截面位次,消除规模差异。

构造好后保存为 model_data,供后续建模直接读取。

💡 为什么强调横截面 rank:日本股票之间规模差异大(丰田和小盘股市值差几十倍),用绝对收益做特征会让大票主导模型。rank 把所有票拉到「1 到 N」的同尺度,这是多空选股的标准预处理。

四、用 LightGBM 生成多空信号

虽然章节名是「随机森林」,但 notebook 05_random_forest_return_signals.ipynb 实际用 LightGBM(下一章详讲)做收益预测——它能高效处理类别特征,逻辑与 sklearn 的随机森林高度相似。流程:

  1. 读取 model_data,划分特征与多个前瞻标签(1/5/21 日)。
  2. MultipleTimeSeriesCV 滚动训练,记录每个 fold 的 IC(Spearman 秩相关)。
  3. 把所有 fold 的样本外预测汇总,作为信号。
import lightgbm as lgb from scipy.stats import spearmanr # 每折训练后,在测试段算 IC ic = spearmanr(y_test, y_pred).correlation

Alphalens 看信号质量

notebook 06_alphalens_signals_quality.ipynb 用 Alphalens 出信号分组的收益分布、信息系数衰减、换手率等标准 tearsheet:

from alphalens.utils import get_clean_factor_and_forward_returns from alphalens.tears import create_full_tear_sheet factor_data = get_clean_factor_and_forward_returns(factor, prices) create_full_tear_sheet(factor_data)

这能在跑 Zipline 回测之前,先从「信号有没有分组单调性」「IC 在哪些前瞻期最强」「换手是否过高」几个维度筛掉低质信号——比直接看回测夏普更早暴露问题。

五、Zipline 回测市场中性多空

notebook 07_backtesting_with_zipline.ipynb 把信号接进 Zipline,做多预测最高的若干只、做空最低的若干只,目标是市场中性:

from zipline import run_algorithm from zipline.api import (attach_pipeline, pipeline_output, schedule_function, date_rules, time_rules, order_target_percent) def initialize(context): attach_pipeline(make_pipeline(), 'signals') def rebalance(context, data): signals = pipeline_output('signals') longs = signals[signals.long_short > 0].index # 等权分配,做多 longs,做空 shorts for stock in longs: order_target_percent(stock, target_weight)

最终用 run_algorithm() 跑完整个回测期,输出 pyfolio 绩效。整套流程串起第 8 章学到的回测基础设施,加上本章的非线性信号——这就是 ML4T 端到端工作流的一次完整落地。

⚠️ 回测衰减是常态:你大概率会看到样本外夏普明显低于样本内,这是树模型在金融数据上的典型表现——信号弱、噪声大、易过拟合。把这次回测当作「流程练习」,而非「可上线策略」。

本节要点回顾

  1. 随机森林 = Bagging + 特征随机:每个分裂点只用 m 个随机特征,强制树之间去相关,进一步降方差。
  2. OOB 评估:bootstrap 漏掉的 37% 样本是「免费验证集」,小样本时尤其珍贵。
  3. 时序调参:GridSearchCV + MultipleTimeSeriesCV,严禁普通 K-fold,会泄漏未来。
  4. 日本股票特征:动量、波动、TA-Lib 指标、横截面 rank,rank 消除规模差异是多空选股标准操作。
  5. LightGBM 信号:在多折滚动训练里收集样本外预测,用 Spearman IC 评估。
  6. Alphalens + Zipline:先 Alphalens 看信号质量(分组单调性、IC 衰减、换手),再 Zipline 跑端到端多空回测。

下一节,我们看 GBM 基线——从 AdaBoost 到梯度提升,理解「串行拟合负梯度」的另一类集成思路。


发布者: 作者: 灏天文库 转发
评论区 (0)
U