> --max-rows 会注入你正在审计的那种泄漏——一半的"意外结果"是截断
一个数据集审计工具报告某天的标签泄漏,审计不通过。真实原因不是那天的数据,是 冒烟测试用的 --max-rows 开关。
结论先行¶
一个数据集审计工具报告某天的标签泄漏,审计不通过。真实原因不是那天的数据,是
冒烟测试用的 --max-rows 开关。
标签里的漂移校正是一个样本均值统计量。在一个前缀上算,它减掉的是前缀的均值, 把局部趋势原封不动留下来——而局部趋势就是未来信息。同一天的同一个检查:
| 读入范围 | aggressor 侧 AUC | 判定(偏离上限 0.10) |
|---|---|---|
| 整个交易日 | 0.5012 | 通过 |
| 前 200,000 笔 | 0.5897 | 标记为 [near] |
| 前 20,000 笔 | 0.6979 | 拒绝数据集 |
截断越狠,"泄漏"越严重。这个项目的调试清单里把它排在第 5 条,附了一句:
这个项目历史上一半的意外结果都是截断。
为什么¶
--max-rows 这类开关的危险性被系统性低估,因为它看起来是纯粹的量的削减。
但凡是跨样本计算的统计量,前缀都不是缩小版的全体:
- 样本均值 / 中位数的去除:在前缀上留下趋势(这一例)。
- 标准化 / 白化:用前缀的方差,在全量上尺度就错了。
- 分位数阈值:前缀的 p99 不是全体的 p99,见 你的 p90 和工具的 p90 不是一个 p90——差 31%,而且没人报错。
- 去重 / 冲突检测:前缀里看不到后面出现的重复项,于是"干净"。
共同形状是:预处理里有一个全局量,而截断把它换成了一个局部量, 并且换完之后代码路径完全一样,不报任何错。
更危险的是它和审计的方向一致:这里截断制造了泄漏,于是审计器尽职地报了泄漏。 一个尽职的检查器加一个被破坏的预处理,等于一条高可信度的假结论。
这个项目的处理是双管:代码里加 truncated() 标志并打印警告说明这件事,
文档里在每个 --max-rows 出现的地方都标注"见 §6.15——截断会破坏漂移校正并注入泄漏",
CLI 帮助里直接写 --max-rows N truncate each day (SMOKE ONLY)。
怎么用¶
- 把"这个结果是在截断数据上得到的吗"放进每次意外结果的前三个问题里。 排在"代码有 bug 吗"之前——它更常见,也更容易排除。
- 给截断开关加一个会跟着结果一起输出的标志位。 不是只在 stderr 打一行警告(没人看),而是写进结果的 JSON, 让下游能拒绝一份被截断的产物。
- 列出预处理里所有的全局统计量,逐个问"在前缀上这个量还对吗"。 不对的,要么禁止和截断同时使用,要么改成在线/两遍算法。
- 冒烟测试要缩小的是"规模",不是"分布"。 更安全的缩小方式是整段抽样(整天、整个 session),不是取前缀。
- 审计器报出拒绝时,先确认它拿到的是完整输入。 一个正确的检查器在被破坏的输入上会给出自信的错误答案—— 见 一天里五次搞错同一类事:核查步骤本身没被核查。
出处¶
~/Engineering/High-Performance-Hybrid-Trading-System/PROJECT_ENGINEERING_GUIDE.md§6.15 的 Danger 行(三档 AUC 0.5012 / 0.5897 / 0.6979,measured on 2024-01-15)、 §7 配置参考里--max-rows的全局标注、§9 实验清单的 Known anomaly 行、 §15.3 调试顺序第 5 条、§15.2 "First check whether--max-rowsis set."- 同项目
CONTRIBUTING.md第 133 行;修复提交1c4576b(加truncated()标志与警告) - 相关:扩大实验、造 benchmark、造术语、写投稿之前的四道门、事先声明的偏差是限制,事后发现的偏差是借口