第 7 课 · Feature / Label / PCA

量化机器学习入门:从特征到可验证的预测

先搞懂特征、Label、时间切分;
再用 18ETF 案例把 LogDiff → PCA50 → Expanding → Lasso 落地。

案例:ASSET_CLASS_ETF_SYMBOLS 18 只全球资产 ETF/LOF · 报告根 reports/lesson_07_etf18_logdiff_pca_ml/
数据链
+ PCA
LogDiff
~1440
PCA
50
Expanding
370
Purge
= H
Lasso
出分
建立直觉 · 输入与输出

监督学习只要记三件事:特征、Label、模型

中学生例子:体育老师想根据身体情况,猜同学的体能测试分数。

特征与 Label 输入,训练后输出模型
特征 = 题目条件身高、体重、每周跑步几次。
Label = 标准答案练习阶段才有的真实体能测试分。
模型 = 解题方法从大量「条件 → 答案」里总结出的规则。
关系一句话:特征 + Label 一起训练,输出的是模型(解题方法),不是某一道题的分数。
监督学习三要素 · 本页先不讲 Weight

Feature、Label、训练、Prediction + 线性回归 / Lasso

概念回答的问题本页要强调
Feature模型现在看到了什么?只能用当时可知信息
Label训练时希望模型学会预测什么?只在训练阶段当“标准答案”
训练(Training)模型怎样从 Feature + Label 学规则?不断调系数,让预测误差变小
Prediction模型对新数据判断什么?仍是预测值,不是交易指令
线性回归:散点与拟合直线
y = f(x):输入 → 规则 → 结果x 放进规则 f,就得到结果 y
x 是条件,y 是答案x 例如跑步次数、身高;y 是真实体测分数。
f 是规则,ŷ 是模型的猜测训练是在找出 f;预测时用 f(x) 算出 ŷ,去猜真实 y
Prediction(ŷ)还不是仓位。案例里 Lasso 吃的是 PCA 后的 50 维,不是原始 1440 维。
样本结构 · 从训练到预测

Feature、Label、训练、预测,怎样接在一起?

X_train + y_train 用于训练;面对新样本时只有 X_new,模型输出 ŷ_new,真实 y_new 留待未来检验。
学员问题 · 先独立判断

下列哪一项只能当 Label,不能当 Feature?

现在是周二收盘,你要预测未来 20 个交易日的收益。
A. 截至周二的价格与成交量 B. 过去 5 日的波动 C. 周三之后 20 日的实际收益

选 A / B / C,并写一句理由:为什么它在周二收盘时能或不能被看到?

先独立想 30 秒,再点击查看答案。

查看答案收起答案
C。
未来 20 日的实际收益在周二收盘时还没有发生,只能在训练阶段作为答案(Label)。A、B 是当时已经可知的信息,才可以做 Feature。
第一部分

核心概念

先把对数差分、PCA、Lasso、截面排名、Expanding、Purge 讲清楚

1 · 对数差分

什么是「对数差分」?

日常收益率是 (今天 − 昨天) / 昨天;量化里更常用对数差分,方便跨时间加总、跨品种比较。

OHLC 两两组合构成对数差分特征
本策略更进一步不只 close 对 close,而是 OHLC 四个价格两两组合。
核心公式log(f1) - log(f2).shift(lag)
举例close vs open.shift(1):昨开到今收的变化。
为何维数会爆跨价格 × 多组 lag/shift → 后面必须 PCA。
1 · LogDiff 维度拆解

1440 个特征,到底是怎样乘出来的?

每只 ETF 都先独立生成这 1440 列;18 只 ETF 增加的是训练样本行数,不是把列数再乘 18。
学员问题 · 对数差分

10 → 11 和 100 → 110,LogDiff 会一样吗?

ETF A 的价格从 10 变到 11;ETF B 从 100 变到 110。两个变化发生在同一天。

回答“会”或“不会”,并写一句理由:LogDiff 比较的是价格差,还是相对变化?

先独立想 30 秒,再点击查看答案。

查看答案收起答案
会。
两者都是 +10%,所以都是 log(1.1)。LogDiff 把不同价格量级统一成相对变化,不是直接比较 1 和 10 这两个价格差。
2 · PCA

PCA:找到数据摊得最开的方向

点云拉成斜椭圆时,先画最长方向的新轴(PC1),再画垂直的次要轴(PC2)。

PCA:散点云与两条主成分方向箭头
PC1 = 变化最大像给斜椭圆找“最长直径”。
PC2 = 次要、垂直在剩下的变化里再找最重要方向。
降维 = 丢掉短箭头上千维时只留前几十条长箭头。
类比身高和体重高度相关时,真正有用的往往是“体型大小”。
配图:Wikimedia Commons GaussianScatterPCA.svg。案例里会把约 1440 维压到 50 维。
2 · PCA 续

为什么 1440 维必须压成 50 维?

