halo 的技术博客

返回

截面因子研究的日常里,最让人头疼的不是噪声,而是离群点:一只股票突然复牌补跌 30%、某公司业绩暴雷一字跌停、或者某个 tick 错单把收益率顶到 ±40%。标准 PCA 是 L2 平方准则,对极端值几乎零容忍——一个离群点会把整个协方差矩阵、所有主成分、所有载荷都拽偏。结果就是:你以为在提取共同因子,其实在给那几只异常股票做降维。

本文用 numpy 从零实现稳健 PCA(Robust PCA,主成分追踪 PCP):它不试图用平方和最小化去”解释”离群点,而是把观测矩阵显式拆成「低秩矩阵 L(真实因子结构)+ 稀疏矩阵 S(离群点)」,让离群点自己滚进 S,低秩 L 干干净净。在 N=60 股票 / T=250 天 / 3 个真实因子 / 3% 离群污染的合成数据上,稳健 PCA 把低秩恢复相关从标准 PCA 的 0.968 拉回到 0.998,离群点 100% 召回且 0% 误报。附完整 Python 与三张真实计算图。

一、问题:标准 PCA 为什么被离群点拽偏#

标准 PCA 对中心化矩阵 XX 做 SVD,等价于最小化重构误差:

minL XLF2s.t. rank(L)r\min_{L}\ \|X - L\|_F^2 \quad \text{s.t.} \ \mathrm{rank}(L) \le r

这是平方准则。一个值为 40σ 的离群点,贡献的误差是 1600σ21600\,\sigma^2——它会被 SVD 当成”必须解释的重要结构”,于是前几个主成分里塞满了”如何重建那个异常值”的方向,真实因子的载荷被稀释、扭曲。

更糟的是,在截面因子研究里这直接传导到下游:因子暴露(载荷)、风险模型协方差、甚至行业中性化,统统建立在被污染的协方差之上。

先造一份”干净的低秩 + 离群污染”数据,把这件事量化:

二、稳健 PCA:把矩阵拆成 低秩 L + 稀疏 S#

稳健 PCA 的核心思想换一个优化目标。假设观测 MM 由两部分组成:

  • LL低秩矩阵,承载真实的因子结构(被少数公因子驱动);
  • SS稀疏矩阵,承载少数极端离群点(大部分元素是 0)。

优化问题是主成分追踪(Principal Component Pursuit, PCP):

minL,S L+λS1s.t.M=L+S\min_{L,\,S}\ \|L\|_* + \lambda\,\|S\|_1 \quad \text{s.t.} \quad M = L + S

其中 L\|L\|_* 是核范数(奇异值之和,低秩的凸松弛),S1\|S\|_1 是 L1 范数(稀疏的凸松弛),λ=1/max(T,N)\lambda = 1/\sqrt{\max(T,N)} 是理论给出的最优权衡系数。这是一个凸问题,可以用**不精确增广拉格朗日乘子法(inexact ALM)**高效求解——它本质就是交替做”软阈值”:

直觉上:每一步先”把离群点从残差里抠出来压进 S”(L1 软阈值让小数值归零、大数值被削掉尖端),再”把剩下的部分压成低秩 L”(核范数软阈值把微小奇异值归零)。几轮迭代后,S 收敛成稀疏离群图,L 收敛成干净低秩结构。

作为对照,标准 PCA 直接对污染矩阵 SVD,用真实因子数 rr 个主成分重建:

Uc, Dc, VcT = np.linalg.svd(M - M.mean(0), full_matrices=False)
L_pca = (Uc[:, :r] * Dc[:r]) @ VcT[:r, :] + M.mean(0)
python

三、结果:离群点被干净剥离#

稳健 PCA 把极端收益单独剥离到稀疏矩阵 S,低秩 L 不再被污染

三张热力图把整件事讲清楚了:① 是被 3% 离群点污染的观测矩阵 M;② 是人工注入的真实离群点位置(ground truth);③ 是稳健 PCA 从 S 里检出的离群点。S 几乎完美复刻了真实离群点——这正是稳健 PCA 的价值:它不只是”抗干扰地提取因子”,还顺手免费做了一个异常检测

量化对比(合成数据的 ground truth 让我们可以精确打分):

