Python科学计算(第2版)
上QQ阅读APP看书,第一时间看更新

3.3.4 奇异值分解-SVD

奇异值分解是线性代数中一种重要的矩阵分解,在信号处理、统计学等领域都有重要应用。假设M是一个m×n阶矩阵,存在一个分解使得:M =UΣV*。其中U是m×m阶酉矩阵;Σ是半正定m×n阶对角矩阵;而V*,即V的共轭转置,是n×n阶酉矩阵。这样的分解就称作M的奇异值分解。Σ对角线上的元素为M的奇异值。通常奇异值按照从大到小的顺序排列。

奇异值的数学描述读起来有些难懂,让我们通过一个实例说明奇异值分解的用途。下面的例子对一幅灰度图像进行奇异值分解,然后从三个分解矩阵中提取奇异值较大的部分数据还原原始图像。首先读入一幅图像,并通过其红绿蓝三个通道计算灰度图像img,图像的宽为375个像素、高为505个像素。

    r, g, b = np.rollaxis(pl.imread("vinci_target.png"), 2).astype(float)
    img = 0.2989 *
 r + 0.5870 *
 g + 0.1140 *
 b
    img.shape
    (505, 375)

调用scipy.linalg.svd( )对图像矩阵进行奇异值分解,得到三个分解部分:

●U:对应于公式中的U

●s:对应于公式中的Σ,由于它是一个对角矩阵,只有对角线上的元素非零,因此s是一个一维数组,保存对角线上的非零元素。

●Vh:对应于公式中的V *

下面的程序查看这三个数组的形状:

    U, s, Vh = linalg.svd(img)
    U.shape       s.shape      Vh.shape 
    ----------     -------     ----------
    (505, 505)     (375,)      (375, 375)

s中的每个值与Vh的行向量以及U中的列向量对应,默认按照从大到小的顺序排列,它表示与其对应的向量的重要性。由图3-9可知s中的奇异值大小差别很大,注意Y轴是对数坐标系。

图3-9 按从大到小排列的奇异值

    pl.semilogy(s, lw=3)

下面的composite( )选择U和Vh中的前n个向量重新合成矩阵,当用上所有向量时,重新合成的矩阵和原始矩阵相同:

    def composite(U, s, Vh, n):
        return np.dot(U[:, :n], s[:n, np.newaxis] *
 Vh[:n, :])
    
    print np.allclose(img, composite(U, s, Vh, len(s)))
    True

下面演示选择前10个、20个以及50个向量合成时的效果,如图3-10所示,可以看到使用的向量越多,结果就越接近原始图像:

图3-10 原始图像以及使用10个、20个、50个向量合成的图像(从左到右)

    img10 = composite(U, s, Vh, 10)
    img20 = composite(U, s, Vh, 20)
    img50 = composite(U, s, Vh, 50)
    
    %array_image img; img10; img20; img50