深圳融克迪特科技有限公司 Logo,金融科技,量化交易,软件开发

深圳融克迪特科技有限公司

RONG CREDIT TECHNOLOGY CO., LTD.

工具实战

【CatBoost 系列 第2讲】CatBoost特征输入规范:类别编码、缺失值与时间切分

聚焦量化样本表的输入规范,说明 CatBoost 在类别特征、缺失值和时间切分上的正确处理方式,避免随机切分与错误编码造成验证失真。

2026-04-29 智铨研究 阅读时长 9 分钟

目录

CatBoost · 工具实战

  1. 第 1 讲【CatBoost 系列 第1讲】CatBoost在量化任务中的优势:有序提升与抗过拟合机制
  2. 第 2 讲【CatBoost 系列 第2讲】CatBoost特征输入规范:类别编码、缺失值与时间切分
  3. 第 3 讲【CatBoost 系列 第3讲】CatBoost参数调参与早停策略:稳定收益优先配置法
  4. 第 4 讲【CatBoost 系列 第4讲】CatBoost在事件驱动策略中的应用:财报与公告特征融合
  5. 第 5 讲【CatBoost 系列 第5讲】CatBoost模型可解释性:特征贡献、样本归因与异常诊断
  6. 第 6 讲【CatBoost 系列 第6讲】CatBoost概率输出与风险分层在选股模型中的应用
  7. 第 7 讲【CatBoost 系列 第7讲】CatBoost跨市场迁移:A股与期货数据域适配方法
  8. 第 8 讲【CatBoost 系列 第8讲】CatBoost模型鲁棒性测试:市场状态切换下的稳定性评估
  9. 第 9 讲【CatBoost 系列 第9讲】CatBoost生产化部署:批量推理、监控告警与漂移修复

一、本讲目标

第 1 讲已经说明了 CatBoost 为什么适合量化建模:它对类别特征友好、对缺失值容忍度高、在中小样本里通常比一味堆深网络更稳。但真正落地时,模型是否好用,往往不是先败在参数,而是先败在输入。很多团队把日频因子表、行业标签、停牌空值、未来收益标签直接拼进一个 DataFrame,就开始训练,结果不是线下分数虚高,就是上线后稳定性明显下滑。

本讲只解决一个问题:在量化场景里,怎样把 CatBoost 的输入表整理成一份可以训练、可以复现、也能避免未来函数的样本表。

你需要完成三件事:

  1. 明确哪些列是数值特征,哪些列是真正的类别特征。
  2. 明确缺失值该保留、该标记,还是该在训练前剔除。
  3. 明确训练集、验证集、测试集必须按时间切开,而不是随机打散。

如果这三件事没有先做对,后面的参数调优和早停策略基本都会建立在偏掉的样本上。

二、为什么第 2 讲必须先讲输入规范

CatBoost 的一个常见误解是:它既然“原生支持类别特征”和“自动处理缺失值”,那输入就可以很随意。这个理解只对了一半。CatBoost 确实能减少大量手工预处理工作,但它并不会替你判断列的业务含义,也不会替你识别时间穿越。

在量化任务里,最常见的三个输入错误是:

  1. 把证券代码、行业、交易状态这类离散信息当连续数值直接喂进去。
  2. 把财务缺失、停牌缺失、样本起始窗口不足造成的缺失混成一类处理。
  3. 用随机切分验证集,导致同一只股票未来时点的信息泄露回过去。

这三个问题里,前两个会让模型学到错误结构,第三个会直接污染验证结论。对 CatBoost 来说,输入规范不是“训练前整理一下表格”,而是模型可信度的第一道门槛。

三、环境准备:一张可训练样本表至少要长什么样

先把目标压缩到最小。假设我们做的是日频横截面收益预测,每一行代表某只股票在某个交易日可见的一组特征,对应未来 5 个交易日收益标签。那一张最小可训练样本表通常至少包含以下字段:

