第 24 课 机器学习究竟在量化里做什么¶
机器学习并不是一台自动赚钱的机器。它更像一位从旧题中学习评分规则的助手。本课先弄清问题、数据和考试方式,再决定是否需要更复杂的模型。
一张人手评分表为什么会遇到困难¶
假设你每周五都要从甲、乙、丙、丁四只虚构股票中选择一只。最初的规则很直接,过去二十日涨幅越高越好,过去六十日波动越低越好。你把两个指标各排一次名,再把名次相加,分数最高的股票进入下周观察名单。
这个规则有一个很大的优点。每一步都能解释,算错时也容易发现。然而研究继续以后,你可能注意到同样的二十日涨幅在不同条件下含义不同。成交活跃、波动较低时,上涨趋势也许更容易延续;经历剧烈跳空以后,同样的涨幅却可能只是一次事件冲击。若再加入估值、盈利质量、行业强弱和市场状态,人手规定每个权重与所有组合条件会变得越来越困难。
机器学习适合从这里登场。它接收许多历史样本,比较当时已经知道的线索与后来发生的结果,再估计一套把线索转换成预测的规则。这里的“学习”不含神秘成分。线性模型在调整一组系数,树模型在寻找一组分叉条件,神经网络则在调整更多层的连接权重。无论名字多么复杂,它们都在做同一件基础工作,让历史预测与历史答案之间的差异逐渐变小。
先看一张小表。前三个数字在周五收盘后已经知道,最后一个数字要等未来五个交易日走完才知道。
| 股票 | 过去二十日收益 | 过去六十日波动 | 成交活跃度 | 后来五日收益 |
|---|---|---|---|---|
| 甲 | 8% | 18% | 高 | 2.0% |
| 乙 | 3% | 12% | 中 | 0.5% |
| 丙 | -2% | 30% | 低 | -1.5% |
| 丁 | 6% | 15% | 高 | 1.2% |
在机器学习语言里,前三列叫特征,它们是作出预测时已经能够观察的线索。最后一列叫标签,它是后来才发生、用来批改旧预测的答案。表格中的每一行叫一个样本。模型在较早年份中同时看特征与标签,学习完成以后,面对新的周五只能看特征,未来答案必须被遮住。

