KPCA核主成分分析法C++程序测试
2015-11-08 21:22
363 查看
传统的PCA可以从线性可分的特征中提取主要特征,但是线性不可分部分的信息直接被抛弃了,但其实有很多信息虽然在样本空间是线性不可分的,但是映射到高维的核空间之后是线性可分的,这部分信息在分类识别的时候也是非常重要的,为了提取这部分信息特征,就必须采用KPCA的方法。
KPCA的简介:
在一个样本空间中,有些数据是线性不可分的,但是当通过一种方法把它映射到高维空间之后,它却有可能变成线性可分的数据。如下图所示,要在一维空间中做线性分割,即通过一个点把红色和白色的区域分割开来,这个不可能的,即线性不可分。但是通过函数f(x)=(x-x0)(x-x1)把数据映射到二维空间之后就成了一条抛物线,在二维空间中做线性区分,即通过一条线把红色和白色区域分开,就可以实现了。依次类推,在二维空间中通过一条线无法分开的数据,当映射到三维空间之后,可能可以通过一个平面轻松的分开。这就是做核空间映射的根本目的。
但是,随着空间维数的增加,运算量也迅速增加。为了减少运算开销,就需要把在核空间的线性运算转而用样本空间的核函数来表示。
![](http://img.blog.csdn.net/20151108204238680?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](http://img.blog.csdn.net/20151108204204506?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
KPCA的主要思路:
(1)将样本数据从样本空间作非线性映射到核空间,以此来增强数据的线性可分性。
(2)将核空间的线性操作全部化为矩阵内积的形式。
(3)将核空间的内积全部用样本空间的核函数或者核矩阵来代替。
(4)用核函数的形式进行子空间降维的操作。
KPCA的步骤:
(1)针对训练集S,给定一个核函数k。
(2)计算出核矩阵K,再计算出~K(中心化的K)。
(3)求~K的特征值和单位特征向量,将特征值从大到小排列,提取前D个特征向量,并令
![](http://img.blog.csdn.net/20151108204840438?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
,降维矩阵为
![](http://img.blog.csdn.net/20151108205020071)
。
(4)对于任一样本向量x,通过KPCA降维后的数据为:
![](http://img.blog.csdn.net/20151108205155285)
。
核矩阵K的计算方法:
![](http://img.blog.csdn.net/20151108205449219)
;
![](http://img.blog.csdn.net/20151108205702406)
~K计算方法:
![](http://img.blog.csdn.net/20151108210430239)
主程序部分代码:
完整Qt工程下载:http://download.csdn.net/detail/u013752202/9252849
下图中红框框住的是保留主成分的贡献率,保留的主成分为6个。
![](http://img.blog.csdn.net/20151108210909731?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
特征值和特征向量如下图:
![](http://img.blog.csdn.net/20151108211417186?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
最后降维的结果如下图:
![](http://img.blog.csdn.net/20151108211220024?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
KPCA输入的样本为一个8*177的矩阵,共有8个样本,每个样本的维度都是177维。
得到的特征值有8个,特征向量8个。
保留了6个主成分,降维后的矩阵为8*6,从177维降维了6维。
KPCA的简介:
在一个样本空间中,有些数据是线性不可分的,但是当通过一种方法把它映射到高维空间之后,它却有可能变成线性可分的数据。如下图所示,要在一维空间中做线性分割,即通过一个点把红色和白色的区域分割开来,这个不可能的,即线性不可分。但是通过函数f(x)=(x-x0)(x-x1)把数据映射到二维空间之后就成了一条抛物线,在二维空间中做线性区分,即通过一条线把红色和白色区域分开,就可以实现了。依次类推,在二维空间中通过一条线无法分开的数据,当映射到三维空间之后,可能可以通过一个平面轻松的分开。这就是做核空间映射的根本目的。
但是,随着空间维数的增加,运算量也迅速增加。为了减少运算开销,就需要把在核空间的线性运算转而用样本空间的核函数来表示。
KPCA的主要思路:
(1)将样本数据从样本空间作非线性映射到核空间,以此来增强数据的线性可分性。
(2)将核空间的线性操作全部化为矩阵内积的形式。
(3)将核空间的内积全部用样本空间的核函数或者核矩阵来代替。
(4)用核函数的形式进行子空间降维的操作。
KPCA的步骤:
(1)针对训练集S,给定一个核函数k。
(2)计算出核矩阵K,再计算出~K(中心化的K)。
(3)求~K的特征值和单位特征向量,将特征值从大到小排列,提取前D个特征向量,并令
,降维矩阵为
。
(4)对于任一样本向量x,通过KPCA降维后的数据为:
。
核矩阵K的计算方法:
;
~K计算方法:
主程序部分代码:
完整Qt工程下载:http://download.csdn.net/detail/u013752202/9252849
#include <QtCore/QCoreApplication> #include "kpca.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); cout<<"=========KPCA Start=========== "<<endl; int i,j,t; int m,n;//数据大小,m为行数样本个数,n为列数样本维度 const char *File="src.txt";//待降维数据文件 const char *eigenvectors="eigen.txt";//特征值和特征向量存储文件 const char *projectfile="kpcaproject.txt"; //KPCA降维结果文件 double eps=0.000001; //jacobi方法的终止精度 double gaussparameter;//高斯核函数参数sigma double getratio=0.90; //提取特征值的最高累计贡献率 KPCA kpca(3,2); Mat src=kpca.getdata(File);//获取外部数据 m=src.rows; n=src.cols; double A[m],B[m];//m维向量 KPCA testkpca(m,n);//声明一个KPCA对象 //=============求中心化的高斯径向基核矩阵================= //gaussparameter=testkpca.getSigma(x,m,n,l,100,800);//计算最佳的高斯径向基参数sigma gaussparameter=392;//计算时间很长,计算好了之后就直接赋值 cout<<"gaussparameter is "<<gaussparameter<<endl; Mat K=testkpca.getkernelmatrix(src,gaussparameter,1);//高斯核矩阵 Mat KL=testkpca.modifykernelmatrix(K); //修正核矩阵 Mat fvalue(m,m,CV_64FC1);//m维方阵fvalue,特征值 Mat fvector(m,m,CV_64FC1);//m维方阵fvector,特征向量 //=========求特征值和特征向量========== for(i=0;i<m;i++) //fvalue = KL for(j=0;j<m;j++) fvalue.ptr<double>(i)[j]=saturate_cast<double>(KL.ptr<double>(i)[j]); i=testkpca.jcb(fvalue,fvector,eps,10000);//求取特征值和特征向量 cout<<"计算特征值的迭代次数: "<<i<<endl; if(i!=-1){ for(i=0;i<m;i++) A[i]=fvalue.ptr<double>(i)[i]; //获取特征值 } else cout<<"不能求得特征值和特征向量"<<endl; //=========正交规范化特征向量======== testkpca.zhengjiao(fvector);//这里是用的施密特正交法,运算很慢,还可以优化 //=========选取主成分=============== testkpca.saveeigenvectors(A,fvector,eigenvectors);//保存特征向量 testkpca.selectionsort(A,fvector); //特征值和特征向量排序 t=testkpca.selectcharactor(A,getratio,B); //提取特征值 cout<<"特征值的累计贡献率:"<<endl; for(i=0;i<m;i++) cout<<B[i]<<" "; cout<<endl; cout<<"选择累计贡献率:"<<getratio<<endl; cout<<"保留主成分个数:"<<t<<endl; //=======求KPCA的结果并保存为文件====== Mat Project; if(t>=1&&t<=m) Project=testkpca.getProject(t,KL,fvector);//计算投影 else cout<<"error"<<endl; testkpca.saveProject(projectfile,Project,t); cout<<"Project:"<<endl; cout<<Project<<endl; cout<<"==============KPCA End============="<<endl; return a.exec(); }运行结果分析:
下图中红框框住的是保留主成分的贡献率,保留的主成分为6个。
特征值和特征向量如下图:
最后降维的结果如下图:
KPCA输入的样本为一个8*177的矩阵,共有8个样本,每个样本的维度都是177维。
得到的特征值有8个,特征向量8个。
保留了6个主成分,降维后的矩阵为8*6,从177维降维了6维。
相关文章推荐
- C语言实现链表之单向链表(九)在任意位置插入结点
- c语言实现,图形界面扫雷
- C语言实现链表之单向链表(八)删除尾结点
- C语言实现链表之单向链表(七)尾结点后插入结点
- C语言实现链表之单向链表(六)删除头结点
- C语言实现链表之单向链表(五)头结点前插入结点
- C语言实现链表之单向链表(四)清空链表
- C语言实现链表之单向链表(三)创建链表
- C++设计模式(二)单例模式
- Make 命令教程详解(转自阮一峰的个人博客)
- C语言运算符优先级
- C语言位域(位段)
- Beaglebone Black(5)C++编程控制GPIO基础进阶
- C++入门基础语法
- C++智能指针
- C语言学习字符串和指针
- C语言产生一个大txt文件,并进行排序
- C++ 中使用dlopen加载动态库
- Beaglebone Black(4)C++编程控制GPIO基础
- 【C】【笔记】《C语言深度剖析》第七章 文件结构