这里有一个关键约束:特征列必须全部来自 trade_date 当天收盘前或当日可确认的数据,标签列必须全部来自未来窗口。 任何把未来回看值混进特征的做法,都会让后面所有验证失去意义。

如果你的表里现在还混着“未来收益滚动均值”“未来成交量变化率”这类字段,先不要训练,先删掉。CatBoost 再稳,也救不了标签泄露。

四、哪些列应该作为类别特征

在量化数据里,不是所有“看起来不是小数”的列都该进 cat_features。一个更稳的判断方式是:这列是否代表离散身份,而不是数值大小。

通常适合交给 CatBoost 作为类别特征的列包括:

通常不应该当类别特征处理的列包括:

一个常见坑是把证券代码直接转成整数,例如把 600519.SH 编成 1057,然后当数值列输入。这会让模型错误地把“1057 比 18 大”理解成有意义的连续关系。对 CatBoost 来说,代码、行业、交易状态这类列最适合保留成字符串或显式声明为类别列。

五、类别编码的原则不是“先独热”,而是“先保真”

很多人在使用树模型时习惯先做 one-hot 编码,但在 CatBoost 里,这往往不是最佳起点。CatBoost 的优势之一,就是它能直接接收类别列并在内部做有序统计变换。对量化任务来说,这有两个现实好处:

  1. 可以避免高基数类别展开后维度急剧膨胀。
  2. 可以减少你手工编码时引入的泄露风险和列对齐问题。

真正该做的不是“先独热”,而是“先保真”:

如果你确实要做分桶,比如把市值分成 smallmidlarge 三类,也应该在训练规则里固定分桶边界,再把同样规则应用到验证集和测试集,而不是每一段数据各自按分位数重切一次。否则模型学到的就不是稳定语义,而是每一段样本内部的相对排名。

六、缺失值要先分型,再决定是否交给模型处理

CatBoost 能处理缺失值,不等于所有空值都应该原封不动交给它。量化数据里的缺失通常至少分成三类:

  1. 自然缺失:比如 60 日动量在上市不满 60 个交易日时天然为空。
  2. 业务缺失:比如某些财务字段在该季度尚未披露。
  3. 异常缺失:比如数据抓取失败、字段拼接错位、行情源断档。

前两类可以保留,但你最好知道它们为什么空。第三类如果不先排查,就会把数据问题伪装成模型鲁棒性。

一个稳妥做法是:

如果某列缺失率在少数日期突然飙升,例如平时只有 2%,某几天突然变成 70%,这通常不是“CatBoost 会自动处理”的问题,而是你该回头检查 ETL 或数据源的信号。

七、时间切分是量化验证里最硬的约束

量化任务和普通表格任务最大的区别之一,就是样本顺序不能随便打散。随机切分在用户画像、风控审批之类任务里可能还成立,但在收益预测、因子建模、事件驱动策略里,随机切分几乎一定会高估效果。

正确原则很简单:

例如:

如果你把 2024 年的数据随机抽一部分回到训练集中,再拿剩余 2024 年样本做验证,那么行业结构、市场状态、事件分布都已经提前泄露给模型了。验证分数会很好看,但上线以后很容易出现“训练时什么都对,实盘时显著降级”的情况。

八、操作步骤:把 DataFrame 交给 CatBoost 前先整理三件事

下面给一个足够小、但方向正确的示例。重点不是参数,而是输入约定。

from catboost import CatBoostRegressor, Pool

feature_cols = [
	"industry_lv1",
	"instrument",
	"is_st",
	"turnover_20d",
	"volatility_20d",
	"momentum_60d",
	"earnings_flag",
]

cat_cols = ["industry_lv1", "instrument", "is_st", "earnings_flag"]
target_col = "label_ret_5d"

train_df = full_df[(full_df["trade_date"] >= "2021-01-01") & (full_df["trade_date"] <= "2023-12-31")].copy()
valid_df = full_df[(full_df["trade_date"] >= "2024-01-01") & (full_df["trade_date"] <= "2024-06-30")].copy()

