行为
CR-011-特征矩阵Parquet存储形态由长表变更为宽表¶
| 字段 | 内容 |
|---|---|
| CR ID | CR-004 |
| 标题 | 特征矩阵落盘形态由长表(EAV)变更为宽表(38列并排) |
| 发起人 | Henry Lin (PM) |
| 日期 | 2026-04-17 |
| 状态 | ✅ Approved |
| 影响范围 | 规约 4.1 节特征目录、S3-04 产出物 Schema、docs/data_contract.md、下游 Step 5 数据加载逻辑 |
1. 变更描述¶
原规约约束:
上述 38 维特征在
features.parquet中必须为长表形态(Schema:fund_id,net_value_date,feature_name,feature_value)。严禁 Pivot 成宽表。
变更为:
features_YYYY.parquet必须为宽表形态。Schema 固定为:fund_id(String),net_value_date(Date),segment_id(UInt32), 以及 38 个特征列(如price_vs_ma_ratio_12wFloat64, ...,calmar_ratio_52wFloat64)。严禁在落盘阶段使用unpivot转换为长表。
2. 变更原因(根因追溯)¶
在 M3a 架构评审中发现,原“长表落盘”红线与高性能计算架构存在严重冲突:
-
计算层冲突:截面 Z-Score 标准化与共线性剔除(IC 计算)的纯函数,在 Polars 中必须基于“行=样本,列=特征”的宽表矩阵才能进行高效向量化运算。若坚持长表,需在每次计算前后频繁执行
pivot/unpivot,带来巨额的 CPU 与内存开销。 - 训练层冲突:LightGBM 等树模型原生要求宽表输入,长表形态迫使 Step 5 必须额外维护一套高频 Pivot 读取逻辑。
-
列式存储劣势:对于 Parquet 这种列式格式,在特征维度固定(38维)且有限的情况下,宽表能完美利用“按列裁剪”优势;而长表(EAV)的
feature_name字符串列会破坏列式压缩率,且按特征筛选时产生大量冗余 IO。 - 维度确定性:本系统特征已通过《特征字典基线文档》刚性冻结为 38 维,不存在“频繁增删特征导致宽表 Schema 失控”的 EAV 适用前提。
3. 影响分析¶
| 受影响模块 | 影响说明 | 应对措施 |
|---|---|---|
feature_engineering.py |
取消落盘前的 unpivot() 逻辑 |
内存中全程维持宽表,计算完毕后直接调用 PyArrow write_parquet()
|
data_contract.md |
存储形态红线描述变更 | 更新《特征矩阵接口契约单》,明确宽表 Schema 及 38 列的严格类型映射 |
trainer.py (Step 5) |
简化数据加载逻辑 | 直接读取宽表,废弃原有的 GroupBy+Pivot 还原逻辑 |
| 元数据校验 | Hash 与审计逻辑适配 |
features_hash.json 基于宽表文件计算,无需变更工具函数 |
由 Huarui Lin 更新于 大约 5 小时 之前 · 2 修订