3.核主元分析
上一次我们谈到了主元分析,主元分析实际上是一种线性降维。那么我们是否可以通过引入核的概念使得降维非线性呢?
这就涉及到了核主元分析(Kernel Principle Component Analysis)。
在PCA中,我们的计算的核心是围绕数据特征的协方差矩阵进行的,通过对协方差矩阵进行特征分解,将特征值进行排序,按一定阈值排除掉特征值小的一些特征值,以及这些特征值对应的特征向量,剩余的特征向量作为我们将数据中心化后降维的正交变换基底,进而完成降维。而引入核之后,这个协方差矩阵则是定义在高维空间,之后的一系列操作也是在高维空间中进行的。
我们设其中是我们的高维映射,我们并不需要知道这个高维映射的具体形式,我们仅仅需要知道这个高维映射的內积即可。即
接着,我们试图通过对高维空间的协方差矩阵进行特征分解进而完成降维: 很明显,我们并没有办法在这里引入核,我们只有通过了解这个映射的具体形式才能得到高维协方差矩阵,这与我们想要的相差甚远。那我们该怎么做才能绕过这个问题呢?
在(六)核主元分析PART1中我们有提到主坐标分析的做法,通过求的特征向量来达到绕过直接求协方差矩阵这个目的,我们发现这个正好满足我们的所有要求:
1.可以绕过求协方差矩阵 ;
2.将计算形式表达为高维內积;
3.求得的特征向量构成的矩阵直接产生降维结果
于是我们令
假设是的特征向量。有:
因为是中心矩阵:
所以对于:
于是这里很显然可以看出高维协方差矩阵的特征向量写成矩阵形式: 根据(六)中的定义,当我们得正交的特征向量矩阵后,降维公式为:
类似的,在这里,我们可以写成其中,是经过特征值排序后筛选出的正交特征向量构成的矩阵;高维映射是作用在整个上的的矩阵;是的元素全为1的向量。
所以得到我们的核主元分析的核心公式:
以高斯核为例上代码:
# ** Statistical Learning **
# File Name: Kernel PCA
# Author: Pan
# Description: a kind of Non-linearly dimension reduction which make use of kernel theory.
# Date: 2020/7/24
# ** --Start-- **
import numpy as np
class KPCA:
def __init__(self,X,sigma,retained_ratio):
self.X=X
self.sigma=sigma
self.n=np.shape(self.X)[0]
self.p =np.shape(self.X)[1]
self.one_vector=np.array([np.ones(self.n)])
self.H=np.identity(self.n)-(1/self.n)*self.one_vector.T.dot(self.one_vector)
self.retained_ratio = retained_ratio
def Guass_Kernal(self):
E_minus_x_square=(np.repeat(np.exp(-1*(np.sum(self.X*self.X,axis=1))),self.n)/self.sigma).reshape(self.n,self.n)
E_x_y=np.exp(self.X.dot(self.X.T)/self.sigma)
return E_minus_x_square*E_x_y*E_minus_x_square.T
def Kernal_PCA(self,Kernal):
self.T=self.H.dot(Kernal).dot(self.H)
self.EigenValues,self.EigenMatrix=np.linalg.eig(self.T)
self.EigenMatrix=self.EigenMatrix/np.array([np.sum(self.EigenMatrix*self.EigenMatrix,axis=1)]).T
self.retained_num =np.argwhere(np.cumsum(sorted(self.EigenValues, reverse=True)) / np.trace(self.T) <= self.retained_ratio)[-1]
self.EigenRanking = self.n - 1 - np.argsort(self.EigenValues)
self.index_selection = np.where(self.EigenRanking <= self.retained_num)
self.V = self.EigenMatrix[self.index_selection]
return self.H.dot(Kernal).dot(self.H).dot(self.V.T)
if __name__ == '__main__':
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.datasets import load_diabetes
data=load_diabetes()
X=data["data"]
kpca=KPCA(X=X.T,sigma=0.1,retained_ratio=0.5)
G_kernel=kpca.Guass_Kernal()
Z=kpca.Kernal_PCA(G_kernel)
def plot(dfData):
plt.subplots(figsize=(9, 9))
sns.heatmap(dfData, annot=True, vmax=1, square=True, cmap="Blues")
plt.show()
plot(np.corrcoef(X.T))
plot(np.corrcoef(Z.T))
运行结果:
降维前:
降维后:
降维后
网友评论