幂法是通过迭代来计算矩阵的主特征值(按模最大的特征值)与其对应特征向量的方法,适合于用于大型稀疏矩阵。
幂法定义
设$A = (a_{ij})\in R^{n\times n}$,其特征值为$\lambda_i$,对应特征向量$x_i(i=1,...,n)$,即$Ax_i = \lambda_i x_i(i=1,...,n)$,且$\{x_1,...,x_n\}$线性无关。
任取一个非零向量$v_0\in R^{n}$,且$v_0\ne 0$,构造一个关于矩阵$A$的乘幂的向量序列:
$v_k = Av_{k-1}=A^2v_{k-2}=A^3v_{k-3}=...=A^kv_{0}$
称$v_k$为迭代向量。
设特征值$\lambda_i$的前$r$个为绝对值最大的特征值(ppt中分为$\lambda_1$强占优和非强占优,感觉没必要),即有:
$|\lambda_1|=|\lambda_2|=...=|\lambda_r|>|\lambda_{r+1}|\ge...\ge|\lambda_n|$
由于$\{x_1,...,x_n\}$ 线性无关,所以构成$R^n$的一个基,于是$v_0$能被表达为:
$v_0=\sum\limits_{i=1}^{n}\alpha_i x_i$(且设$\alpha_1...\alpha_r$非全零)
由$Ax_i = \lambda_i x_i$:
$v_k = Av_{k-1}=...=A^kv_{0}=\sum\limits_{i=1}^{n}A^k\alpha_i x_i=\sum\limits_{i=1}^{n}\lambda_i^k\alpha_i x_i=\lambda_1^k(\sum\limits_{i=1}^{r}\alpha_ix_i+\varepsilon_k)$
其中:
$\varepsilon_k = \sum\limits_{i=r+1}^{n}(\frac{\lambda_i}{\lambda_1})^k\alpha_ix_i$
因为$\lambda_1$最大,所以有$|\frac{\lambda_i}{\lambda_1}|<1 (i=r+1,...,n)$,从而有:
$\lim\limits_{k\to \infty}(\frac{\lambda_i}{\lambda_1})^k=0 (i=r+1,...,n)$
所以有:
$\lim\limits_{k\to \infty}\varepsilon_k = 0$
$\lim\limits_{k\to \infty}v_k = \lim\limits_{k\to \infty}\lambda_1^k(\sum\limits_{i=1}^{r}\alpha_ix_i+\varepsilon_k) = \lim\limits_{k\to \infty}\lambda_1^k(\sum\limits_{i=1}^{r}\alpha_ix_i)$
因为在上式中$(\sum\limits_{i=1}^{r}\alpha_ix_i)$是固定项,可以看出,迭代到后期,$v_{k+1}$和$v_k$的各个元素有固定比值$\lambda_1$,即:
$\lim\limits_{k\to \infty}\frac{(v_{k+1})_i}{(v_{k})_i} = \lambda_1$
这样,收敛到主特征值后,还可另外计算它对应的一个特征向量(其实就是构成$v_0$的前$r$项之和,而且只能算一个):
$\lim\limits_{k\to \infty}\frac{v_{k}}{\lambda_1^k} = \sum\limits_{i=1}^{r}\alpha_ix_i$
其中收敛速度由比值$|\frac{\lambda_{r+1}}{\lambda_1}|$决定,越小收敛越快。
幂法改进
以上定义中,随着不断的迭代,如果$|\lambda_1|>1$,$v_k$会无限大;如果$|\lambda_1|<1$,$v_k$则会趋于0。在计算机中就会导致溢出而出错。当然如果$|\frac{\lambda_{r+1}}{\lambda_1}|$很小,使得$\varepsilon_k$能快速收敛为0,并且$|\lambda_1|$不会太大或太小以至于在$\varepsilon_k$收敛前$v_k$就溢出了,那用上述方法就行了。
但是通常不会碰到那么好的运气,所以就在每次迭代的时候就要对$v_k$进行“规范化”,防止它溢出。规范化就是将向量除以一个标量,使向量的长度为1,而向量的长度有多种度量法,比如$||\cdot||_2、||\cdot||_\infty$等。一般使用$||\cdot||_\infty$,就是向量各个分量的绝对值的最大值(用别的也一样,但是这个复杂度最小,计算机最好算)。
为了便于理解,将一次迭代分为两步,一步乘矩阵$A$,一步除以向量长度进行规范化:
迭代序号 | 乘$A$($v_i$) | 规范化($u_i$) |
初始化 | 随机取$v_0=\sum\limits_{i=0}^{n}\alpha_ix_i$ | $u_0=\frac{v_0}{||v_0||}$ |
1 | $v_1=Au_0=\frac{Av_0}{\left\|v_0\right\|}$ | $u_1=\frac{v_1}{||v_1||}=\frac{\frac{Av_0}{\left\|v_0\right\|}}{\left\|\frac{Av_0}{\left\|v_0\right\|}\right\|}=\frac{Av_0}{\left\|Av_0\right\|}$ |
2 | $v_2=Au_1=\frac{A^2v_0}{\left\|Av_0\right\|}$ | $u_2=\frac{v_2}{||v_2||}=\frac{\frac{A^2v_0}{\left\|Av_0\right\|}}{\left\|\frac{A^2v_0}{\left\|Av_0\right\|}\right\|}=\frac{A^2v_0}{\left\|A^2v_0\right\|}$ |
... | ... | ... |
k | $v_k=Au_{k-1}=\frac{A^kv_0}{\left\|A^{k-1}v_0\right\|}$ | $u_k=\frac{v_k}{||v_k||}=\frac{\frac{A^kv_0}{\left\|A^{k-1}v_0\right\|}}{\left\|\frac{A^kv_0}{\left\|A^{k-1}v_0\right\|}\right\|}=\frac{A^kv_0}{\left\|A^kv_0\right\|}$ |
... | ... | ... |
根据迭代,以下计算主特征值和对应的特征向量。
主特征值
对于向量序列${v_k}$:
$v_k=\frac{A^kv_0}{\left\|A^{k-1}v_0\right\|}=\frac{\lambda_1^k(\sum\limits_{i=1}^{r}\alpha_ix_i+\varepsilon_k)}{\left\|\lambda_1^{k-1}(\sum\limits_{i=1}^{r}\alpha_ix_i+\varepsilon_{k-1})\right\|}$
对$v_k$取范数:
$||v_k||=\frac{\left\|\lambda_1^k(\sum\limits_{i=1}^{r}\alpha_ix_i+\varepsilon_k)\right\|}{\left\|\lambda_1^{k-1}(\sum\limits_{i=1}^{r}\alpha_ix_i+\varepsilon_{k-1})\right\|}=|\lambda_1|\frac{\left\|\sum\limits_{i=1}^{r}\alpha_ix_i+\varepsilon_k\right\|}{\left\|\sum\limits_{i=1}^{r}\alpha_ix_i+\varepsilon_{k-1}\right\|}\to\left|\lambda_1\right|, (k\to\infty)$
注意!在计算机中并不是直接通过这个极限$k\to\infty$来计算,而是通过上面表格的迭代来实现$k\to\infty$,由于每一步的“规范化”,才能使得计算成为可能。而且如果直接用这个极限算的话就和前面的没区别了,“规范化”的优势没有用起来。
另外,因为算范数的时候是先取向量分量的绝对值再算的,所以改进后的方法计算出来的主特征值不可避免带有绝对值,因此特征值的符号还要再判断一下(下面判断)。而改进之前的是不带的(因为没有计算范数进行规范化),如果符合条件,改进之前的也可一试。
主特征值对应的一个特征向量
观察向量$u_k$:
$u_k=\frac{A^kv_0}{\left\|A^kv_0\right\|}=\frac{\lambda_1^k(\sum\limits_{i=1}^{r}\alpha_ix_i+\varepsilon_k)}{\left\|\lambda_1^{k}(\sum\limits_{i=1}^{r}\alpha_ix_i+\varepsilon_{k})\right\|}\to{\rm sign}(\lambda_1^k)\frac{\sum\limits_{i=1}^{r}\alpha_ix_i}{\left\|\sum\limits_{i=1}^{r}\alpha_ix_i\right\|},(k\to\infty)$
如上,通过$u_k$可获得一个单位化的主特征值特征向量。因为还乘上了$\lambda_1^k$的符号,所以向量各个分量的符号和迭代的次数$k$有关。当$k$足够大(使迭代收敛),连续两次迭代,$u_k$的分量的符号不变时,则可以判断主特征值符号为正,否则为负,从而解决了上面主特征值符号未知的问题。
另外,求出的单位特征向量(如果用L2范数)是主特征值的所有不相关特征向量的线性组合,与设置的$v_0$有关。当然如果主特征值的没有重根,且$\alpha_1$不为零(为零的话就迭代出第二大的特征值),规范化后得出的都是同一个特征向量(如果特征值为负,符号可能随迭代次数改变)。
Python代码
1 import numpy as np 2 3 #矩阵A 4 A = np.matrix( 5 [[-5.6,2.,0.], 6 [3.,-1.,1.], 7 [0.,1.,3.]]) 8 L0=2#范数类型 9 v = np.matrix([[-2.],[-7.],[1.]])#v0 10 u = v/(np.linalg.norm(v,L0))#u0 11 12 #迭代函数 13 def iterate_fun(A,u,final,L): 14 i=0 15 while i<final: 16 v = A*u 17 u = v/(np.linalg.norm(v,L)) 18 i=i+1 19 print("幂法特征值:") 20 print(np.linalg.norm(v,L)) 21 print("numpy特征值:") 22 print(np.linalg.eig(A)[0]) 23 print("幂法特征向量:") 24 print(u) 25 print("numpy特征向量:") 26 print(np.linalg.eig(A)[1]) 27 28 iterate_fun(A,u,1010,L0)
结果截图:
主特征值与numpy算出来绝对值一致。这里用的是L2范数,且主特征值无重根,所以计算出来的特征向量单位化后和numpy主特征值对应的向量除符号外相同。