【机器学习实践】主成分分析及相关

主成分分析

原理

通俗地讲,主成分分析(PCA)的原理是数据集旋转(可以是高维)后,使前面的特征对应的值的方差尽量大,只取前面若干个特征达到降维的目的。
方法:求出数据集的散度矩阵,求出它的特征值和特征向量,使用最大的K个(数量自定)特征值对应的特征向量作为基,使用矩阵乘法直接求出数据集变换后的结果。
参考链接
PCA csdn
PCA zhihu
刘建平大佬:SVD 顺便吹一波这位,资料很全推导很详细

作用

PCA和类似的降维算法有很大作用

  1. 数据降维:对高维数据进行降维,减轻机器学习的计算量。
  2. 数据可视化:高维的数据不利于人类的观察,故常常降维到二维或者三维
  3. 图像压缩:将一些眼睛难以察觉的细节去除,常见图像使用PCA的压缩率能够达到50%以上,而不损失大量细节。
  4. 数据降噪,包括图像降噪:噪声数据的方差一般比较小,而信号数据的方差一般比较大,所以PCA能够去除噪声。

python实现

由于PCA算法不依赖于数据集,无需进行训练等,故封装为一个函数。

#pca.py
import numpy as np

def pca(X:np.ndarray, K:int, debug:bool=False)->np.ndarray:
    if np.shape(X)[1] <= K:
        print("[-] dim too low");return
    if K <= 0:
        print("[-] K not valid");return
    # centering the data
    X_avg = np.average(X, axis=0)
    X_centered = X - X_avg
    # covariance matrix
    cov_mat = X_centered @ X_centered.T
    eigval, eigvec = np.linalg.eig(cov_mat)
    eigval_target = eigval[0:K]
    eigvec_target = eigvec[:, 0:K]
    if debug : print(eigval, eigvec)
    if debug : print(np.linalg.norm(np.abs(eigvec_target), axis=0))
    # print(np.linalg.norm(eigvec/np.linalg.norm(eigvec, ord=2, axis=1), ord=2, axis=1))
    # print(eigval_target, eigvec_target)
    return np.array(cov_mat @ eigvec_target, dtype=np.float64)

测试上述代码,使用三维特征的数据集进行测试。

#main.py

import pca
import numpy as np

X = np.array(
[
    [0., 0., 2.],
    [1., 1., 3.],
    [2., 2., 5.],
    [-1., 0., 5.],
    [4., 3., 2.]
])

print(pca.pca(X, 2))

测试结果如下所示

ComplexWarning: Casting complex values to real discards the imaginary part
  return np.array(cov_mat @ eigvec_target, dtype=np.float64)
[[  5.45643859   5.30087165] 
 [  0.66197922   1.3243035 ] 
 [ -2.64791688  -5.29721401] 
 [ 13.72678804  -2.15574602] 
 [-17.19728897   0.82778488]]

可以看到对数据实现了降维

相关算法的应用

对图片进行压缩,原理见刘建平文
其中应用了SVD(奇异值分解),SVD也可以用于PCA降维

#svd.py
def image_compress_pca_svd(X:np.ndarray, K:int, debug:bool=False)->np.ndarray:
    if len(np.shape(X)) != 2 : print("just support 2d data");return
    u, sigma, vh = np.linalg.svd(X)
    if debug:print(np.shape(sigma), "sigma shape")
    if debug:print(np.shape(u), np.shape(sigma), np.shape(vh))
    
    u[:, K:] = 0
    vh[K:, :] = 0

    s = np.zeros(np.shape(X), X.dtype)
    for i in range(K):
        s[i, i] = sigma[i]

    return u @ s @ vh

利用图片进行测试
分别对三个通道进行压缩,之后进行还原,查看效果

#compress.py
import pca
import numpy as np
import matplotlib.pyplot as plt

img = plt.imread("what.jpg")

r = img[:, :, 0]
g = img[:, :, 1]
b = img[:, :, 2]

plt.imshow(img)
plt.show()

r1 = pca.image_compress_pca_svd(r, 400)
g1 = pca.image_compress_pca_svd(g, 400)
b1 = pca.image_compress_pca_svd(b, 400)

img1 = np.ndarray(np.shape(img), img.dtype)
img1[:, :, 0] = r1
img1[:, :, 1] = g1
img1[:, :, 2] = b1

# cv2.imshow("img1", img1)
plt.imshow(img1)
plt.show()

压缩前后图像


【机器学习实践】主成分分析及相关_第1张图片
压缩前

【机器学习实践】主成分分析及相关_第2张图片
压缩后

可以看出基本上还原了图片的效果而没有肉眼可见的损失

总结

  1. PCA降维算法是一种重要的数据处理方法
  2. SVD具有实际用途,是一种朴素的压缩方法,对于第二个维度的压缩,可以作为一种降维方法
  3. 实现起来也真方便:)

你可能感兴趣的:(【机器学习实践】主成分分析及相关)