训练使用的是已经走完的历史。真正预测某个新日期时,模型只能拿到左侧线索,右侧答案仍在未来。
机器学习只替换了量化流程中的一小段¶
经典均线策略由研究者直接规定信号,机器学习策略则让模型估计“特征怎样变成分数”。它没有替代数据清洗、成交模拟、费用、风险控制和样本外检验。若原始价格错了一位小数,或者回测按信号产生以前的价格成交,再先进的模型也只会把错误包装得更复杂。
flowchart LR
accTitle: 机器学习在量化流程中的位置
accDescr: 历史数据形成特征和标签,机器学习只负责从特征估计预测分数,分数还需经过组合、成交和风险检查
a[历史行情与公告<br/>确认当时是否可见] --> b[制作特征<br/>描述已知线索]
a --> c[制作标签<br/>描述后来结果]
b --> d[训练模型<br/>学习特征到分数]
c --> d
d --> e[新日期打分<br/>此时看不到答案]
e --> f[选股票与定仓位]
f --> g[模拟成交、费用<br/>风险与复盘]
这条流程也说明了一个重要次序。研究者应先确定要作出什么决策,再定义能够代表这个决策结果的标签;随后检查特征在预测时是否可见;最后才选择模型。若一开始就决定使用某个流行模型,之后再勉强寻找可以喂给它的数据,研究问题很容易被工具带偏。
先把“预测未来”改写成可以批改的问题¶
“我想预测股票”无法直接交给模型,因为它没有说明预测什么、从什么时候开始,又用什么标准判断对错。一个可以研究的问题至少要写出预测对象、预测时点、未来范围和最终用途。
继续使用周五的例子。研究者可以问“根据周五收盘时已知的数据,预测四只股票从下周一开盘买入后五个交易日的收益率”。这个问题把信号形成时点、真实可成交时点和持有期限都写清楚了。模型输出一个连续数字,预测 0.02 表示模型估计收益约为 2%,并不保证结果一定为正。
同一批数据也可以提出另外两个问题。若标签只记录未来收益是否大于零,模型学习的是上涨概率,这叫分类任务。若标签记录每只股票的未来收益在同一天所有候选股票中的名次,模型学习的是相对强弱,这叫排序任务。连续收益保留幅度,方向任务把结果压成类别。排名任务只留下相对次序,三种任务因此服务于不同决策。
| 学习任务 | 模型要回答什么 | 适合的决策 | 会丢掉什么信息 |
|---|---|---|---|
| 收益预测 | 未来收益可能是多少 | 估计幅度和风险收益 | 对极端值比较敏感 |
| 方向分类 | 上涨概率有多大 | 达到概率门槛后交易 | 看不出涨跌幅度 |
| 截面排序 | 同日候选中谁更强 | 选择前若干只股票 | 不保证第一名绝对上涨 |
标签必须从实际可能成交的时点开始。周五收盘后才算出的信号,无法倒回周五收盘价买入。若策略约定下周一开盘成交,周五收盘到周一开盘的价格变化就不属于这条信号能获得的收益。第 25 课会用具体价格把标签从手算推到公式和代码。
特征为什么需要有来路¶
特征并不是越多越好。每增加一个字段,模型就多一种解释历史的自由,也多一次偶然碰中噪声的机会。二十日收益与二十一日收益高度相似,把两者同时放入模型未必增加新的信息;财务指标如果错误使用报告期而不是公告日,还会把未来信息带进过去。
初学者可以先用一张特征卡约束自己。卡片要写明这条特征试图表达什么、使用哪些原始字段、何时才能完整,以及最可能出现哪种错误。填写卡片会增加前期工作,也会省下大量排查时间。
| 特征 | 想表达的市场现象 | 最早可见时间 | 主要风险 |
|---|---|---|---|
| 二十日收益 | 一段时间内的价格方向 | 当日收盘以后 | 窗口方向写反 |
| 六十日波动 | 近期价格是否稳定 | 当日收盘以后 | 极端行情估计滞后 |
| 成交活跃度 | 信号是否可能成交 | 当日成交数据完整以后 | 单位和异常成交 |
| 盈利质量 | 公司经营是否稳健 | 财报真正公告以后 | 用报告期代替公告时间 |
第一个模型最好只使用少量、含义不同的特征。之后每增加一组特征,都与原来的简单版本使用同一批日期、股票和交易规则比较。若模型分数略有改善,换手和成本却大幅增加,这组新特征可能没有带来可交易价值。
模型究竟怎样从旧题里学习¶
假设模型先看 2019 年到 2022 年的历史样本。它根据每行特征给出一个预测,再把预测和已经发生的标签比较。衡量两者差异的计算规则叫损失函数。预测偏离答案越远,损失通常越大。训练程序反复调整模型参数,希望让训练样本的平均损失下降。
线性模型可以想成一张自动调整权重的评分表。若历史中高动量经常对应较高未来收益,动量前面的系数可能变为正;若高波动经常对应较差结果,波动系数可能变为负。树模型不要求关系是一条直线,它可以学习“动量较高并且波动较低时给高分”这样的组合条件。神经网络拥有更多层和参数,可以表达更复杂的关系,也更容易记住训练历史中的偶然细节。
训练损失持续下降,只能说明模型越来越适应已经见过的旧题。它可能学到了能够延续的规律,也可能记住了某些年份、某几只股票甚至数据错误。为了分清这两种情况,机器学习必须把历史按时间分成不同用途。
训练、验证和测试为什么不能混在一起¶
训练集用来调整模型参数,类似带答案的练习册。验证集用来比较少量模型设置并决定何时停止训练,类似模拟考试。测试集只在研究方案基本确定以后使用,类似最后一次正式考试。量化数据还必须保持时间先后,不能把未来日期随机塞进训练集。
假设有六年数据,可以先这样安排。
| 时间 | 用途 | 可以做什么 |
|---|---|---|
| 2019 至 2022 年 | 训练 | 学习模型参数和数据处理规则 |
| 2023 年 | 验证 | 比较有限设置、决定是否早停 |
| 2024 年 | 测试 | 检查一次真正未参与选择的结果 |
| 2025 年 | 向前滚动 | 带着过去规则继续模拟未来研究 |
每次训练还要等待标签完整。若预测目标覆盖未来五个交易日,2023 年最后几行样本的答案可能延伸到 2024 年。预测 2024 年初时,这些答案在现实中尚未全部发生,不能参加训练。第 17 课介绍的时间切分在这里继续有效,机器学习不会因为使用了新模型就获得豁免。
标准化也会从数据中学习平均值和波动范围,所以它只能在训练集计算。下面的代码在数学上只做一件事,先从训练特征学习转换规则,再把同一规则应用到验证和测试。阅读之前应先认识两个动作,fit 表示学习规则,transform 表示使用已经学好的规则。
scaler.fit(train_features)
train_scaled = scaler.transform(train_features)
valid_scaled = scaler.transform(valid_features)
test_scaled = scaler.transform(test_features)
如果先把六年数据合在一起执行 fit,模型会提前知道未来几年特征的平均值、波动和极端范围。这种信息不会直接出现在某一列里,却仍然改变了过去数据的处理方式,属于数据泄漏。
从模型分数到实际持仓还有一段路¶
模型给一只股票输出 0.72,不能直接理解成“上涨 72%”,也不能直接买入 72% 仓位。这个数字的含义由训练任务决定。分类模型的 0.72 可能表示估计上涨概率,排序模型的 0.72 可能只是同日相对分数,回归模型的 0.72 还可能因为标签单位不同而代表完全不同的量级。
截面选股常把同一天的预测分数从低到高排序,再选择最靠前的一部分股票。假设每天选择前 20%,并在入选股票之间等分资金,过程可以先用自然语言写成三步。第一步在每个日期内部排名,第二步标出排名不低于 80% 的股票,第三步用入选数量把资金等分。
下面三行代码正好对应这三步。它把已经说明的自然语言规则写成不会含糊的操作,读者只需逐行核对含义,无需背诵。
rank = prediction.groupby("date").rank(pct=True)
selected = rank >= 0.80
weight = selected / selected.groupby("date").transform("sum")
组合还要处理单只股票上限、行业集中、停牌、流动性和换手。预测分数每天稍微变化,排名就可能反复交换,交易次数因此增加。模型在统计上更准确,却可能因为价差、手续费和冲击成本而在策略层失去价值。

