4、标签构造:如何定义“好股票”?未来N日收益率排序。相对排名与分组标签。
好,咱们进入实战环节最核心的一步——标签构造。
说白了,就是回答一个问题:到底什么样的股票,才算“好股票”?
你想想看,如果连好坏都定义不清楚,模型学出来的东西肯定跑偏。我在早期做量化的时候,就犯过这个错。直接用未来N日的绝对收益率当标签,结果模型学了一堆“垃圾股”的特征——因为那些小盘妖股短期涨得猛,但风险也大。后来我痛定思痛,改用排序和分组的思路,效果才稳定下来。
4.1 为什么不用绝对收益率?
绝对收益率,比如“未来5天涨了10%”,看起来直观。但问题在于:
- 市场环境不同:牛市里大部分股票都涨,熊市里大部分都跌。模型如果只学绝对收益,会把“市场Beta”当成“个股Alpha”。
- 极端值干扰:一只股票因为重组连续涨停,收益率100%,另一只正常涨了5%。模型会拼命去拟合那个100%的异常点,反而忽略了常态。
- 不可比性:不同时间点、不同板块的股票,收益率分布差异巨大。直接拿数值去训练,模型会“晕头转向”。
所以,我个人习惯的做法是:放弃绝对数值,改用相对排序。
4.2 核心思路:未来N日收益率排序
具体怎么做?很简单:
- 在每一个调仓日(比如每月第一个交易日),计算所有候选股票的未来N日收益率(比如未来20个交易日)。
- 然后,按收益率从高到低排序。
- 排名越靠前,说明这只股票在未来一段时间内,相对其他股票表现更好。
这样做的好处是:去掉了市场整体的影响。不管大盘涨跌,我们只看股票之间的相对强弱。模型学到的,是“哪些特征的股票更容易跑赢同行”,而不是“哪些股票容易跟风大盘”。
核心公式:
标签 = rank(未来N日收益率) / 总样本数
这样标签值在0到1之间,0代表最差,1代表最好。方便模型统一处理。
4.3 相对排名 vs 分组标签
有了排序之后,我们有两种常见的标签构造方式:
| 方式 | 说明 | 适用场景 |
|---|---|---|
| 相对排名 | 直接用排序后的百分位数作为标签(0~1连续值) | 回归模型(如LightGBM回归、神经网络) |
| 分组标签 | 将股票分成若干组(如5组、10组),每组赋予离散标签 | 分类模型(如逻辑回归、分类树)或排序学习模型(LambdaRank) |
我个人更推荐分组标签。为什么?
因为连续排名虽然信息量大,但模型容易过拟合到细微的排名差异上。比如排名0.51和0.52,其实差别不大,但模型会拼命去区分它们。分组之后,我们只关心“这只股票属于前20%还是后20%”,模型学到的模式更鲁棒。
我的经验:分组数量一般取5组(Quintile)或10组(Decile)。5组比较粗,适合样本量不大的情况;10组更精细,适合股票数量多的市场(比如A股4000+只)。
4.4 代码实现:从收益率到分组标签
嗯,这里我直接给一段核心代码。假设你已经有了一个DataFrame,包含每只股票在每个调仓日的未来20日收益率。
import pandas as pd
import numpy as np
def create_rank_labels(df, date_col='date', code_col='code', ret_col='fwd_20d_ret', n_groups=5):
"""
构造分组标签
df: 包含日期、股票代码、未来收益率的DataFrame
n_groups: 分组数量,默认5组
"""
df = df.copy()
# 按日期分组,在每个调仓日内部排序
df['rank'] = df.groupby(date_col)[ret_col].rank(method='first', ascending=True)
df['group'] = df.groupby(date_col)['rank'].transform(
lambda x: pd.qcut(x, q=n_groups, labels=False, duplicates='drop')
)
# 注意:pd.qcut的标签是0,1,2,...,n_groups-1
# 0代表最差组,n_groups-1代表最好组
# 我们通常希望标签越大代表越好,所以可以反转
df['label'] = n_groups - 1 - df['group']
return df[['date', 'code', 'ret', 'rank', 'group', 'label']]
# 使用示例
# result = create_rank_labels(raw_data, n_groups=5)
# result['label'] 就是我们要的标签,0最差,4最好
避坑指南:
我曾经遇到过一个问题:某一天所有股票的收益率都一样(比如停牌日),导致pd.qcut报错。所以建议在分组前,先检查一下该日是否有足够的收益率差异。如果差异太小,可以跳过该日,或者用随机排序打破平局。
4.5 标签构造的完整流程
为了让你更直观地理解,我画了一张流程图。这张图展示了从原始数据到最终标签的完整链路。
4.6 分组标签的进阶技巧
有了基础的分组标签,我们还可以做一些优化:
- 加权分组:不是简单等分,而是根据收益率的大小赋予不同权重。比如收益率最高的1%单独成一组,剩下的再等分。这样可以捕捉极端收益。
- 动态分组:市场波动大的时候,分组可以多一些(比如10组);市场平稳的时候,分组少一些(比如5组)。
- 多周期标签:同时构造未来5日、20日、60日的分组标签,让模型学习不同时间尺度下的选股能力。
一个小技巧:如果你用的是排序学习模型(比如LambdaRank),可以直接用pairwise的排序对作为标签。也就是说,不关心具体分组,只关心“股票A是否比股票B好”。这样模型更专注于相对关系,效果往往更好。
好了,标签构造这部分就讲到这里。记住一句话:好的标签,是成功模型的一半。花时间把标签定义清楚,后面模型训练会省很多力气。