降维概述
降维的目的
维度灾难
在数据挖掘中,特征工程是极其重要的一环,不断寻找特征的过程,就是不断给数据增加维度。通常特征更丰富,算法就更容易捕获数据之间的模式。
维度高了之后,计算开始变得非常困难; 同时特征之间会相互干扰,而不是相互独立,从而影响算法性能;
还有一个很重要的原因是维度高了之后,样本在空间的分布会变得很稀疏,这容易导致过拟合,比如决策树的叶子节点上样本太少。
——机器学习 - 降维算法概述
具体来说,做m次实验,有m个样本,每个样本有n个随机值,用矩阵表示数据集就是
降维的要求
降维就是说把A变成
降维的要求则是新矩阵能近似地刻画原矩阵(线性变换),数据的主要信息要能保留下来。
如何才能刻画呢,就是把各维度中最能表征此线性变换的维度(真正的特征)抽出来,把那些相关的维度合并处理,而不是简单的去掉一些维度。
PCA降维的手段
PCA目标
PCA(Principal Component Analysis,主成分分析)常用于提取一系列多维样本的主要成分。那么,怎么理解主成分?
假设三维空间中有一系列点,这些点分布在一个过原点的斜面上,如果你用自然坐标系x,y,z这三个轴来表示这组数据的话,需要使用三个维度,而事实上,这些点的分布仅仅是在一个二维的平面上,那么,问题出在哪里?如果你再仔细想想,能不能把x,y,z坐标系旋转一下,使数据所在平面与x,y平面重合?这就对了!如果把旋转后的坐标系记为x’,y’,z’,那么这组数据的表示只用x’和y’两个维度表示即可!当然了,如果想恢复原来的表示方式,那就得把这两个坐标之间的变换矩阵存下来。这样就能把数据维度降下来了!但是,我们要看到这个过程的本质,如果把这些数据按行或者按列排成一个矩阵,那么这个矩阵的秩就是2!这些数据之间是有相关性的,这些数据构成的过原点的向量的最大线性无关组包含2个向量,这就是为什么一开始就假设平面过原点的原因!那么如果平面不过原点呢?这就是数据中心化的缘故!将坐标原点平移到数据中心,这样原本不相关的数据在这个新坐标系中就有相关性了!有趣的是,三点一定共面,也就是说三维空间中任意三点中心化后都是线性相关的,一般来讲n维空间中的n个点一定能在一个n-1维子空间中分析!所以,不要说数据不相关,那是因为坐标没选对!
实际上PCA是要找到样本空间中的一组新的基(维度更低),将原数据在这组新基上进行投影(将每一个样本表示为这组基的线性组合),使得投影后的方差(variance)最大(因为选取了方差最大的维度,所以这样可以存储最多的信息)或者说投影使损失最小。
下图应该是对PCA第二种解释(损失最小化)展示得最好的一张图片了(ref:svd,pca,relation)
降维步骤
- 数据表示为
A={z1→,z2→,…,zn→} 对数据A进行中心化得新矩阵
X={x1→,x2→,…,xn→}={z1→−μ→,z2→−μ→,...,zn→−μ→} ;
其中μ→=1n∑n1zi→
注意这里的向量都是列向量 - 求X的协方差矩阵;
cov(X)=XX′/(m−1) ;实际中不需要分母,因为去掉后特征向量是一致的 - 对协方差矩阵
cov(X) 进行特征值分解; - 取特征值矩阵中最大的K个特征值对应的”k-特征向量”矩阵
P′ ; - 将原数据A乘以
P′ 得到降维后的新矩阵
为什么这么做
目标是投影后使方差最大
为什么要得协方差的特征向量呢?
这里有一个推导过程:
我们先考虑矩阵在新坐标的第一主轴
XX’是半正定的对称阵,所以上式为半正定的二次型,存在最大值。
现在问题就是如何求目标函数的最大值?以及取最大值时u1的方向?
上式是关于u1的函数,现在求函数极值且存在约束条件
目标函数和约束条件构成了一个最大化问题:
构造拉格朗日函数:
对u1求导(找驻点):
显然,u1即为XX’特征值
所以,如果取最大的那个特征值,那么得到的目标值就最大
第二主轴方向为第二大特征值对应的特征向量方向,以此类推,证明类似。
这样我们就能依次找到每个轴的方向。
综上,我们将
代码实现
import numpy as np
class PCA:
def __init__(self, dimension, train_x):
# 降维后的维度
self.dimension = dimension
# 原始数据集
self.train_x = train_x
@property
def result(self):
'返回降维后的矩阵'
# 1. 数据中心化
data_centering = self.train_x - np.mean(self.train_x, axis=0)
# 2. 计算协方差矩阵
cov_matrix = np.cov(data_centering, rowvar=False)
# 3. 特征值分解
eigen_val, eigen_vec = np.linalg.eig(cov_matrix)
# 4. 生成降维后的数据
p = eigen_vec[:, 0:self.dimension]
return np.dot(data_centering, p)
后面我们会看一些具体的应用案例