halo 的技术博客

返回

先说结论:PCA 能压缩,但压出来的成分你读不懂;NMF 牺牲一点数值最优性,换来一组能当『主题构成』读的基。 差别的根源只有一条约束——非负。PCA 的载荷有正有负(本文实验里 58.3% 的 PCA 载荷是负的),所以 PC1 可能是「+0.4 科技 −0.3 消费 +0.2 能源」,这种带减号的组合在物理上没有「构成」的意义。NMF 强制 W、H 全非负,每个基就是一个可加的时间模式,每个资产是这些基的非负叠加,H 的每一列直接读作「这个资产由各主题占多少」。

非负矩阵分解 NMF:把资产收益矩阵压成可解释的基与权重

一、问题:降维不等于可解释#

量化里降维几乎是反射动作——几百只资产、几十个因子,先 PCA 抽几个主成分再说。但 PCA 解决的是「用最少的正交方向解释最多方差」,它从没答应过你「这些方向能读懂」。

矩阵分解的通用形式是把一个 T × N 的数据矩阵 V(T 个时间点、N 个资产)近似成两个小矩阵的乘积:

V  ≈  W · H
(T×N)  (T×K) (K×N)
plaintext
  • WT × K:K 个基(成分)随时间的激活强度
  • HK × N:每个资产在这 K 个基上的权重

PCA、ICA、NMF 都是这个框架,区别只在对 W、H 加什么约束

方法约束成分含义
PCAW 列正交、方差递减方差最大的正交方向(可正可负)
ICA各成分统计独立相互独立的源(可正可负,符号/幅度不定)
NMFW ≥ 0 且 H ≥ 0可加的『部分/主题』(全非负)

NMF 的杀手锏就是最后那行:非负 = 只能相加、不能相减。这逼着模型学出「构成型」的表示——就像把一张脸拆成鼻子、眼睛、嘴(可加的部件),而不是拆成一堆有正有负的鬼影(PCA 的特征脸)。

二、合成实验:3 个主题,12 个资产#

为了能验证还原效果,我构造一个「真相已知」的场景:3 个潜在时间主题(各自是非负的高斯脉冲叠加,模拟事件驱动的活跃度爆发),12 个资产各自主要挂在一个主题上、带一点跨主题泄漏。

注意最后一行的 np.maximum(..., 0):NMF 只接受非负输入。这里数据天然是「活跃度 / 成交强度 / 换手率」这类恒非负的量,正好适配。收益率有正有负,不能直接喂 NMF——这是第一个必须警惕的坑,后面细说。

三、算法:Lee-Seung 乘法更新#

NMF 最经典的求解器是 Lee & Seung 的乘法更新(multiplicative update)。它的美妙之处在于:只要初值非负,每一步更新都是「乘以一个非负比值」,所以 W、H 永远保持非负,不需要投影、不需要裁剪。

目标是最小化 Frobenius 范数 ‖V − WH‖²,更新规则:

def nmf(V, K, iters=400, seed=0):
    r = np.random.default_rng(seed)
    W = r.uniform(0.1, 1.0, size=(V.shape[0], K))
    H = r.uniform(0.1, 1.0, size=(K, V.shape[1]))
    eps = 1e-9
    errs = []
    for _ in range(iters):
        H *= (W.T @ V) / (W.T @ W @ H + eps)      # 更新 H
        W *= (V @ H.T) / (W @ H @ H.T + eps)      # 更新 W
        errs.append(np.linalg.norm(V - W @ H))
    return W, H, errs

W, H, errs = nmf(V, K=3, iters=400, seed=3)
python

分子分母都是非负矩阵,比值非负,乘上原本非负的 W/H 依然非负——约束天然满足。这个更新可以证明让目标函数单调不增(不会变大)。

乘法更新误差单调下降,秩选择的肘部

左图:400 次迭代重构误差单调下降,最终收敛到 ‖V − WH‖_F = 2.536。右图后面讲秩选择。

四、结果:基被干净还原#

NMF 分解出来后有个恼人的问题——成分顺序和缩放是不定的W·H = (WD)·(D⁻¹H) 对任意非负对角阵 D 都成立,所以学出来的「基 1」不一定对应真实的「主题 1」。要跟真相对比,必须先按相关性把成分排列对齐、再归一化缩放:

from itertools import permutations
best = None
for p in permutations(range(K)):
    c = sum(np.corrcoef(H[p[i]], H_true[i])[0,1] for i in range(K))
    if best is None or c > best[0]:
        best = (c, p)
perm = best[1]
Hn = H[list(perm)]; Wn = W[:, list(perm)]
for k in range(K):                       # 归一化:H 行和为 1
    s = Hn[k].sum() + 1e-9
    Hn[k] /= s; Wn[:,k] *= s
