• PCA原理及代码实现


    PCA(Principle Component Analysis)主成分分析是广泛使用的降维算法,由PCA的名字就可以知道,PCA的主要目标是把数据维度降下来,使得减少数据冗余,降低数据处理带来的计算资源消耗。

    1 PCA原理

    PCA的基本思想是将数据的最主要成分提取出来代替原始数据,也就是将(n)维特征映射到,由(k)维正交特征组成的特征空间就是主成分,这里使用的降维方法就是投影。问题是怎样抽取数据的主要成分,如何衡量投影后保存的信息呢?PCA算法使用方差来度量信息量,为了确保降维后的低维度数据尽可能多的保留原始数据的有效信息,需要使降维后的数据尽可能的分散,从方差角度理解就是保留最大的方差。那么如何得到包含最大差异性的主成分呢?实际上,计算数据矩阵的协方差矩阵,得到协方差矩阵的特征值和特征向量,然后选择特征值最大的(k)个特征对应的特征向量组成的矩阵,就将原始数据矩阵投影到了新的(k)维特征空间,实现了数据特征的降维。下面介绍方差和协方差的计算过程,关于特征值和特征向量的计算查看SVD原理。
    样本均值:$$ar{x}=frac{1}{n}sum_{i=1}^{n}x_{i}$$
    样本方差:$$S{2}=frac{1}{n-1}sum_{i=1}{n}left ( x_{i}-ar{x} ight )^{2}$$
    样本协方差:$$Covleft ( X,Y ight )=Eleft [ left ( X-E(X) ight ) left ( Y-E(Y) ight ) ight ]=frac{1}{n-1}sum_{i=1}^{n}left ( x_{i} -ar{x} ight )left ( y_{i}-ar{y} ight )$$

    2 PCA算法

    输入: (n)维数据集(D=left { x^{(1)},x^{(2)},cdots ,x^{(m)} ight }),降维到(k)
    输出: 降维后的数据集({D}')
    1)对所有的样本数据去中心化:(x^{(i)}=x^{(i)}-frac{1}{m}sum_{j=1}^{m}x^{(j)})
    2)计算数据集的协方差矩阵(XX^{T})
    3)分解协方差矩阵(XX^{T})得到特征值和特征向量
    4)取出最大的(k)个特征值对象的特征向量(left ( w_{1},w_{2},cdots ,w_{k} ight )),将所有特征向量标准化得到特征向量矩阵(W)
    5)对数据集中的每一个样本(x^{(i)}),转换为新的样本(z^{(i)}=W^{T}x^{(i)})
    6)得到输出样本集({D}'=left ( z^{(1)},z^{(2)},cdots ,z^{(m)} ight ))

    3 PCA代码实现

    PCA降维

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    from scipy.io import loadmat
    
    #2D-->1D
    mat = loadmat('D:/Python/Andrew-NG-Meachine-Learning/machine-learning-ex7/ex7/ex7data1.mat')
    X = mat['X']
    print(X.shape)   #(50, 2)
    plt.scatter(X[:,0], X[:,1], facecolors='none', edgecolors='b')
    
    #X 均值归一化
    def featureNormal(X):
        means = X.mean(axis=0)
        stds = X.std(axis=0, ddof=1)
        X_norm = (X - means)/stds
        return X_norm, means, stds
    
    
    #PCA
    def pca(X):
        sigma = (X.T@X)/len(X)
        U, S, V = np.linalg.svd(sigma)
        return U, S, V
    
    
    X_norm, means, stds = featureNormal(X)
    U, S, V = pca(X_norm)
    
    
    print(U[:,0])
    
    
    plt.figure(figsize=(7, 5))
    plt.scatter(X[:,0], X[:,1], facecolors='none', edgecolors='b')
    plt.plot([means[0], means[0]+1.5*S[0]*U[0,0]],
             [means[1], means[1]+1.5*S[0]*U[0,1]],
             c='r', linewidth=3, label='First Principal Component')
    
    
    plt.plot([means[0], means[0]+1.5*S[1]*U[1,0]],
             [means[1], means[1]+1.5*S[1]*U[1,1]],
             c='g', linewidth=3, label='Second Principal Component')  
    plt.grid()
    plt.axis("equal")
    plt.legend()      
    
    
    #Dimensionality Reduction with PCA
    
    
    def projectData(X, U, K):
        Z = X @ U[:,:K]
        return Z
    
    
    Z = projectData(X_norm, U, 1)
    Z[0]
    #print(Z[0]) #[ 1.48127391]
    
    
    #Reconstructing an approximation of the data 重建数据
    def recoverData(Z, U, K):
        X_rec = Z @ U[:,:K].T
        return X_rec
               
    X_rec = recoverData(Z, U, 1)
    X_rec[0]  
    #print(X_rec[0])     #[-1.04741883 -1.04741883]        
    
    
    #Visualizing the projections
    plt.figure(figsize=(7,5))
    plt.axis("equal")
    plot = plt.scatter(X_norm[:,0], X_norm[:,1], s=30, facecolors='none',
                       edgecolors='b',label='Original Data Points')
    
    
    plot = plt.scatter(X_rec[:,0], X_rec[:,1], s=30, facecolors='none',
                       edgecolors='r',label='PCA Reduced Data Points')
    
    
    plt.title("Example Dataset: Reduced Dimension Points Shown", fontsize=14)
    plt.xlabel('x1 [Feature Normalized]',fontsize=14)
    plt.ylabel('x2 [Feature Normalized]', fontsize=14)
    plt.grid(True)
    
    
    for x in range(X_norm.shape[0]):
        plt.plot([X_norm[x,0], X_rec[x,0]],[X_norm[x,1], X_rec[x,1]], 'k--')
        #输入第一项全是X坐标 第二项全是y坐标
    plt.legend()
    

    可视化 PCA将数据从2D减少到1D:


    PCA应用 Face Image Dataset 人脸识别图像上运行PCA 实践中使用PCA减少维度

    大数据集实现PCA

    import numpy as np
    import pandas as pd
    from scipy.io import loadmat
    import matplotlib.pyplot as plt
    
    mat = loadmat('D:/Python/ex7faces.mat')
    X = mat['X']
    print(X.shape)  #(5000, 1024)
    
    
    def displayData(X, row, col):
        fig, axs = plt.subplots(row, col, figsize=(8,8))
        for r in range(row):
            for c in range(col):
                axs[r][c].imshow(X[r*col + c].reshape(32,32).T, cmap = 'Greys_r')
                axs[r][c].set_xticks([])
                axs[r][c].set_yticks([])
                
    displayData(X, 10, 10)
    
    def featureNormalize(X):
        means = X.mean(axis=0)
        stds = X.std(axis=0, ddof=1)
        X_norm = (X - means) / stds
        return X_norm, means, stds
    
    
    def pca(X):
        sigma = (X.T @ X) / len(X)
        U, S, V = np.linalg.svd(sigma)
        
        return U, S, V    
    
    X_norm, means, stds = featureNormalize(X)
    U, S, V = pca(X_norm)    
    #print(U.shape, S.shape)  #(1024, 1024) (1024,)
    
    displayData(U[:,:36].T, 6, 6)
    
    #Dimensionality Reduction
    
    def projectData(X, U, K):
        Z = X @ U[:,:K]
        
        return Z
    
    z = projectData(X_norm, U, K=36)
    def recoverData(Z, U, K):
        X_rec = Z @ U[:,:K].T
        
        return X_rec
    X_rec = recoverData(z, U, K=36)
    displayData(X_rec, 10, 10)
    

    参考: 吴恩达机器学习

  • 相关阅读:
    [C++] 习题 2.18 倒序查找字串
    [C++] 二叉树计算文件单词数
    [C++] 例题 2.7.1 用栈实现简易计算器
    [C++] 非递归实现前中后序遍历二叉树
    [C++] 习题 2.15 实现简单环形队列
    数据结构、算法及应用
    [C++] 习题 2.14 用队列实现桶排序
    svn add 所有文件的命令
    解决Error opening terminal: xterm.的错误
    linux下删除项目中所有.svn的命令
  • 原文地址:https://www.cnblogs.com/eugene0/p/11470225.html
Copyright © 2020-2023  润新知