美文网首页
机器学习实战-12-PCA主成分分析

机器学习实战-12-PCA主成分分析

作者: nobodyyang | 来源:发表于2019-01-11 17:15 被阅读0次

    一、降维介绍

    降维是对数据高维度特征的一种预处理方法。降维是将高维度的数据保留下最重要的一些特征,去除噪声和不重要的特征,从而实现提升数据处理速度的目的。在实际的生产和应用中,降维在一定的信息损失范围内,可以为我们节省大量的时间和成本。降维也成为了应用非常广泛的数据预处理方法。
    降维具有如下一些优点:

    • 使得数据集更易使用
    • 降低算法的计算开销
    • 去除噪声
    • 使得结果容易理解

    二、降维技术

    2.1. 主成分分析(Principal Component Analysis,PCA)
    在PCA中数据从原来的坐标系转换到新的坐标系,系坐标系的选择是由数据本身决定的。第一个新坐标轴选择的是原始数据中方差最大的方向,第二个新坐标轴的选择是和第一个坐标轴正交且具有最大方差的方向。该过程一直重复,重复次数为原始数据中特征的数目。我们会发现,大部分方差都包含在最前面的几个新坐标轴中。因此,我们可以忽略余下的坐标轴,即对数据进行了降维处理。

    2.2. 因子分析(Factor Analysis)
    在因子分析中,我们假设在观察数据的生成中有一些观察不到的隐变量(latent variable)。假设观察数据是这些隐变量和默写噪声的线性组合。那么隐变量的数据可能比观察数据的数目少,也就是说通过找到隐变量就可以实现数据的降维。

    2.3.独立成分分析(Independent Component Analysis,ICA)
    ICA假设数据是从N个数据源生成的。假设数据为多个数据源的混合观察结果,这些数据源之间在统计上是相互独立的。而在PCA中只假设数据是不相关的。同因子分析一样,如果数据源的数目少于观察数据的数目,则可以实现降维过程。

    三、PCA实现

    3.1 移动坐标轴
    考虑下图中的大量数据点。如果要求画出一条直线,这条线要尽可能覆盖这些点,那么最长的线可能是哪条?从图中看出,3条直线中B最长。

    在PCA中,我们对数据的坐标进行了旋转,该旋转的过程取决于数据的本身。第一条坐标轴旋转到覆盖数据的最大方差位置,即图中的直线B。数据的最大方差给出了数据的最重要的信息。在选择了覆盖数据最大差异性的坐标轴之后,我们选择了第二条坐标轴。假如该坐标轴与第一条坐标轴垂直,它就是覆盖数据次大差异性的坐标轴。这里更严谨的说法就是正交(orthogonal)。当然,在二维平面下,垂直和正交是一回事。在图中,直线C就是第二条坐标轴。

    通过PCA进行降维处理就可以同时获得SVM和决策树的优点:一方面,得到了和决策树一样简单的分类器,同时分类间隔和SVM — 样好。考察下面的图,其中的数据来自于上面的图并经PCA转换之后绘制而成的。如果仅使用原始数据,那么这里的间隔会比决策树的间隔更大。另外,由于只需要考虑一维信息,因此数据就可以通过比SVM简单得多的很容易采用的规则进行区分。

    在上图中,我们只需要一维信息即可,因为另一维信息只是对分类缺乏贡献的噪声数据。在二维平面下,这一点看上去微不足道,但是如果在高维空间下则意义重大。

    3.2 在NumPy中实现 PCA
    全文代码

    from numpy import *
    import matplotlib.pyplot as plt
    
    
    def load_data_set(file_name, delim='\t'):
        """
            Function:
                簇绘图函数
            Parameters:
                file_name - 文件名
                delim - 分隔符,默认是tab键'\t'
            Returns:
                mat(dat_arr) - 数据矩阵
            Modify:
                2019-1-10
        """
        fr = open(file_name)
        string_arr = [line.strip().split(delim) for line in fr.readlines()]
        dat_arr = [list(map(float, line)) for line in string_arr]
        return mat(dat_arr)
    
    
    def pca(data_mat, top_n_feat=9999999):
        """
            Function:
                降维函数
            Parameters:
                data_mat - 数据集
                top_n_feat - N个特征
            Returns:
                low_d_data_mat - 降维后的N维数据矩阵
                recon_mat - 重构原数据矩阵
            Modify:
                2019-1-10
        """
        mean_vals = mean(data_mat, axis=0)
        mean_removed = data_mat - mean_vals
        # 计算协方差矩阵
        cov_mat = cov(mean_removed, rowvar=0)
        # eig()计算特征值
        eig_vals, eig_vects = linalg.eig(mat(cov_mat))
        # 对特征值从小到大排序,返回索引
        eig_val_ind = argsort(eig_vals)
        # 从倒数第一个(也就是最大的)往左取N个值
        eig_val_ind = eig_val_ind[: -(top_n_feat + 1): -1]
        # 将特征值最大的N个特征值对应索引的特征向量提取出来,组成压缩矩阵
        red_eig_vects = eig_vects[:, eig_val_ind]
        # 将去除均值后的数据矩阵*压缩矩阵,转换到新的空间,使维度降低为N
        low_d_data_mat = mean_removed * red_eig_vects
        # 利用降维后的矩阵反构出原数据矩阵(用作测试,可跟未压缩的原矩阵比对)
        recon_mat = (low_d_data_mat * red_eig_vects.T) + mean_vals
        return low_d_data_mat, recon_mat
    
    
    def plot_pca(data_mat, recon_mat):
        """
            Function:
                绘制原始数据集及降维后的数据集
            Parameters:
                data_mat - 原数据集
                recon_mat - 重构原数据矩阵
            Returns:
                无
            Modify:
                2019-1-10
        """
        fig = plt.figure()
        ax = fig.add_subplot(111)
        ax.scatter(data_mat[:, 0].flatten().A[0], data_mat[:, 1].flatten().A[0], marker='^', s=90)
        ax.scatter(recon_mat[:, 0].flatten().A[0], recon_mat[:, 1].flatten().A[0], marker='o', s=50, c='red')
        plt.show()
    
    
    def replace_nan_with_mean():
        """
            Function:
                将NaN替换成平均值
            Parameters:
                无
            Returns:
                data_mat - 处理缺失值后的数据矩阵
            Modify:
                2019-1-10
        """
        data_mat = load_data_set('./machinelearninginaction/Ch13/secom.data', ' ')
        num_feat = shape(data_mat)[1]
        for i in range(num_feat):
            mean_val = mean(data_mat[nonzero(~isnan(data_mat[:, i].A))[0], i])
            data_mat[nonzero(isnan(data_mat[:, i].A))[0], i] = mean_val
        return data_mat
    
    
    
    if __name__ == '__main__':
        # data_mat = load_data_set('./machinelearninginaction/Ch13/testSet.txt')
        # low_d_mat, recon_mat = pca(data_mat, 2)
        # print(shape(low_d_mat))
        # plot_pca(data_mat, recon_mat)
    
        # data_mat = replace_nan_with_mean()
        # mean_vals = mean(data_mat, axis=0)
        # mean_removed = data_mat - mean_vals
        # cov_mat = cov(mean_removed, rowvar=0)
        # eig_vals, eig_vects = linalg.eig(mat(cov_mat))
        # # print(eig_vals)
        # for i in range(20):
        #     first_i_eig_vals_ratio = sum(eig_vals[0: i + 1]) / sum(eig_vals)
        #     print('前%d个主成分的方差值占总方差值百分比:%.2f' % (i, first_i_eig_vals_ratio))
    
        from sklearn.decomposition import PCA
        data_mat = replace_nan_with_mean()
        pca = PCA(n_components=7)
        pca.fit(data_mat)
        print('各主成分的方差值占总方差值百分比:', pca.explained_variance_ratio_)
        print('各主成分的方差值:', pca.explained_variance_)
        # 转化后的数据
        trans_data = pca.transform(data_mat)
        savetxt("../trans_data.txt", trans_data)
    
    

    lowDMat 包含了降维之后的矩阵是个一维矩阵,将降维后的数据和原始数据一起绘制出来。

    原始数据集(三角形点表示)及第一主成分(圆形点表示)

    top_n_feat = 2,既然没有剔除任何特征,那么重构之后的数据会和原始的数据重合。会看到和上图类似的结果(无直线)。

    四、示例:利用PCA对半导体制造数据降维

    我们知道,像集成电路这样的半导体,成本非常昂贵。如果能在制造过程中尽早和尽快地检测出是否出现瑕疵,将可能为企业节省大量的成本和时间。

    那么,我们在面对大规模和高维度数据集时,显然计算损耗会很大,无疑会非常耗时。

    所以,如果利用 PCA 等降维技术将高维的数据特征进行降维处理,保留那些最重要的数据特征,舍弃那些可以忽略的特征,将大大加快我们的数据处理速度和计算损耗,为企业节省不小的时间和成本。

    现有一上述数据集,而它也比前面使用的数据集更大,包含了590个特征,并且该数据包含很多以NaN标识的的缺失值。先尝试对这些特征进行降维处理。

    对于缺失值,我们用平均值来代替缺失值,平均值根据那些非NaN得到。

    会看到一大堆值,但是其中很多值都是0。实际上,其中有超过20%的特征值都是0。这就意味着这些特征都是其他特征的副本,也就是说,它们可以通过其他特征来表示,而本身并没有提供额外的信息。 最前面15个值的数量级大于105,实际上那以后的值都变得非常小。这就相当于告诉我们只有部分重要特征,重要特征的数目也很快就会下降。最后,我们可能会注意到有一些小的负值,它们主要源自数值误差应该四舍五入成0。在下图13-4中已经给出了总方差的百分比,在开始几个主成分之后,方差就会迅速下降。

    于是,可以知道在数据集的前面多个主成分中所包含的信息量。我们可以尝试不同的截断值来检验它们的性能。有些人使用能包含90%信息量的主成分数量,而其他人使用前20个主成分。我们无法精确知道所需要的主成分数目,必须通过在实验中取不同的值来确定。

    上述分析能够得到所用到的主成分数目,然后我们可以将该数目输入到PCA算法中,最后得到约简后数据就可以在分类器中使用了。

    五、应用scikit-learn进行降维

    在scikit-learn中,与PCA相关的类都在sklearn.decomposition包中。最常用的PCA类就是sklearn.decomposition.PCA。除了PCA类以外,最常用的PCA相关类还有KernelPCA类,,它主要用于非线性数据的降维,需要用到核技巧。另外一个常用的PCA相关类是IncrementalPCA类,它主要是为了解决单机内存限制的。此外还有SparsePCA和MiniBatchSparsePCA。他们和上面讲到的PCA类的区别主要是使用了L1的正则化,这样可以将很多非主要成分的影响度降为0,这样在PCA降维的时候我们仅仅需要对那些相对比较主要的成分进行PCA降维,避免了一些噪声之类的因素对我们PCA降维的影响。

    sklearn.decomposition.PCA的主要参数做一个介绍:
    (1) n_components:这个参数可以帮我们指定希望PCA降维后的特征维度数目。最常用的做法是直接指定降维到的维度数目。不输入n_components即为默认值,此时n_components=min(样本数,特征数)。
    (2) whiten :判断是否进行白化。所谓白化,就是对降维后的数据的每个特征进行归一化,让方差都为1。对于PCA降维本身来说,一般不需要白化。如果你PCA降维后有后续的数据处理动作,可以考虑白化。默认值是False,即不进行白化。
    (3) svd_solver:即指定奇异值分解SVD的方法,由于特征分解是奇异值分解SVD的一个特例,一般的PCA库都是基于SVD实现的。默认是auto,即PCA类会自己去在前面讲到的三种算法里面去权衡,选择一个合适的SVD算法来降维。

    除了这些输入参数外,有两个PCA类的成员值得关注。第一个是explained_variance_,它代表降维后的各主成分的方差值。方差值越大,则说明越是重要的主成分。第二个是explained_variance_ratio_,它代表降维后的各主成分的方差值占总方差值的比例,这个比例越大,则越是重要的主成分。

    从图中的各主成分的方差值占总方差值的比例、方差值可以看出,sklearn.decomposition.PCA的降维结果和上面是一致的。

    降维转化后的结果

    六、小结

    降维技术使得数据变得更易使用,并且它们往往能够去除数据中的噪声,使得其他机器学习任务更加精确。降维往往作为预处理步骤,在数据应用到其他算法之前清洗数据。

    有很多技术可以用于数据降维,在这些技术中,独立成分分析、因子分析和主成分分析比较流行,其中又以主成分分析应用最广泛。

    PCA可以从数据中识别其主要特征,它是通过沿着数据最大方差方向旋转坐标轴来实现的。
    选择方差最大的方向作为第一条坐标轴,后续坐标轴则与前面的坐标轴正交。协方差矩阵上的特
    征值分析可以用一系列的正交坐标轴来获取。

    相关文章

      网友评论

          本文标题:机器学习实战-12-PCA主成分分析

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