python

对齐 + 归一化之后,还原质量很硬:

  • 时间基激活 W 与真实基相关:0.918 / 0.834 / 0.821
  • 权重矩阵 H 与真实权重相关:0.845 / 0.905 / 0.804

NMF 还原的时间基激活

灰线是真实主题激活,彩线是 NMF 还原——两次爆发的位置、相对高度都对上了。这意味着 NMF 不只是压缩,它真的把「哪个主题在什么时候活跃」拆了出来。

五、真正的价值:可解释性#

这才是 NMF 值钱的地方。把 NMF 的权重矩阵 H 和 PCA 的载荷并排放:

NMF 权重全非负 vs PCA 载荷有正有负

左边 NMF 的 H:全是非负数,每一列(资产)读起来就是「这个资产 = 基1 占 x + 基2 占 y + 基3 占 z」,像一张成分表。资产 0-3 明显主要挂基 1,资产 4-7 挂基 2,资产 8-11 挂基 3——聚类结构一目了然。

右边 PCA 的载荷:58.3% 是负数。PC1 上某个资产是 +0.41、另一个是 −0.33,你怎么解释「这个资产在主成分 1 上是负构成」?在方差分解的语境里这没问题,但在「我想知道这个组合由哪些主题构成」的语境里,负载荷是灾难。

一句话:PCA 回答『方差在哪』,NMF 回答『构成是什么』。 做因子聚类、板块归因、组合主题拆解时,你要的是后者。

六、秩选择:误差肘部#

K(成分数)怎么定?扫一遍,看重构误差的肘部:

ranks = range(1, 8); rec = []
for kk in ranks:
    _, _, e = nmf(V, kk, iters=250, seed=5)
    rec.append(e[-1])
python

实测最终误差随 K 变化:

K1234567
误差17.4810.982.522.512.302.262.14

从 K=2 到 K=3 误差断崖式下跌(10.98 → 2.52),K=3 之后几乎拐平——这个肘部精确对上了真实秩。右图那条曲线就是它。这是实践中定 K 的主力方法(配合领域先验)。

已知偏差(Limitations and Bias)#

  • 合成数据是理想剧本:真实数据里主题不会这么干净可分,泄漏更严重、主题数未知、还可能随时间漂移。这里的相关 0.8+ 是在「真相已知且噪声很小」下取得的,实盘还原度会明显下降。
  • NMF 无全局唯一解:目标函数非凸,不同随机初值收敛到不同局部最优。本文用固定 seed 报告单次结果,稳健做法是多起点跑、按重构误差挑最好的,并检查基的稳定性。
  • 成分顺序/缩放不定W·H = (WD)(D⁻¹H) 的等价性意味着「基 1」是谁纯属随机,必须靠对齐才能和先验对照——这不是 bug,是 NMF 的内禀不定性。
  • 秩肘部有时不干净:本例 K=3 之后误差没有完全平(还在缓慢降),真实数据肘部往往更模糊,单看误差容易过拟合,需结合成分可解释性和稳定性交叉判断。

结果解读(Result Interpretation)#

为什么 NMF 在量化里被低估又被误用。 它的定位很清楚:当你的数据天然非负(成交量、换手率、波动强度、情绪计数、持仓占比),并且你要的是「构成/主题」而非「方差方向」时,NMF 几乎是唯一给你可加解释的降维。本文实验里它把 3 个主题干净拆开、权重读起来像占比表,这是 PCA 给不了的。

但它的适用边界很窄。 三个最常见的翻车点:其一,直接喂收益率——收益有负值,NMF 要么报错要么逼你做 max(0) 截断,等于把所有下跌信息扔掉,分解出的「主题」失去意义;正确做法是分解非负派生量(如 |收益|、成交额、波动率),或改用允许负值的 PCA/ICA。其二,把基当成真实因子——NMF 找的是「能重构数据的非负基」,不保证有金融含义,本文能对上真相是因为数据就是这么造的,真实数据里一个基可能混了两个概念。其三,唯一解幻觉——非凸 + 缩放不定,别人复现你的「基 2」很可能是你的「基 1」,报告结果必须说明初值、迭代、对齐方式。

和 PCA/ICA 的分工。 要方差压缩、要正交、数据有正负 → PCA;要还原相互独立的驱动源、不在乎符号 → ICA;数据非负、要可加的构成解释 → NMF。三者不是替代关系,是针对不同问题的三把刀。用错场景,再干净的还原也是错的。

非负矩阵分解 NMF:把资产收益矩阵压成可解释的基与权重
https://blog.halo26812.eu.org/blog/nmf-asset-decomposition
Author halo
Published at 2026年7月24日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