图中蓝色区域是预测时已经完成的工作,金色区域表示仍需等待的未来答案,绿色区域则是模型输出以后必须完成的组合与成交检查。
准确率高为什么仍然可能亏损¶
假设一个方向模型预测十次,其中六次正确,准确率为 60%。如果每次猜对只赚 0.2%,每次猜错却亏 1%,六次盈利合计 1.2%,四次亏损合计 4%,结果仍然是负数。准确率只计算对错次数,没有考虑每次盈亏的大小,也没有考虑交易成本。
模型评估因此分为两层。第一层检查预测本身,例如预测值与未来收益的关系是否稳定,分类概率是否可信,排名是否在不同年份都保持一定方向。第二层把分数转换成真实持仓,再检查扣除费用后的收益、回撤、换手、行业暴露和容量。两层必须同时报告,因为它们回答的是不同问题。
分类任务还要警惕类别不平衡。若历史中 55% 的样本上涨,一个永远猜“上涨”的模型已经有 55% 准确率。新模型得到 56%,并不自动意味着学到了有用规律。它需要和这个最简单的猜法比较,还要观察上涨与下跌样本各自的识别情况。
什么时候值得使用机器学习¶
机器学习更适合输入字段较多、变量之间可能互相作用、固定规则难以完整表达的问题。例如同时使用估值、质量、动量、波动和流动性,对同一天的一组股票做相对排序。它也适合重复处理大量结构相同的样本,因为模型需要从足够多的旧题中估计关系。
若策略规则已经简单清楚,普通公式往往更合适。一条十日均线上穿六十日均线的规则不需要神经网络重新发现。只有几十次事件,却训练数万个参数,同样不合理;模型有足够空间记住每一次历史,却没有足够新样本证明这种记忆能够延续。
判断是否使用机器学习,可以依次回答四个问题。研究目标能否写成一个明确标签,预测时是否拥有足够多的合法特征,历史样本是否足以支持模型复杂度,以及复杂模型是否在严格的未来检验中稳定超过简单基线。只要其中一个问题回答不清楚,继续堆叠模型通常不会解决根本困难。
一架逐级增加复杂度的比较梯子¶
可靠的研究不会让最复杂模型直接与空白比较。先建立一个无需学习的简单基线,再逐级增加自由度,可以看见性能究竟来自哪里。
- 随机分数用来确认回测和排序没有自带优势。
- 单一特征排名检验最基本的研究假设。
- 等权多特征分数观察简单组合是否已经足够。
- 正则化线性模型让数据学习有限的特征权重。
- 受约束的树模型尝试表达弯曲关系和变量互动。
- 深度模型只在样本、任务和前级结果都支持时继续。
六个级别应使用完全相同的日期、股票池、标签、成交时点和成本。若复杂模型只在某一次随机训练中略胜,却在换一个年份或种子以后消失,应保留简单版本。模型越难解释和维护,需要提供的样本外证据就越充分。
容易弄错的地方¶
| 常见想法 | 问题出在哪里 | 更稳妥的顺序 |
|---|---|---|
| 先挑最流行的模型 | 模型先于研究问题,标签容易被工具反向决定 | 先写决策和标签,再看是否需要模型 |
| 特征越多越容易发现规律 | 自由度和偶然关系一起增加 | 从少量有来路的特征开始 |
| 训练分数高说明模型聪明 | 模型可能只记住旧题 | 按时间检查验证和测试 |
| 预测分数可以直接当仓位 | 分数单位、风险和成交都未处理 | 先排序或校准,再构造组合 |
| 准确率超过一半就能赚钱 | 盈亏幅度和费用没有进入准确率 | 同时检查预测层与策略层 |
一分钟自测¶
假设一条人工规则只使用二十日收益给股票排序。新模型加入六十日波动和成交活跃度以后,训练准确率明显提高,未来一年表现却没有改善。你应该先增加模型层数,还是回到基线检查数据、标签和新增特征?
查看答案
应先回到基线。训练表现提高只说明模型更适应旧样本,未来没有改善说明新增复杂度尚未提供稳定信息。需要逐项检查标签时间、特征可得时间、换手和不同年份的结果,再决定是否保留新增特征。本课术语¶
| 词语 | 现在应该怎样理解 |
|---|---|
| 机器学习 | 从历史样本中估计输入与目标关系的方法 |
| 特征 | 预测时已经知道并交给模型的线索 |
| 标签 | 后来发生并用来批改预测的答案 |
| 样本 | 一组特征与一个标签组成的一道历史题 |
| 监督学习 | 使用带有历史答案的样本学习 |
| 损失函数 | 衡量模型预测与历史答案相差多少的规则 |
| 基线 | 复杂方法必须稳定超过的简单比较对象 |
| 过拟合 | 模型记住旧样本细节,却不能适应新数据 |
课后练习¶
- 基础理解 预测未来五日收益为什么属于监督学习?
提示
想一想历史样本是否拥有可以批改预测的答案。
答案
较早历史已经走完,所以每行样本都能得到未来五日收益标签。模型使用这些带答案的旧题学习,因此属于监督学习。- 任务判断 把股票按相似的波动形状自动分组,却没有预先规定正确类别,这与监督学习有什么不同?
提示
这里有没有标签。
答案
数据没有正确类别标签,任务是在输入中寻找结构,更接近无监督学习中的聚类。- 排错 模型在训练集上的方向准确率达到 99%,为什么应先怀疑数据流程?
提示
金融预测通常很弱,异常高分可能意味着模型看到了什么。
答案
异常高分常来自未来信息进入特征、标签与特征日期错位、重复样本或训练测试混合。应先用手算和时间检查排除这些问题。- 动手修改 把“预测股票上涨”改写成一个可以制作标签的问题。
提示
写出预测时点、成交时点、持有期限和输出形式。
答案
示例答案是“根据每周五收盘时已知的信息,预测下周一开盘买入并持有五个交易日后收益是否大于零”。其他答案只要四个要素清楚也可以。- 开放思考 什么情况下应放弃机器学习,保留普通规则?
评价要点
回答可以讨论样本太少、规则已经清楚稳定、复杂模型没有样本外增量、维护成本过高、特征可得时间不可靠,或交易成本吞噬改进等情况。
下一课不会立刻训练模型,而是把本课的小表拆开,逐步制作特征、标签和样本。继续阅读第 25 课 特征、标签、样本与时间对齐。