PCA原理及python实现

数据降维

在机器学习中,数据通常都是以向量的形式输入模型以进行训练。众所周知,当数据的特征比较多,向量的维度比较大的时候,在对数据进行处理的过程中以及对模型进行训练的过程中,将会消耗极大的消耗系统的内存空间以及增加模型训练的时间成本,甚至产生维度灾难(维数灾难(Curse of Dimensionality):通常是指在涉及到向量的计算的问题中,随着维数的增加,计算量呈指数倍增长的一种现象)。因此,对数据进行降维,用低维度的向量来表示原始高维度的向量就显得尤为重要。常见的降维方法有:主成分分析,线性判别分析,等距映射,局部线性嵌入,拉普拉斯特征映射,局部保留投影等。
其中,主成分分析作为最经典的降维方法,本文将对最近对PCA降维的复习内容做一个系统的总结。

PCA 降维

顾名思义,PCA降维就是要找到数据的主成分,然后用这些主成分表示原始数据。如下图所示,所有的数据样本都是X1和X2这两个特征来表示的。
在这里插入图片描述
可以看出,所有的样本几乎都分布在一条直线上,因此可以将这条直线作为一个坐标轴,将所有的数据用这条坐标轴近似的表示。因此,特征也就有二维降到了一维。
在信号处理领域,通常认为信号具有较大方差,噪声具有较小方差,信号的方差和噪声方差的比值则称为信噪比。信噪比越高,则认为数据的质量就越高,反之则否。由上图可知,数据在主成分所在的轴上的投影点最为分散,投影方差也最大。因此可知,PCA降维过程,就是寻找一个轴W,使得原始数据在这个轴上的投影方差最大。
对于给定的一组数据,{v1,v2,v3,…,vn}, 去中心化后表示成{x1,x2,x3,…,xn} = {v1 - u, v2 - u, v3 - u, …, vn - u}, 其中 u= 1 n \frac{1}{n} n1 ∑ i = 1 n v i \displaystyle\sum_{i=1}^{n}v_i i=1nvi.(至于为什么要进行中心化,这里暂且不表,后面自然一目了然)。向量 x i x_i xi在轴 w w w上的投影坐标可以表示为:
在这里插入图片描述
PCA的目标就是找到这样的一个 w w w, 使得 x i x_i xi w w w上的投影坐标的投影方差最大化。投影坐标平均值可以表示为:
在这里插入图片描述
看到这里是否领悟到对原始数据进行中心化处理的目的了?其实就是使得数据的投影坐标的均值为0,方便后面计算最大投影方差。投影方差可以表示为:
在这里插入图片描述
以上公式中间部分的
在这里插入图片描述
就是数据样本的协方差矩阵,用 表示。另外,由于 w w w是一个单位向量,所以
因此我们要求解一个最大化的问题,可以表示为:
在这里插入图片描述
引入拉格朗日乘子,并且对 w w w求导令其为零,可以求得在这里插入图片描述
显然, λ \lambda λ是协方差矩阵的特征值, w w w则是特征值 λ \lambda λ所对应的特征向量。投影方差可以表示为:
在这里插入图片描述
投影方差就等于协方差矩阵的特征值。要求最大的投影方差只要求协方差矩阵的最大的特征值即可,最佳投影方向即对应着最大特征值所对应的特征向量。次投影方向即对应着第二大特征值岁对应的特征向量。以此类推,便可求得由协方差矩阵的前K大的特征值所对应的特征向量所构成的K维空间来表示原始数据,即将原始数据的n维降到K维。
PCA的求解过程可以归纳如下:
(1)对原始数据进行中心化处理(方便后期的投影方差的计算)
(2)求中心化处理后的样本的协方差矩阵
(3)求解协方差矩阵的特征值以及所对应的特征向量
(4)选取协方差矩阵的前d大的特征值所对应的特征向量构造d维空间,通过以下映射将n维样本映射到d维:
在这里插入图片描述
降维后的信息占比是:
在这里插入图片描述
以上便是通过最大方差理论的角度分析PCA降维理论的过程。除此之外,PCA降维也可以通过最小回归误差构造损失函数的角度来解释,具体过程详见https://www.cnblogs.com/sowhat4999/p/5824880.html

import numpy as np
class PCA:
	def __init__(self, X):
		self.X = X
		self.mean = None
		self.feature = None
	def transform_data(self, n_components = 1):
		n_samples, n_features = self.X.shape  #样本数以及每个样本中的特征个数
		self.mean = np.array([np.mean(self.X[:, i]) for i in range(n_features)]) #每个特征的平均值
		norm_X = self.X - self.mean #对原始数据进行中心化处理
		scatter_X = np.dot(norm_X.T, norm_X) #数据样本的协方差矩阵
		eig_val, eig_vec = np.linalg.eig(scatter_X) #求解协方差差矩阵的特征值以及每个特征值所对应的特征向量
		eig_pairs = [(np.abs(eig_val[i]), eig_vec[:, i]) for i in range(len(eig_val))]
		eig_pairs.sort(reverse = True) #将特征值按从大到小的顺序排序
		self.feature = np.array([ele[1] for ele in eig_pairs[:n_components]) #取前n_components个特征向量
		new_data = np.dot(norm_X, self.feature.T) #降维过后的数据
		return new_data
	def inverse_transform(self, new_data):
		return np.dot(new_data, self.feature) + self.mean

def load_dataset(filepath):
	return np.loadtxt(filepath, dtype = np.float)

if __name__ == "__main__":
	X = load_datatxt('D:/机器之心/当前学习/PCA/pca-master/data/testPCA4.txt') #导入数据
	myPCA = PCA(X = X)
	new_data = myPCA.transform(n_components = 1)
	origin_data = myPCA.inverse_transform(new_data = new_data)
	print("将数据降到{}后, 数据前后方差比是{}".format(new_data.shape[1], np.var(new_data)/np.var(origin_data)

当然,如果我们不想自己造轮子的话,也可以直接调用PCA的API.

from sklearn.decomposition import PCA 
pca = PCA(n_components  = 1)
X = load_datatxt('D:/机器之心/当前学习/PCA/pca-master/data/testPCA4.txt')
new_data = pca.fit_transform(X)
origin_data = pca.inverse_data(new_data)
print("将数据降到{}后, 数据前后方差比是{}".format(new_data.shape[1], np.var(new_data)/np.var(origin_data)

以上便是个人对于降维算法中最经典的PCA的算法的一点拙见,不足之处望批评指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值