方法低秩恢复相关 corr(L, L_true)离群召回率离群精确率
标准 PCA(污染数据)0.968
稳健 PCA(PCP)0.998100%100%

稳健 PCA 把离群点压进 S 后,低秩 L 与真实因子结构的相关从 0.968 拉回 0.998;而 S 中非零项占比恰好是 3.00%,与真实离群占比完全一致——没有误报、没有漏报。标准 PCA 做不到这点:它没有”离群”这个容器,只能把异常值揉进低秩结构里。

四、为什么标准 PCA 的因子数被”拖散”#

稳健 PCA 的 L 干净地落在 r=3 个因子上;标准 PCA 被离群点拖散

碎石图(各主成分解释方差占比)暴露了根因:稳健 PCA 得到的 L 的奇异值,干净地集中在前 3 个成分上(红虚线标出的真实因子数 r=3r=3),第 4 个之后几乎为 0——和真实生成机制一致。而标准 PCA 在被污染数据上,解释方差被离群点”摊”到了更多主成分上,前 3 个的分量被稀释,因子结构不再清晰可辨。

这意味着:当你用标准 PCA 做风险模型降维、或提取前几个”市场/行业/风格”因子时,如果数据里有未清理的离群点,你提取出来的第 4、第 5 个主成分很可能不是真实因子,而是一堆异常股票的共同噪声。

五、低秩恢复质量:散点对照#

稳健 PCA 还原的低秩因子结构更接近真实(离群点已剥离)

把重建的 L 对每个真实 L_true 画散点:左侧标准 PCA 的散点明显偏离对角线(相关系数仅 0.968,且离群点把整团云拉宽);右侧稳健 PCA 的散点紧贴对角线(0.998)。差的那 3 个百分点,正是离群点污染掉的真实因子信息。

六、工程落地要点(诚实讲清边界)#

  1. 先判断离群占比。PCP 的理论保证要求 SS 足够稀疏(通常 < 10%–15% 的非零比例)。如果一整批股票同时异常(系统性黑天鹅、全市场流动性冻结),那它们不再是”稀疏离群”,而是真实低秩结构的一部分——这时候稳健 PCA 会把它们留在 L 里,这其实是对的,因为它们确实是共同运动。

  2. λ 不是唯一选项1/√max(T,N) 是理论最优,但实践中若你怀疑离群更密,可适度调小 λ(让 S 更”舍得”装离群);若数据很干净只想兜底,可调大 λ。这是唯一需要你拍的旋钮。

  3. 计算成本。PCP 每轮要算一次完整 SVD,对 N×T 大矩阵(比如全 A 股 5000 只 × 2500 天)比标准 PCA 慢一个量级。生产中可用随机 SVD 加速,或对截面分块(行业/板块内)单独跑,块内离群相互独立、效果好且快。

  4. 和”先 winsorize 再 PCA”的差别。Winsorize(把 ±3σ 截尾)也能抗离群,但它是无差别地扭曲所有接近边界的正常值,且截断阈值主观;稳健 PCA 是自适应地只动真正的离群点,正常值原样保留。数据量大、离群稀疏时,稳健 PCA 更干净。

  5. 下游要接 S 还是丢掉 S? 做因子研究通常丢掉 S(用 L 进风险模型/协方差);做异常监控则保留 S(S 非空的位置就是预警名单)。一套分解,两个用途。

七、小结#

标准 PCA 是平方准则的囚徒——一个极端值就能毁掉整个因子结构。稳健 PCA(PCP)用”低秩 + 稀疏”分解,把离群点单独关进 S,让 L 回到真实因子轨道上。本文合成实验里它把低秩恢复相关从 0.968 提到 0.998、离群点 100% 召回零误报;真实截面数据里你会看到类似的干净化效果,尤其是财报季、复牌潮、闪崩日这些离群高发时段。它不是银弹(系统性崩溃它不会误判为离群),但是截面因子清洗里性价比极高的一道前置工序。

完整可复现代码(含三张图的生成)已随本文给出,固定 seed 即可重现全部数值。

稳健 PCA 与异常因子剥离:用主成分把离群股票的影响压下来
https://blog.halo26812.eu.org/blog/robust-pca-outlier-factor
Author halo
Published at 2026年8月30日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