winsorize 分位可以理解为:

把极端值压到某个分位边界上,而不是直接删除。

它常用于因子研究里处理异常值,防止极端币种把截面排序带偏。


1. 最简单例子

假设某一时点有 10 个币的因子值:

[-3, -2, -1, 0, 1, 2, 3, 4, 5, 100]

这里 100 明显是极端值。

如果做:

winsorize_quantile: [0.05, 0.95]

意思是:

小于 5% 分位的值,压到 5% 分位;
大于 95% 分位的值,压到 95% 分位。

所以 100 不会被删除,而是被压成接近 95% 分位的值。


2. 它和删除异常值不一样

删除异常值

[-3, -2, -1, 0, 1, 2, 3, 4, 5]

直接把 100 扔掉。

Winsorize

[-3, -2, -1, 0, 1, 2, 3, 4, 5, 5附近]

保留这个币,但限制它的极端影响。


3. 为什么截面因子要做 winsorize?

数字货币里经常有:

插针
低流动性拉盘
刚上线暴涨
数据错误
极端成交量
异常 funding

如果不处理,一个币的因子值可能特别夸张:

普通币 BreakoutScore: 0.5, 1.2, 1.8
异常币 BreakoutScore: 50

后续做 zscore 时,这个 50 会把均值和标准差严重拉歪。

结果是:

不是这个币特别强,而是整个截面标准化被污染了。


4. 分位 winsorize 的含义

常见写法:

winsorize_quantile: [0.01, 0.99]

意思是:

低于 1% 分位的值 → 压到 1% 分位
高于 99% 分位的值 → 压到 99% 分位

也可以写:

winsorize_quantile: [0.05, 0.95]

意思是:

低于 5% 分位的值 → 压到 5% 分位
高于 95% 分位的值 → 压到 95% 分位

5. 0.01/0.99 和 0.05/0.95 有什么区别?

设置含义特点
0.01 / 0.99只压最极端 1%更温和,保留更多尾部信息
0.025 / 0.975压两端 2.5%比较常见
0.05 / 0.95压两端 5%更激进,更抗异常
0.10 / 0.90压两端 10%太强,容易损失真实 alpha

6. 在你的截面策略里怎么用?

假设每个 4h 时点,有 100 个币的 BreakoutDistanceAdj

原始值:

[-2.1, -1.5, ..., 0.8, 1.2, 2.0, 15.0]

如果做:

winsorize_quantile: [0.01, 0.99]

那个 15.0 可能被压到 99% 分位,比如 3.2

然后再做:

cross_sectional_zscore

这样得到的 zscore 更稳定。


7. 推荐顺序

截面因子常用流程:

原始因子值
→ winsorize 分位截尾
→ zscore 标准化
→ 多因子加权
→ 排序选头尾

也就是:

先压极端值,再标准化。

不要先 zscore 再 winsorize,除非你明确采用 zscore clipping。


8. 分位 winsorize vs zscore clip

这是两个常见方法。

分位 winsorize

winsorize_quantile: [0.01, 0.99]

按排序位置截尾。

优点:

不依赖均值和标准差
对极端值更稳健
适合肥尾分布

数字货币更推荐这个。


zscore clip

winsorize_zscore: [-5, 5]

意思是:

zscore 小于 -5 的压到 -5
zscore 大于 5 的压到 5

优点:

简单直观
便于多因子统一尺度

缺点:

均值和标准差本身可能已经被极端值污染

9. 实战建议

对数字货币截面因子,初版可以用:

winsorize:
  method: quantile
  lower: 0.01
  upper: 0.99

如果资产池比较小,比如只有 50 个币,可以用更温和的:

winsorize:
  method: quantile
  lower: 0.02
  upper: 0.98

如果是 meme 或极端波动资产池,可以用:

winsorize:
  method: quantile
  lower: 0.05
  upper: 0.95

一句话总结

winsorize 分位就是把因子值两端过于极端的部分压回到指定分位边界,保留样本但限制异常值影响。

在截面因子里,推荐流程是:

原始因子 → 分位 winsorize → 截面 zscore → 排序 → 选头尾