12.4 特征工程:把原始数据变成可用特征
课前导读
本节目标
你将学会:把价格、成交量、财务和公告等原始数据加工成可复核特征,并识别可得性和泄露风险。
适合对象:已经理解因子、回测、机器学习切分和实盘数据校验的 A 股投资者。
难度:advanced
预计用时:约 45 分钟
特征工程是量化研究中最容易被低估的一环。
很多人把注意力放在模型上,却忽视模型吃进去的每一列数据。
如果特征含义不清、时间不可得、口径漂移或混入未来答案,再复杂的模型也只是在放大错误。
这一节的主线是:特征不是越多越好,而是越清楚、越可验证、越不泄露越好。
你会从价格、成交量、财务和公告四类数据出发,学习如何构造特征卡,并理解为什么特征工程是“更严格地验证想法”。
知识正文
1. 类比:特征工程像备菜
做饭前要洗菜、切菜、分装、标注日期。
如果菜已经坏了,锅再高级也做不出好饭。
原始行情、财务和公告数据就是食材。
特征工程就是备菜。
模型是锅。
回测是试吃。
实盘观察是把菜端给真实客人前的小范围验证。
如果备菜环节把明天才送到的食材提前放进今天的菜里,味道当然会异常好。
但那是时间穿越,不是研究能力。
关键直觉
特征工程的第一原则不是“创造更多列”,而是“每一列都能解释、能复现、能站在当时使用”。
2. 术语一:原始数据、特征、标签
原始数据是直接记录下来的事实。
例如收盘价、成交额、换手率、财报披露日期、公告标题。
特征是从原始数据加工出来、用于解释或预测的字段。
例如过去 20 日涨跌幅、过去 60 日波动率、ROE 滞后值、公告后第几天。
标签是研究答案。
例如未来 20 日收益、未来是否跑赢行业、未来最大回撤。
特征和标签必须严格分开。
特征回答“当时我知道什么”。
标签回答“后来发生了什么”。
如果这两者混在一起,模型就会偷看答案。
3. 价格类特征:从 K 线到行为线索
价格数据是最常用的原料。
它更新快、覆盖广、容易复现。
但也最容易被过度挖掘。
常见价格特征包括:
| 特征 | 构造方式 | 直觉 | 风险 |
|---|---|---|---|
| 20 日动量 | 今日收盘价 / 20 日前收盘价 - 1 | 近期是否被市场认可 | 追高、风格切换 |
| 60 日反转 | 过去 60 日跌幅较大 | 是否存在修复机会 | 可能是基本面变差 |
| 均线距离 | 收盘价 / MA20 - 1 | 偏离短期均值多少 | 极端行情会钝化 |
| 波动率 | 过去 N 日收益标准差 | 持有过程是否颠簸 | 波动本身也会变化 |
| 最大回撤 | 窗口内从高点到低点的跌幅 | 近期风险体验 | 窗口选择影响很大 |
价格类特征要注意复权口径。
前复权、后复权、不复权会影响动量和均线。
研究报告里必须写清楚使用哪一种口径。
否则同一个因子在不同数据源上可能结果不同。
4. 成交量和流动性特征:观察资金是否愿意交易
成交量不是单纯的热闹程度。
它反映市场参与者是否愿意用真金白银交换筹码。
常见成交类特征包括:
- 成交额相对过去 20 日均值的倍数。
- 换手率过去 5 日均值。
- 成交额分位数。
- 量价配合,例如放量上涨或放量下跌。
- 买卖价差或可成交性指标,如果数据可得。
在 A 股中,流动性特征尤其重要。
很多纸面策略忽略小票成交困难、涨跌停无法成交、冲击成本放大。
一个看似高收益的因子,如果集中买入低流动性股票,实盘可能很难复现。
常见误区
成交量特征不能只看“放量就是好”。放量可能是资金进入,也可能是恐慌出逃,还可能是利空公告后的换手。
5. 财务特征:必须尊重披露时间
财务数据能帮助你理解公司质量、成长和估值。
但财务特征最容易出现可得性错误。
财报有报告期,也有披露日。
报告期是会计上覆盖的时间段。
披露日才是投资者真正能看到数据的时间。
例如某公司 2023 年年报报告期结束于 2023 年 12 月 31 日。
但实际披露日可能是 2024 年 4 月 20 日。
你不能在 2024 年 1 月的模型里使用这份年报。
常见财务特征包括:
| 特征 | 直觉 | 关键边界 |
|---|---|---|
| ROE | 股东资金赚钱效率 | 使用披露日后可见值 |
| 营收增长率 | 生意规模是否增长 | 注意同比口径和季节性 |
| 净利润增长率 | 盈利是否改善 | 警惕一次性收益 |
| 经营现金流质量 | 利润是否有现金支持 | 需结合行业特征 |
| 资产负债率 | 杠杆和偿债压力 | 金融、地产等行业口径不同 |
财务特征不适合和高频交易节奏硬拼。
它更适合中低频选股、组合暴露和风险过滤。
6. 公告和事件特征:把文字变成结构化记录
公告是 A 股投资者的重要正式信息来源。
但公告文本不能随意变成模型魔法。
你可以先做非常朴素的事件特征:
- 是否发布业绩预告。
- 业绩预告类型:预增、预减、扭亏、续亏。
- 公告披露后第几天。
- 最近 30 日是否有减持公告。
- 是否有监管问询。
- 是否停牌后复牌。
这些特征不要求你马上做复杂自然语言处理。
先把“公告是否存在、何时可见、属于哪类事件”记录清楚,就已经很有价值。
事件特征的最大风险是时间戳。
公告如果在晚间披露,通常只能影响下一交易日及以后。
不能把当天白天尚未披露的公告用于当天买卖判断。
7. 特征可得性:每一列都要有身份证
一个合格特征至少要回答六个问题。
| 字段 | 说明 |
|---|---|
| 特征名称 | 例如 momentum_20_lag1 |
| 原始来源 | 行情、财务、公告或手工记录 |
| 计算公式 | 如何从原始数据得到 |
| 可见时间 | 投资者何时可以合理看到 |
| 使用频率 | 日频、周频、月频或财报披露后 |
| 风险备注 | 缺失、异常、行业口径、泄露可能 |
这张表就是特征卡。
特征卡不是形式主义。
它能让你在几个月后复查时知道当初为什么这样算。
也能让别人复现你的研究。
量化开发中,特征卡还可以转化为数据字典、审计日志和测试用例。
8. 特征泄露:最隐蔽的高分作弊
特征泄露是指模型使用了当时不该知道的信息。
常见泄露包括:
- 用未来收益筛选股票池。
- 用全样本均值或标准差标准化历史数据。
- 用修正后的财务数据覆盖历史版本。
- 用公告披露前的财务字段参与决策。
- 用未来成分股列表回看过去。
- 用当天收盘后才知道的数据假设当天收盘前成交。
泄露的可怕之处在于,它通常不会报错。
代码可以运行,曲线可以很漂亮,报告可以很完整。
但结论是假的。
风险提醒
任何异常优秀的特征表现,都要先排查泄露、幸存者偏差、成本忽略和极端样本贡献,再讨论是否有投资价值。
9. 特征处理:缺失、异常、标准化和方向
你在因子章节已经学过清洗。
这里从特征工程角度再强调一次。
缺失值不一定要简单删除。
财务数据缺失可能意味着公司尚未披露。
公告特征缺失可能意味着没有事件。
停牌导致价格缺失,背后是交易不可得。
异常值也不能机械处理。
成交额突然放大可能是数据错误,也可能是真实重大事件。
标准化可以让不同量纲放在一把尺子上。
但标准化必须按当时可见样本计算。
方向统一可以让模型更容易学习。
例如把“估值越低越好”转换成“价值得分越高越好”。
10. A 股案例:构造一个稳健观察表
假设你想研究“质量较好、估值不贵、近期没有过热的股票是否更稳”。
可以构造一张日频观察表。
| 特征名称 | 类别 | 构造直觉 | 使用边界 |
|---|---|---|---|
| roe_lagged | 财务 | 公司赚钱效率 | 只在财报披露后使用 |
| pe_percentile_3y | 估值 | 当前估值在历史中贵不贵 | 需处理亏损公司 |
| momentum_20_lag1 | 价格 | 近期市场认可程度 | 滞后一日避免收盘偷看 |
| volatility_60_lag1 | 风险 | 近期持有颠簸程度 | 窗口过短会噪声大 |
| amount_ratio_20_lag1 | 成交 | 是否突然受关注 | 放量方向需结合价格 |
| announcement_flag_30 | 公告 | 近 30 日是否有重大事件 | 只用披露后信息 |
这个表不是买入清单。
它只是把原本模糊的观察转成可检查字段。
下一步还要做样本外验证、分组收益、成本测试和组合约束。
11. 特征工程流程
graph TD
A["提出研究问题"] --> B["列出原始数据"]
B --> C["确认可见时间"]
C --> D["构造候选特征"]
D --> E["处理缺失和异常"]
E --> F["滞后与标准化"]
F --> G["写特征卡"]
G --> H["进入回测或模型验证"]注意流程中“确认可见时间”非常靠前。
如果一列数据的可见时间说不清,就不应该急着进入模型。
12. 短小 Python 示例:安全构造价量特征
下面代码只展示思路,不依赖外部数据。
# df 已按 date 升序排列,包含 close、amount 两列
# 所有可用于决策的特征都滞后一日
df["ret_1d"] = df["close"].pct_change()
df["momentum_20"] = df["close"] / df["close"].shift(20) - 1
df["volatility_20"] = df["ret_1d"].rolling(20).std()
df["amount_ratio_20"] = df["amount"] / df["amount"].rolling(20).mean()
feature_cols = ["momentum_20", "volatility_20", "amount_ratio_20"]
for col in feature_cols:
df[col + "_lag1"] = df[col].shift(1)
# 研究标签:未来 20 日收益,只能当答案,不能当特征
df["label_next_20d"] = df["close"].shift(-20) / df["close"] - 1直觉解释:
先用历史价格和成交额计算候选特征。
再统一滞后一日,保证决策时已经可见。
最后构造未来收益标签,用来评估特征是否有信息。
如果你把 label_next_20d 放进模型特征列表,整个实验就失去意义。
13. 专业老师、投资者、开发者三重视角
老师视角:先解释每个特征背后的投资直觉,再讲计算公式。
投资者视角:特征是观察工具,不是单独下单理由。
量化开发视角:特征必须可复现、可审计、可追踪版本。
三重视角合起来,就是把“我感觉这家公司不错”变成“我能用当时可见数据描述它为什么不错,并检验这个描述是否经得住样本外”。
14. 特征少而清楚,通常优于多而混乱
特征工程很容易膨胀。
一个价格字段可以衍生出几十个窗口。
一个财务字段可以衍生出同比、环比、分位数、行业中性值。
如果没有研究假设,特征越多,越容易试出偶然结果。
更稳健的做法是:
- 先写每个特征的投资直觉。
- 再写可见时间和计算公式。
- 然后检查缺失和异常。
- 最后才进入模型或回测。
特征工程不是追求复杂。
它追求的是让每一列都经得起追问。
交互实验室
练习 1:填写一张特征卡
请为“过去 20 日动量”填写特征卡。
| 项目 | 示例答案 |
|---|---|
| 特征名称 | momentum_20_lag1 |
| 原始来源 | 日线收盘价 |
| 计算公式 | 今日收盘价 / 20 日前收盘价 - 1,再滞后一日 |
| 可见时间 | 当日收盘后可算,下一交易日可用 |
| 使用频率 | 日频 |
| 风险备注 | 追高风险、停牌影响、复权口径影响 |
请再选择一个财务特征或公告特征,按同样格式填写。
练习 2:识别泄露风险
判断下面特征是否安全。
- 使用 2024 年 4 月披露的年报数据,回填到 2024 年 1 月模型。
- 用当天收盘价计算信号,第二天执行。
- 用全市场 2016-2024 年均值标准化 2017 年特征。
- 用公告披露日后的交易日构造“公告后第几天”。
参考答案:
- 第 1 条不安全,财报披露前不可见。
- 第 2 条较安全,因为执行在第二天。
- 第 3 条不安全,标准化用了未来年份。
- 第 4 条较安全,前提是公告时间戳准确。
练习 3:从想法到特征
研究想法:近期没有过热、基本面质量较好、流动性足够的股票更适合作为观察池。
请写出至少 4 个候选特征:
| 维度 | 候选特征 | 为什么可能有用 |
|---|---|---|
| 过热程度 | 20 日涨幅分位数 | 避免过度追高 |
| 质量 | ROE 滞后值 | 观察赚钱效率 |
| 流动性 | 20 日成交额均值 | 降低无法成交风险 |
| 风险 | 60 日波动率 | 控制持有颠簸 |
| 事件 | 近 30 日重大公告标记 | 避免信息冲击未消化 |
完成后请加一句边界说明:这些特征只用于筛选和验证,不构成买卖建议。
核心复盘
知识清单:
- [ ] 我能区分原始数据、特征和标签。
- [ ] 我知道价格、成交量、财务和公告都能构造特征,但可见时间不同。
- [ ] 我会为每个特征写来源、公式、可见时间和风险备注。
- [ ] 我能识别常见特征泄露,如未来股票池、全样本标准化和财报回填。
- [ ] 我理解特征工程是为了更严格验证想法,而不是堆更多变量。
金句总结
好特征不是最会讲故事的列,而是最经得起时间、口径和泄露检查的列。