美文网首页
【2019-11-29】土人说土话-机器学习基础-PCA-SVD

【2019-11-29】土人说土话-机器学习基础-PCA-SVD

作者: 6g3y | 来源:发表于2019-11-29 12:13 被阅读0次

土人说土话系列1-通俗理解-没有公式(建议配合其他文章一起食用)

机器学习-PCA-SVD 如何用土话理解

主要成分分析法是降维比较常用的算法
那么什么是 主要成分分析法(SVD方法) 呢?

先说结论(SVD):

1.第一步旋转矩阵到另外一个坐标系
2.在另外那个坐标系进行放缩(可以放弃放缩不明显的维度,关键)
3.再转回来

无标题.png

完毕!!!
什么?没听懂?

解释一下:

网上常见的图片,原理来的矩阵= 旋转到特征特征向量的位置,放缩,然后再转回来:

v2-8963b9c2c6d65511f302c8d6953f2bf0_1200x500.jpg

旋转

矩阵在线性代数里面代表的是旋转放缩
但是有的放缩会让原来的矩阵的夹角发生变化,例如:


20140524110652218.jpg

那么问题来了,有没有可以做到不会改变夹角的呢?

如果按坐标系的进行放缩,那么是不是就不会改变夹角了呢

扩展一下,就变成找正交的坐标系,也就是正交矩阵了

20140523235902031.jpg
旋转到这变应该是没什么问题了吧
如果还有问题:线性代数的本质 - 系列合集 看一下大神视频

放缩

SVD 的s矩阵是个对角矩阵

|5 0 0|
|0 3 0|
|0 0 1|

什么意思呢,矩阵乘完后就是说对于每个向量都进行了放缩

20140523234733328.jpg
有些放缩是不明显(向量在基的投影很短),这时候就可以把这些放缩给省略掉,达到较少计算的目的
import numpy as np
import matplotlib.pyplot as plt
import os
import imageio

m=np.array(
    [[60, 40, 65],
     [61, 82, 78],
     [69, 95, 75],
     [70, 77, 81],
     [64, 47, 53]]
)

U, S, V = np.linalg.svd(m)

print(U)
print(S*np.eye(3))
print(V)
#旋转
[[-0.35672442 -0.66281097  0.36273147 -0.3393367  -0.43209466] 
 [-0.48152119  0.30125544  0.41771491 -0.38994684  0.59231598]
 [-0.52005108  0.5114878  -0.38602628 -0.18607474 -0.53318571]
 [-0.49538551 -0.02730932  0.23701757  0.83524415 -0.00610569]
 [-0.35358889 -0.45558886 -0.69910408 -0.02314023  0.42205651]]
#放缩
[[266.12913135   0.           0.        ]
 [  0.          29.89261007   0.        ]
 [  0.           0.          12.27669792]]
#旋转
[[-0.54096467 -0.59340339 -0.59601145]
 [-0.5743479   0.7783313  -0.2536235 ]
 [-0.61439541 -0.20511657  0.76186972]]

SVD本质就是用“简单的矩阵”去把“复杂的矩阵”给线性表示出来,而这些“简单的钜阵”,恰好又是其对应特征向量的张量积(或者说外积其自身)的运算结果。
SVD与离散傅里叶变换SVD与泰勒公式 非常相似,可以慢慢体会一下过程

下面我们用直观的方式展示出来:

针对不同的放缩的省略来做的
代码中的r指的是 取r个维度来计算
取不同的对应的值生成的图片如下

原图:


Hydrangeas.jpg

代码


import numpy as np
import matplotlib.pyplot as plt
import os
import imageio

im = plt.imread('Hydrangeas.jpg')
if not os.path.exists('svd'):
    os.mkdir("svd")

for r in range(10, 122 ,10):
    svd_image = []
    for ch in range(3):
        im_ch = im[:, :, ch]
        U, D, V = np.linalg.svd(im_ch)
        imx = np.matmul(np.matmul(U[:, :r], np.diag(D[:r])), V[:r, :])
        for k in imx:
            for m in range(0,k.shape[0]):
                k[m]=max(min(255,k[m]),0)
        svd_image.append(imx.astype('uint8'))
    img = np.stack((svd_image[0], svd_image[1], svd_image[2]), 2)
    imageio.imwrite('svd/%02d.jpg' % r,img)
10.jpg 20.jpg 30.jpg 40.jpg 50.jpg 60.jpg 70.jpg 80.jpg 90.jpg 100.jpg 110.jpg 120.jpg

直观理解PCA

其实就是不操作第三步骤(转回来)

图片片的颜色代表的是放缩的程度,亮度越高越数值越高,越黑代表越没用
如果我们放弃后面黑的其实对图片也没多大效果影响,所以上面的图片取到120左右的时候跟原来图片其实没多大区别(在120列往后其实颜色基本上是黑的了)
如果不旋转回去,那就是PCA降维的结果了
你问我怎么降维?取前面不是黑色的就完事了


import numpy as np
import matplotlib.pyplot as plt
import os
import imageio

im = plt.imread('Hydrangeas.jpg')
if not os.path.exists('svd'):
    os.mkdir("svd")

r=648
svd_image = []
for ch in range(3):
    im_ch = im[:, :, ch]
    U, D, V = np.linalg.svd(im_ch)
    imx = np.matmul(np.matmul(U[:, :r], np.diag(D[:r])), V[:r, :])
    imx =np.matmul(U[:, :r], np.diag(D[:r]))#加了这行 变成降维度操作
    for k in imx:
        for m in range(0,k.shape[0]):
            k[m]=max(min(255,k[m]),0)
    svd_image.append(imx.astype('uint8'))
img = np.stack((svd_image[0], svd_image[1], svd_image[2]), 2)
imageio.imwrite('svd/pca.jpg' ,img)
pca.jpg

如果我们不要前面10个特征向量(中间矩阵的10个参数)会怎么样呢?

如图:图片虽然有细节,但是失去了大部分的颜色,可以说图片失去了主要成分!
反过来说,后面的特征向量虽然不是主要成分,但是也保留了大部分细节,有时候细节才是关键的东西
并不是无脑降维就可以了

10.jpg

反过来说,如果特征值都是一样的,那么就是表达细节了(噪音放大器)

120.jpg

跟下面这个东西很像:

可以吧一个个的指针想想成这的向量,向量越多拟合的越好
12分钟的傅立叶级数动画

相关文章

网友评论

      本文标题:【2019-11-29】土人说土话-机器学习基础-PCA-SVD

      本文链接:https://www.haomeiwen.com/subject/heuwwctx.html