原始 1440 维高度冗余
很多列在说同类事
PCA 50 维精华浓缩
保留主要方向
1440 → 50压缩前后维数
98.9%本课折内解释方差
28.8×压缩比
关键细节PCA 只在训练集上 fit,再 transform 预测集 → 防止未来信息泄露。
丢掉的 1.1% 是什么多半是单日噪声;保留的 50 维已覆盖绝大部分共同波动。
50 是拍脑袋定的吗是个待调旋钮:本课默认 50,课后练习让你换成 20 / 100 看绩效差多少。
98.9% 来自本课报告 fold_metrics_lasso.csvpca_explained_variance_sum(5 折 98.90%–99.00%)。
互动演示 · PCA

从 3D 投影到 2D / 1D

同一批样本仍保留;PCA 丢弃的是信息较少的坐标方向,并用更少的坐标重新表示它们。

学员问题 · PCA

能把预测期的数据一起拿来 fit PCA 吗?

你用 2018–2024 年训练,打算预测 2025 年。有人先把 2018–2025 年全部样本混在一起,再执行 pca.fit(full_X)

这一步能不能做?选“能”或“不能”,并说出原因。

先独立想 30 秒,再点击查看答案。

查看答案收起答案
不能。
PCA 会从数据里学习主要变化方向;把 2025 年一起 fit,就让未来分布影响了训练过程。正确顺序是只在训练窗 fit,再对训练窗和预测窗都 transform
过渡 · OLS 基线

OLS:先学一条「误差最小」的直线

把 PCA 后的特征送进模型时,OLS 会找一组系数,让训练样本的预测误差平方和最小。

ŷ = β₀ + β₁x
min Σ(yᵢ − ŷᵢ)²
残差是点到线的竖直距离e = y − ŷ。每个点都要被照顾,不是只让某一个点贴着线。
为什么要平方偏得越远,代价增长越快;正负误差也不会彼此抵消。
它是 Lasso 的出发点OLS 只追求拟合误差;Lasso 保留这个目标,再给系数加上“总额度”约束。
二维直线只是示意。进入多维 PCA 特征后,直线变成一组系数;本课正式训练的模型仍然只有 Lasso。
互动演示 · OLS

拖动直线,看残差平方和怎样变

先随意移动斜率或截距,再点“回到 OLS 最优直线”:黄色残差加总后平方,最小值就是 OLS 的选择。

过渡 · 从 OLS 到 Lasso

同样拟合误差,Lasso 多了一道「系数预算」

两者都希望预测接近真实值;差别在于 Lasso 会同时惩罚所有系数的绝对值之和。

OLS:min Σ(yᵢ − ŷᵢ)²

Lasso:min Σ(yᵢ − ŷᵢ)² + αΣ|βⱼ|
OLS:只管把误差压低只要能让残差平方和更小,很多特征都可能保留一点系数。
Lasso:误差之外再算“用多少系数”αΣ|βⱼ| 像总预算;弱特征不值得花预算时,系数会被压成 0。
alpha 决定取舍alpha 小时更像 OLS;alpha 太大时模型虽简单,却可能漏掉有用信号。
比较点OLSLasso
系数结果通常多数特征都会留下系数弱特征可恰好归零
模型复杂度以拟合误差为主用少量有效特征换取更简洁的模型
本课角色理解 Lasso 的无约束基线唯一正式训练的模型
3 · Lasso

Lasso:给系数设一个「总额度」

普通线性回归给 50 个主成分都配一个系数;Lasso 额外要求「所有系数的绝对值之和不能太大」,装不下的就只能归零。

alpha 变大时 Lasso 系数逐个归零,非零个数从 46 降到 0
alpha 是唯一旋钮alpha 越大额度越紧;一路调大,非零系数从 46 个降到 0 个。
本课 alpha=1e-3最后一折只剩 PC1、PC2、PC10、PC11 四个,其余 46 个系数正好是 0。
归零 = 自动选特征Ridge 只会把系数压小,Lasso 能压到恰好 0,所以模型可读。
为什么先 PCA 再 LassoPCA 去掉列与列之间的相关,Lasso 在互不相关的轴上挑选更稳。
图由 lessons/legacy-slides/ppt/lesson_07/make_figures.py 在本课最后一折真实训练数据上跑出来,不是示意图。
互动演示 · Lasso

把 alpha 调大,看弱系数何时归零

用一个可控的示意路径,把“正则化更强 → 模型更稀疏 → 可能欠拟合”的关系看清楚。

学员问题 · Lasso

把 alpha 调大后,弱系数会怎样?

同一批 PCA 特征送进 Lasso。你把 alpha 从很小的值逐步调大。

弱特征的系数更可能“变大”,还是“被压到 0”?写一句理由。

先独立想 30 秒,再点击查看答案。

查看答案收起答案
更可能被压到 0。
alpha 越大,Lasso 对系数总量的限制越强,弱特征会先归零,因此它同时在做稀疏化和特征筛选。太大时,连有用特征也可能被删掉。
4 · 截面 Rank Label

截面排名是 Label:给模型的「标准答案」

每个交易日先看未来 20 日实际收益,再把同日 ETF 排成 [0,1];这个排名只在训练时当作 y(Label)