train_pool = Pool(
	data=train_df[feature_cols],
	label=train_df[target_col],
	cat_features=cat_cols,
)

valid_pool = Pool(
	data=valid_df[feature_cols],
	label=valid_df[target_col],
	cat_features=cat_cols,
)

model = CatBoostRegressor(
	loss_function="RMSE",
	eval_metric="RMSE",
	iterations=800,
	depth=6,
	learning_rate=0.03,
	random_seed=42,
	verbose=100,
)

model.fit(train_pool, eval_set=valid_pool, use_best_model=True)

这个示例里最重要的不是 depth=6,而是以下三点:

  1. 类别列是显式声明的,而不是偷偷转成整数。
  2. 训练集和验证集是按时间切开的,而不是随机抽样。
  3. 特征列和标签列的边界是固定的,没有把未来字段混入输入。

九、工具落地:上线前要检查的五个输入一致性问题

在训练能跑通之后,不要立刻进入调参。先做一轮输入一致性检查,至少回答下面五个问题:

  1. 训练、验证、测试三段里,类别列的数据类型是否完全一致。
  2. 是否存在只在测试集才出现的大量新类别。
  3. 缺失值高峰是否集中在某几个日期或某几类资产上。
  4. 标签构造窗口是否和特征可见时间严格错开。
  5. 同一只资产是否在不同时间段被重复拼接出冲突样本。

这里尤其要注意“新类别涌入”。例如行业分类规则升级、证券简称变更、交易状态编码变化,都可能让验证集和测试集出现训练集没见过的类别。CatBoost 能处理一部分未见类别,但如果变化是系统性的,你更应该先统一口径,而不是让模型被动承受脏输入。

十、常见问题排查:不是不会调参,而是样本表根本不干净

实际项目里,以下几种情况最容易被误判成“模型问题”:

这些问题如果不在输入层解决,后面调 depthl2_leaf_regbagging_temperature 只是表面功夫。CatBoost 的强项是把一份结构清楚的表学得更稳,而不是替你把脏样本自动修正成干净样本。

十一、本讲完成标准

如果你已经做到下面几点,这一讲就算真正完成:

  1. 能明确列出你当前样本表中的类别列和数值列。
  2. 能说清每一类缺失值分别来自哪里,而不是统一用均值或统一删行。
  3. 能把训练集、验证集、测试集按时间切开,并说明为什么不能随机打散。
  4. 能用一份最小样本表构造出 Pool,让 CatBoost 正常读取类别列。
  5. 能检查并解释输入表中最容易造成未来函数的字段。

做到这一步,你才真正有资格进入下一讲的参数调优和早停策略。否则调参调出来的只是偏样本上的最优解。

十二、系列衔接

本讲是《CatBoost量化建模完整学习计划》的第 2/9 讲,当前主题是《CatBoost特征输入规范:类别编码、缺失值与时间切分》。

上一讲:第 1 讲《CatBoost在量化任务中的优势:有序提升与抗过拟合机制》。

下一讲:第 3 讲《CatBoost参数调参与早停策略:稳定收益优先配置法》。

后续安排:第 4 讲《CatBoost在事件驱动策略中的应用:财报与公告特征融合》;第 5 讲《CatBoost模型可解释性:特征贡献、样本归因与异常诊断》。

十三、风险揭示与免责声明

风险揭示与免责声明

本页面内容仅用于量化研究与技术交流,旨在展示研究方法与流程,不构成对任何金融产品、证券或衍生品的要约、招揽、推荐或保证。

本文所涉历史数据、回测结果与示例参数不代表未来表现,也不应作为投资决策依据。

市场存在波动、流动性与执行偏差等不确定性,任何策略均可能出现收益波动或阶段性失效。

读者应结合自身风险承受能力进行独立判断,并在必要时咨询持牌专业机构意见。