SVD原理
SVD分解或者说极大协方差分析方法,主要针对于一般实矩阵的SVD运算。其中,一般实矩阵指行数和列数可以不等的实元素矩阵。
如下所示,假设 C C C 为 m × n m \times n m×n阶矩阵,则存在一个 m × m m \times m m×m阶的列正交矩阵 U U U 和 n × n n \times n n×n阶的列正交矩阵 V V V,使得:
C = U ( Σ 0 0 0 ) V T \mathbf{C}=\mathbf{U} \begin{pmatrix} \mathbf{\Sigma} & \mathbf{0} \\ \mathbf{0} & \mathbf{0} \end{pmatrix}\mathbf{V}^\mathbf{T} C=U(Σ000)VT
成立。其中,
Σ
\Sigma
Σ
是
r
r
r 阶对角矩阵或者可以写成
Σ
=
d
i
a
g
(
σ
1
,
σ
2
,
σ
3
,
.
.
.
,
σ
r
)
\Sigma=diag(\sigma_1,\sigma_2,\sigma_3,...,\sigma_r)
Σ=diag(σ1,σ2,σ3,...,σr),
(
r
⩽
min
{
m
,
n
}
)
(r\leqslant\min\{m,n\})
(r⩽min{m,n}),且
σ
1
⩾
σ
2
⩾
⋯
⩾
σ
r
>
0
\sigma_1\geqslant\sigma_2\geqslant\cdots\geqslant\sigma_r>0
σ1⩾σ2⩾⋯⩾σr>0。
以上称为实一般矩阵 C C C的奇异值分解, σ i ( i = 1 , 2 , 3 , . . . , r ) \sigma_i(i=1,2,3,...,r) σi(i=1,2,3,...,r)称为 C C C的奇异值, U U U的列向量称为左奇异向量, V V V的列向量称为右奇异向量。
对于正交矩阵,总是使空间旋转或反射,而对角矩阵总是使空间缩放。
本质上,对于一个矩阵 C C C的奇异值分解,实际转换为求取以上两个方阵 U U U和 V V V的特征值和特征向量的问题,特征值的正的平方根就是奇异值(对角矩阵 Σ \Sigma Σ的对角线元素),特征值对应的特征向量分别是左奇向量和右奇向量,下面会介绍相关的计算。
下面是SVD的一个分解示意图:
计算步骤
以下 C T C^T CT表示 C C C的转置
1、计算左奇异向量( U U U)。它等于 C C T CC^T CCT 的特征向量。
2、计算右奇异向量( V V V)。它等于 $C^TC $的特征向量。
3、计算 C C T CC^T CCT 或 C T C C^TC CTC 的特征值的平方根。
以上计算过程可以在numpy函数中封装,可以直接进行调用:numpy.linalg.svd(a, full_matrices=True, compute_uv=True, hermitian=False)
当 a 是一个 2D 数组时, 且 full_matrices=False
,然后将其分解为 u @ np.diag(s) @ vh = (u * s) @ vh
,其中 u
和 vh
的 Hermitian 转置是具有正交列的二维数组,s
是 a 的奇异值的一维数组。
np.diag()
表示提取对角线或构建对角数组。其中,返回的
U
U
U是左奇异向量,
V
h
Vh
Vh是右奇异向量,
s
s
s是奇异值
GitHub上有博主提供了一个计算演示代码:
- https://github.com/longhongc/SVD-python-implementation/blob/main/my_SVD.ipynb
SVD与EOF的关系
EOF实际上是SVD的特殊情况,对于SVD针对的是两个物理时空场,而EOF是一个物理时空场,如m表示空间点,n表示时间点,那么
利用计算得到的奇异向量和对应的时间系数可以恢复原来的数据,这里 X X X表示原始数据,即
X
=
U
T
X = UT
X=UT
那么,同样的道理,根据原始数据和奇异向量也可以用来得到对应的时间序列,即
T = U T X T=U^TX T=UTX
SVD在气象海洋中的应用
在实际使用SVD分解在气象海洋数据时,步骤相对上述的计算有完善一点,具体为:
1、数据的预处理,需要输入两个距平变量场或者标准化变量场的交叉协方差矩阵A
2、计算A矩阵的左奇异向量U,即主成分模态,列向量对应EOF空间模态
3、计算A矩阵的右奇异向量V
4、根据左变量场及左奇异向量计算时间系数矩阵,即 P C = U X PC=U^X PC=UX,这里 X X X表示原始场
5、计算每对奇异向量的方程贡献和累计方差贡献
6、显著性检验
SVD的物理意义
SVD在气象、海洋实际应用中往往是对两个物理量场做分解的。其原理是要求两个场的展开系数的协方差最大。比如对某海域的海表温度(SST)和海表气压(SLP)做SVD分析,是为了提取出这两个变量之间相互耦合(协方差矩阵)的最重要的空间模态和时间演变信息。
其中的空间模态就是SVD得到的奇异向量(左右奇异向量分别对应SST和SLP),它们有各自的时间系数表征了时间演变特征。注意SVD方法输入的两个变量场的空间点数可以不相同(m1, m2),但是两个变量的时间长度必须相同(n)
python中的svd分解
在python中,不仅numpy提供了svd函数,scipy也提供了可调用的函数:scipy.linalg.svd
和scipy.sparse.linalg.svds
.
以上scipy提高的函数中,当输入矩阵是密集矩阵且需要所有奇异值时,第一种方法通常更有效。而当输入矩阵 X 是稀疏矩阵或只需要最大奇异值时,第二种方法通常非常有效。
而scipy.linalg.svd
快速的原因是以分配大量内存用于临时计算为代价,随维数的增加而变化。
应用个例
对于热带垂直速度 ω \omega ω,可以通过svd将其它被分解为经验垂直结构函数(EOF)及其相关的主成分(PC),代表空间和时间变率。
其中,第一模态和第二模态分别可以表示第一斜压和第二斜压模,第一斜压模态与深对流云有关,第二斜压模态与层状云有关。
参考
-
https://mp.weixin.qq.com/s/SBwRI1vg3h-wqjphMsHbGA
-
https://numpy.org/doc/2.2/reference/generated/numpy.linalg.svd.html
-
https://fa.bianp.net/blog/2012/singular-value-decomposition-in-scipy/
-
https://github.com/longhongc/SVD-python-implementation
-
https://pyoceans.github.io/sea-py/
-
https://github.com/mathildejutras/mtm-svd-python/tree/master
-
上课课件