1. 目的

对多维数据进行升维或者降维的过程,得到合理的特征维度,用于模型的训练,其中降维主要有特征的融合(PCA)和特征筛选(如根据卡方分布选择最优的K个特征),本章节主要讲解PCA。

2. 概念

主成分分析Principal component analysis,简写为PCA,主要用于高维数据的降维操作,以提取数据的主要特征,而去除掉无用或者噪音的信息。

3. 理论依据

PCA主要是将原来特征所在的一组基,变换到另外一组基中,如果新的一组基的数量小于原来基的数量,即达到了降维的目的。

而转换后的坐标在新的一组基中的指定一个基中的映射(投影),称为该组数据在指定基上的坐标,如果所有的数据在该指定基上的投影(坐标)相对集中(极端情况:均投到同一个位置),则在该基上就无法对数据进行区分,同理,如果在所有基上的投影均相对集中,则数据在该组基中为一团,没法区分样本,所以为了能够区分样本,数据在指定基上的投影应该尽可能的分散(即混乱程度较严重,即信息熵越大),而方差是一组数据分散程度的一种度量指标。

方差:是一组数据与其均值的差的平方和的均值,其数学公式表示如下:

机器学习-特征选择-PCA_特征值

为了后面计算方便,将数据做0均值化处理,即xi = xi - μ,则其数学公式表示如下:

机器学习-特征选择-PCA_方差_02

故优化目标函数为:所有数据在这个基变换后的坐标的方差最大的那个基。

在高维数据中,可以用协方差表示两个变量的相关性(用pearsonr度量也可以,因为pearsonr是标准化的协方差,机器学习-特征选择-PCA_方差_03),而协方差的数学表示如下:

机器学习-特征选择-PCA_协方差矩阵_04

如果两个变量x和y的协方差为越小,则两个变量的相关性越低,若为0,则两个变量之间不存在线性相关(有可能存在非线性相关),因此新的一组基中的第二个基只能在与第一个基正交的方向上,依次类推。

机器学习-特征选择-PCA_特征值_05

故将PCA优化的目标函数表示为:将原来M个N维向量,降维到M个K维向量,求解所需的K个基满足单位正交,且原来数据变换到该组基后,各变量(基)两两之间的协方差为0,而各自变量的方差越大越好。

而上述目标可以用协方差矩阵表示(对角线表示相同变量之间的方差,非对角线表示两两变量之间的协方差)。

对于一组n维的m个数据,进行每个维度0均值化处理后得到新的数据用X表示(Xn,m)

机器学习-特征选择-PCA_特征值_06


设P矩阵是降维后的组分(每行为一个基),Y是在P基变换后的坐标;C和D分别为X和Y对应的协方差矩阵,则它们的关系如下:

机器学习-特征选择-PCA_协方差矩阵_07

则将原来的优化目标转化为:求解能够使得协方差矩阵C对角化的矩阵P,且PCPT的对角线元素从左上角到右下角的值依次减小,则找到的矩阵P的前K行就是要寻找的基,即用P的前K行 * 矩阵X就能够使得矩阵X从N维度降低到了K维度。

由下面线性代数的补充知识(对称阵的性质可得),存在正交矩阵U使得,UTAU = Λ,A为对阵矩阵,U为单位正交矩阵

​即,上述所求的P为U的转置,即UT,U为矩阵C的不同特征值的特征向量,且特征向量按照特征值大小从大到小排序得到的。

4. 求解过程

  1. 采样:m个数据,每个数据有n个维度|特征
  2. 将数据处理为n * m的矩阵A,即每个列向量对应一个数据,每一行对应一个特征的采样。
  3. 将上述矩阵A的每行做:0均值化处理,即每个特征的均值为0,得到新的A,Aij = Aij - Ai_mean
  4. 计算上述新的矩阵Ade协方差C的矩阵即,C = A * AT / m
  5. 计算上述协方差矩阵的特征值和特征向量λ和U
  6. 将特征向量按照特征值大小从小到大进行排序,同时特征值也进行排序
  7. 取上述排序后的特征向量的前K行,组成新的矩阵P
  8. Y = PA ,即得到降维到K维度后的数据Y

5. 代码演示

# -*- coding:utf-8 -*-
import sys
import numpy as np
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
np.set_printoptions(linewidth=200)
K = 2
iris = load_iris() # 创建鸢尾花数据集的类对应的实例:iris
arr = iris.data # 对应于第一步: 150 * 4的矩阵
A = arr.T.copy() # 对应于第二步: 将数据处理为n*m,n:特征个数,m:样本个数
print("特征进行0均值化处理之前的数据")
print(A[:,:10].round(2))
print(A.mean(axis = 1))
A = A - A.mean(axis = 1).reshape(-1,1) # 对应于第三步
print("特征进行0均值化处理之后的数据")
print(A[:,:10].round(2))
print(A.mean(axis = 1))
C = np.cov(A, ddof = 0, bias = True) # 第四步 计算协方差矩阵
eig_value, eig_vector = np.linalg.eig(C) # 第五步:计算协方差矩阵的特征值和特征向量
print("协方差矩阵的特征值和特征向量:")
print(eig_value)
print(eig_vector) # 每一列为一个特征值
eig_value_index = eig_value.argsort()[::-1] # 第六步: 对协方差矩阵的特征值和特征向量进行排序
eig_value = eig_value[eig_value_index].copy()
eig_vector = eig_vector[:,eig_value_index].copy()
print("协方差矩阵的特征值和特征向量(排序后):")
print(eig_value)
print(eig_vector) # 每一列为一个特征值
P = eig_vector[:,:K].T.copy()

A_new = P.dot(A)
#rr_new = P.dot(arr.T)

print("调用sklearn库中decomposition模块的PCA类")
pca = PCA(n_components=K, whiten=True, random_state=0)
x = pca.fit_transform(arr) # arr.shape: sample_num * feature_num
print('各方向方差:', pca.explained_variance_) # 上述协方差矩阵C的特征值(排序后的)
print('方差所占比例:', pca.explained_variance_ratio_) # 上述协方差矩阵C的特征值在所有特征值加和中的占比
print("各方向的基:", pca.components_) # 新的坐标系的基
pca_p = pca.components_
x = x.T.copy()

print("自己实现与sklearn库的区别和比较")
pca_p = pca.components_
pca_eig = pca.explained_variance_
x = pca.fit_transform(arr).T

self_p = P
self_eig = eig_value[:K]
new_A = P.dot(A)
print("方差比较(几乎相等):", self_eig , pca_eig)
print("基比较(相同或者部分基的方向相反):", self_p / pca_p)
print("降维后数据值的比较(结果不同:与方差和基的方向相关):")
print(np.unique((A_new / x).round(2)[:,:10], axis = 1)[:,0]) # 2.06, -0.49
print(self_p[:,0] / pca_p[:,0] * np.sqrt(self_eig))

更多文章请关注《万象专栏》