FSS-Sprint4
打开标签生成器¶
由于 Step 4 业务逻辑高度内聚且规约给出了标准伪代码,一周时间安排相对紧凑,核心攻坚集中在向量化实现与边界防御。
| 周次 | Story ID | Story 描述 | 规约硬性映射 | 验收标准 | 工时 |
|---|---|---|---|---|---|
| W4 | S4-01 |
DCA 标签向量化核心引擎 实现基于 Polars group_by + NumPy 的标签计算逻辑。 |
规约 3.2 (算法伪代码);CR-001 (segment_id隔离) | ① 按 group_by(['fund_id', 'segment_id']) 提取极小数组,严禁跨 segment 滑动窗口;② 有效窗口 len < 2 时输出 label = 0;③ 严格使用 np.cumsum 与 np.arange 计算简单平均成本;④ 使用 np.argmax(mask) + 1 计算耗费周数,映射为 150 - weeks;⑤ 性能卡控:全量数据跑批耗时需在可接受范围内(预估 10-20 分钟)。 |
2天 |
| W4 | S4-02 |
样本平衡与落盘机制 实现正负样本的等距抽样限制与长表 Parquet 写入。 |
规约 3.3 (等距抽样/上限50/15);规约 7.4 (严禁Pivot宽表) | ① 正样本(label>0)单基金上限 50 条; ② 负样本(label=0)单基金上限 15 条( 50 * 0.3);③ 强制使用 np.linspace(0, len(samples)-1, N, dtype=int) 进行等距抽样;④ 产出 labels.parquet,Schema 为长表:fund_id, net_value_date, segment_id, label (Int32);⑤ 产出 data/metadata/labels_hash.json。 |
1天 |
| W4 | S4-03 |
7 场景极限防御单测与 CI 闭环 针对规约第九节的 7 个场景编写单测,并补充 segment 边界测试。 |
章程 M3b Done标准;规约第九节;架构推演延伸 | ① 规约 7 个场景单测 100% 全绿,断言精确匹配期望值(如场景 5 必须等于 149); ② 补充单测(PM 强制):构造一只基金包含 2 个 segment 的 Mock 数据,断言 segment 0 末尾的标签计算绝不使用 segment 1 的数据; ③ pytest tests/test_label_generator.py -v 纳入 CI 强阻断红线。 |
2天 |
可优化与可复用逻辑提示¶
1. “有效窗口长度 < 2” 的防御性考量¶
规约伪代码写道:“若有效窗口长度 < 2 → label = 0”。
在实际工程中,如果由于 Step 2 的截断导致某个时间点 t 之后只剩下 1 周的数据(即 t+1 存在,但 t+2 不存在),np.cumsum 依然可以运行(长度为 1 的数组),但这不符合“定投”的语义(至少要投入 2 期才能算成本)。因此,强制拦截 < 2 是极其正确的防御,单测场景 7(建仓期后首周)刚好能覆盖此边界。研发在实现时切勿将判断条件放宽为 < 1。
2. np.argmax(mask) 的陷阱防御¶
NumPy 的 argmax 在 mask 全为 False 时会返回 0。虽然伪代码中用了 any(mask) 做前置判断,但在向量化实现(如使用 np.where 或底层 NumPy 循环)时,极易引入隐式 Bug。
建议实现:不要过度追求炫技的纯矩阵运算,规约已允许“对每只基金处理极小数组”,直接在 map_elements 或 Python UDF 中使用规约给定的标准 if-else 伪代码逻辑是最安全的,性能瓶颈不在 Python 层,而在 Polars 的 group_by 调度。
新增/修改文件清单¶
| 操作 | 文件路径 | 简介与企业级约束 |
|---|---|---|
| 新增 | src/label_generator.py |
核心模块。包含 2 个公开函数:generate_labels(df: pl.DataFrame) -> pl.DataFrame — 主流程(按 segment 隔离 + DCA 计算);balance_samples(df: pl.DataFrame) -> pl.DataFrame — 样本平衡(linspace 抽样)。严禁出现 150、0.20 等魔法数字。 |
| 新增 | tests/test_label_generator.py |
防线级单测。必须包含规约第九节全部 7 个场景的测试用例,输入数据需精心构造净值序列(如场景 5 需构造首周涨幅超 20% 的极端数据),并附加 segment 边界隔离测试。 |
| 修改 | docs/data_contract.md |
新增《标签矩阵接口契约单》:明确 labels.parquet 的 Schema(重点标注包含 segment_id),以及 label 字段的值域约束 [0, 149]、数据类型 Int32。 |
| 修改 | .gitea/workflows/ci.yml |
无需额外修改,已在 Step 3 阶段配置了全局 pytest tests/ 触发逻辑。 |
| 产出 | data/labels/labels.parquet |
运行时产物。长表形态,经过样本平衡后的标签数据集。 |
| 产出 | data/metadata/labels_hash.json |
运行时产物。基于 src/utils/hash.py 计算。 |
下级目录¶
导出 TXT