同一天 ETF 收益转成截面百分位排名
它是 Label,不是 FeatureFeature 是当日已知的信息;未来排名是训练时才有的标准答案。
模型学什么关心谁排前面,不关心精确涨幅。
预测时有真实 Rank 吗?没有。只给 Feature,Lasso 输出用于排序的预测分数。
也不是仓位分数先用于排序;Top N 与回测留给第 8 课。
学员问题 · 截面 Rank Label

截面排名在本课里,是 Feature、Label,还是仓位?

周二收盘后,未来 20 日实际收益还没发生。等这 20 日过去后,才把当周二的所有 ETF 按实际收益排成百分位排名。

这个截面排名应归为哪一项?选 Feature / Label / 仓位,并写一句理由。

先独立想 30 秒,再点击查看答案。

查看答案收起答案
Label。
它依赖未来 20 日的实际收益,在周二收盘时还不存在,因此只能作为训练答案。Feature 是周二已经可知的信息;Lasso 的预测分数才会在下一步被用于排序,二者都不是仓位本身。
5 · Expanding Window

Expanding:训练窗只往前长,不丢历史

市场会变,不能只训一次;但也不扔掉旧数据——历史越积越多。

Expanding 折次:Train 累积、Purge、Pred
初始训练边界在第 250 日,扣掉 Purge 后实际训练 230 日。
每次推进370 个交易日(约 1.5 年),全样本切成 5 折。
Purge= horizon = 20 日,挡住 Label 未来窗。
对照直觉Rolling 是固定长度前移;本课主链用 Expanding。
步长是可调旋钮:retrain_step 调小 → 折数变多、重训更频繁、跑得更慢;本课工作流默认 370。
第二部分

策略逻辑

18ETF × LogDiff × PCA50 × Expanding × Lasso

7 · 策略整体架构

本课在预测什么?整条链长什么样?

数据18 只 ETF日频 OHLCV
全球资产池
特征1440 维OHLC 对数差分
降维PCA 50train-only
模型Lasso预测截面排名
核心问题同一天里,谁未来 horizon=20 日收益排名可能更高?
本课停在Lasso 出分;Top N / 回测留给第 8 课。
项目本课口径
特征OHLC 对数差分 4×4×9 lag×10 shift = 1440 维
降维PCA → 50(只在训练窗 fit)
模型Lasso(alpha=1e-3)(本课只用这一个)
标签未来 20 日收益的截面 percentile rank
训练Expanding:min_train=250 / retrain_step=370 / purge=20
互动演示 · Expanding Window

每一折都先训练,再预测

同一折中:训练窗先生成 1440 维 LogDiff、fit PCA(50)、fit Lasso;预测窗只能复用已 fit 的 PCA 和 Lasso 出分。下一折训练窗扩张后,再重新 fit。
交给 AI · 数据链 + Lasso

把数据准备与 Lasso 出分交给 AI

推荐 Prompt 要点

  1. 读取 18 ETF 的 1d_adj 日线(已复权,不要二次调整)。
  2. make_logdiff_panel_features(panel) 拼出 1440 列。
  3. 生成 horizon=20 截面 Rank Label,剔除尾部不完整样本。
  4. Expanding:min_train=250, retrain_step=370, purge=20
  5. 每折 train-only PCA(50),再 fit Lasso(alpha=1e-3)
  6. 报告维数、解释方差、非零系数、折外 MSE / R² / Rank IC。
必须讲清
模型边界:本课只跑 Lasso。
仓位边界:不做 Top N 与完整回测。
禁止:全样本 fit PCA。
学员问题 · 策略边界

Lasso 给出最高分,就能直接买入吗?

模型给 18 只 ETF 都打了预测分数,A 的分数最高。你还没有设 Top N、调仓频率、仓位权重或交易成本。

此刻能不能直接下单买 A?选“能”或“不能”,并指出模型当前只完成了哪一步。

先独立想 30 秒,再点击查看答案。

查看答案收起答案
不能。
本课的模型只完成“预测并排序”,输出的是分数。把分数变成 Top N、权重、调仓和含成本回测,是后续的组合与执行问题。
AI 实验 · 验收 ①

验收:LogDiff → PCA → Expanding → Lasso

Lasso 链路在 h=1/5/10/22 下的样本外净值
1LogDiff = 1440lookback=5 默认维数。
2Expanding 边界250 / 370 / purge=20 能复述。
3PCA train-onlyfit(train) → transform 双侧。
4只有 Lasso输入 PC1…PC50;ŷ ≠ 仓位。
预览图来自 horizon 敏感性网格(purge=各自 horizon),四条线是同一条 Lasso 链路换预测跨度的结果:跨度越长越稳。
作业 · Lasso 工作流

固定 Lasso,比较 PCA 维数下的策略绩效

STEP 1 · 固定模型,只改 PCA 维数分别运行 Lasso + PCA = 20 / 50 / 100

使用本课的 Lasso 工作流三次。每次只改变 PCA 维数;训练、验证与回测设置保持一致。

实验 A:Lasso + PCA 20
实验 B:Lasso + PCA 50
实验 C:Lasso + PCA 100