数据降维(PCA、KPCA、PPCA)及C++实现
1、何為數據降維
1.1維數災難:往往滿足采樣條件所需的樣本數目巨大、樣本稀疏、距離計算困難。
1.2降維:利用數學變換將原始高維屬性空間轉變為低維“子空間”,即在高維采樣數據中提取能夠表達原始數據的特征。
1.3 降維優點:數據集更易懂、使用和顯示;降低算法計算開銷;去除噪聲。
2、一些降維算法
Principal Component Analysis (PCA)
Linear Discriminant Analysis(LDA)
Locally linear embedding(LLE)
Laplacian Eigenmaps
本文主要針對以下三種算法:
2.1 PCA:PCA算法是一種線性投影技術,利用降維后使數據的方差最大原則保留盡可能多的信息;
2.2 KPCA:PCA僅考慮了數據的二階統計信息,而沒有利用高階統計信息,忽略了數據的非線性相關性,而KPCA,通過非線性變換將數據映射到了高維,在高維空間中進行特征提取,獲得了更好的特征提取性能;
2.3 PPCA:PCA沒有將數據的概率分布考慮,PPCA對PCA做了概率上的解釋,延伸了PCA算法。
總之:PPCA和KPCA都是針對PCA算法的缺陷,做出了不同方向上的改進。
3 PCA、KPCA、PPCA算法步驟
3.1 PCA: 數據在低維線性空間上的正交投影,這個線性空間被稱為主子空間,使得投影數據的方差被最大化。
》將原始數據按列組成n行m列矩陣X;
》將X的每一行(代表一個屬性字段)進行零均值化,即減去這一行的均值;
》求出協方差矩陣C;
》求出協方差矩陣的特征值及對應的特征向量;
》將特征向量按對應特征值大小從上到下按行排列成矩陣,取前k行組成矩陣P;
》Y=PX即為降維到k維后的數據。
3.2 KPCA:通過使用一個非線性核替換線性的方式來對高維數據向低維投影。
》將原始數據按列組成m行n列矩陣X;
》計算核矩陣,先選定高斯徑向核函數中的參數,計算核矩陣K,修正核矩陣得到KL;
》求出協方差矩陣C,運用雅可比迭代方法計算KL特征值與特征向量;
》將特征向量按對應特征值大小從上到下按行排列成矩陣,取前k行組成矩陣;
》通過施密特正交化方法單位正交化特征向量得到P;
》Y=PX即為降維到k維后的數據。
3.3 PPCA:PPCA是一種考慮每個變量概率分布的方法,在確定主元和誤差的概率函數后,通過期望最大(EM)算法建立模型。
》將原始數據按列組成n行m列矩陣;
》對原始訓練樣本數據進行標準中心化處理得到X;
》在隱含變量x 的條件下得到觀測數據的概率分布;
》通過EM 算法獲得概率PCA 的模型參數W(因子矩陣)和方差;
》舍去不滿足因子矩陣與方差特定關系的歸一化數據;
》剩余滿足條件數據即為降維到k維后的數據。
4、C++實現PCA、KPCA
(環境:Visual Studio 2013)
pca.h
??? #include<math.h>?? ?
??? #include<fstream>?? ?
??? #include<iostream>?? ?
??? #include<stdio.h>?? ?
??? #include<iomanip>?? ?
??? #include<math.h>
??? using namespace std;
??? ?
??? typedef struct sourcedata????? //聲明了一個原始數據類型
??? {
?? ??? ?int m;
?? ??? ?int n;
?? ??? ?double **data;
??? }SourceData;
??? class PCA
??? {
??? public:
?? ??? ?PCA(int m, int n);??????????????????????????????? //m為行數,n為列數?? ?
?? ??? ?SourceData getdata(const? char *file);?????????? //獲取外部數據
?? ??? ?void standarddata(double **a);????????????????? //數據標準化
?? ??? ?double? product(double *a, double *b);???????? //向量乘積
?? ??? ?void? swap(double &x, double &y);???????????? //數據交換
?? ??? ?double? **matrixproduct(double **a);??????????? //求解協方差矩陣
?? ??? ?void? selectionsort(double *A, double **v);???? //特征值排序
?? ??? ?void? zhengjiao(double **v);?????????????????? //向量正交化
?? ??? ?int jcb(double **a, double **v, double eps, int jt);?? ??? ? //求解特征值和特征向量
?? ??? ?int selectcharactor(double *A, double getratio, double *B); //提取主分量
?? ??? ?double? **getProject(int t, double **x, double **v);??????? //計算降維后特征點 ?
?? ??? ?void?? saveProject(const char *projectfile, double **project, int t); //保存
?? ??? ?~PCA(){}
??? private:
?? ??? ?int? rows;
?? ??? ?int columns;
??? };
kpca.h
??? #include<math.h>
??? #include<fstream>
??? #include<iostream>
??? #include<stdio.h>
??? #include<iomanip>
??? #include<math.h>
??? #include<stdlib.h>
??? #include<time.h>
??? using namespace std;
??? ?
??? class KPCA
??? {
??? public:
?? ??? ?KPCA(int m, int n);
?? ??? ?SourceData getdata(const char *file); //獲取外部數據
?? ??? ?int randdef(int n1, int n2); //生成n1到n2隨機整數
?? ??? ?double getvar(double **testdata, int m, int n, int l, double left, double right);//通過對隨機樣本的最大特征提取效率獲取高斯徑向基函數的參數
?? ??? ?double product(double *a, double *b, int size);? //向量乘積
?? ??? ?double kernel(double var, double *x, double *y, int sign);? //核函數定義
?? ??? ?double **getkernelmatrix(double **a, double var, int sign); //獲取核矩陣
?? ??? ?double **modifykernelmatrix(double **K);? //修正核矩陣
?? ??? ?int jcb(double **a, double **v, double eps, int jt);?? ?//求解矩陣的特征值和特征向量?? ?
?? ??? ?void zhengjiao(double **v); //正交化特征向量
?? ??? ?void swap(double &x, double &y); //交換元素
?? ??? ?void selectionsort(double *A, double **v);? //特征值和特征向量選擇排序
?? ??? ?void saveeigenvectors(double A[], double **v, const char *vectorfile);//保存特征值和特征向量
?? ??? ?int selectcharactor(double *A, double getratio, double *B);? //提取特征
?? ??? ?double? **getProject(int t, double **x, double **v);? //獲得投影
?? ??? ?void saveProject(const char *projectfile, double **project, int t);? //保存投影
?? ??? ?~KPCA(){}
??? private:
?? ??? ?int? rows;
?? ??? ?int columns;
??? };
pca.cpp與kpca.cpp由于篇幅問題未分享,有意者郵箱:1490217008@qq.com或https://download.csdn.net/download/u010442908/10628230
main.cpp
??? #include"pca.h"?? ?
??? #include"kpca.h"
??? void main()
??? {
?? ??? ?//pca
??? ?
?? ??? ?cout << "-----------------------pca------------------------" << endl;
?? ??? ?int i, j, t;??????????????????????????????????????????????????????? //i,j循環用;t降維后維數
?? ??? ?int m, n;?????????????????????????????????????????????????????????? //m行n列
?? ??? ?double **x, **c, **v, **Project;???????????????????????????????????? ?
?? ??? ?double *A, *B;???????????????????????????????????????????????????????? //A特征值B貢獻率
?? ??? ?sourcedata pp;
?? ??? ?double eps = 0.000001;????????????????????????????????????????????? //雅克比方法的終止精度?????????? ?
?? ??? ?double getratio = 0.9;????????????????????????????????????????????? //特征值的提取率???? ?
?? ??? ?const? char *File = "test1.txt";??????????????????????????????????? //原始數據文件名稱?? ?
?? ??? ?const char *projectfile = "pcaproject.txt";???????????????????????? //處理后的數據文件名稱?? ?
?? ??? ?PCA pca(2, 3);????????????????????????????????????????????????????? //聲明一個臨時對象調用成員函數來獲取數據?? ?
?? ??? ?pp = pca.getdata(File);???????????????????????????????????????????? //獲取外部數據?? ?
?? ??? ?x = pp.data;
?? ??? ?m = pp.m;
?? ??? ?n = pp.n;
??? ?
?? ??? ?cout << "數據的行數為" << m << ",數據的列數為 " << n << endl;
?? ??? ?A = new double[n];?????????????????????????????????????????? //存放特征值
?? ??? ?B = new double[n];????????????????????????????????????????? //存放特值貢獻率
?? ??? ?v = new double*[n];????????????????????????????????????????? //存放特征向量
?? ??? ?for (i = 0; i < n; i++)
?? ??? ??? ?v[i] = new double[n];
??? ?
??? ?
?? ??? ?PCA? testpca(m, n);??????????????????????????????????????? //聲明一個對象并初始化????????? ?
?? ??? ?testpca.standarddata(x);?????????????????????????????????? //對數據進行標準化處理?? X是原始數據?????? ?
?? ??? ?c = testpca.matrixproduct(x);????????????????????????????? //??? 求協方差矩陣 ?
?? ??? ?i = testpca.jcb(c, v, eps, 100);?????????????????????????? //??? 求特征值和特征向量?? ?
?? ??? ?for (int k = 0; k < n; k++)
?? ??? ??? ?A[k] = c[k][k];??????????????????????????????????????? //存特征值?? ?
?? ??? ?testpca.zhengjiao(v);???????????????????????????????????? //正交化特征向量?? ?
?? ??? ?testpca.selectionsort(A, v);????????????????????????????? //特征值和特征向量排序?????? ?
?? ??? ?t = testpca.selectcharactor(A, getratio, B);????????????? //提取特征值 t為降維后維數? ?
??? ?
??? ?
?? ??? ?cout << "PCA降維后的維數:" << t << endl;
?? ??? ?cout << "排序后提取的特征值及對應的特征向量" << endl;
?? ??? ?for (i = 0; i <= t - 1; i++)????????????????????????????? //輸出特征值
?? ??? ??? ?printf("%13.7e? ", A[i]);
?? ??? ?printf("\n\n");
??? ?
?? ??? ?for (i = 0; i < n; i++)??????????????????????????????????? //輸出特征向量
?? ??? ?{
?? ??? ??? ?for (j = 0; j < t; j++)
?? ??? ??? ??? ?printf("%13.7e? ", v[i][j]);
?? ??? ??? ?printf("\n");
??? ?
?? ??? ?}
?? ??? ?cout << "特征值的累計貢獻率為" << endl;
?? ??? ?for (i = 0; i < n; i++)
?? ??? ??? ?cout << B[i] << "? ";
?? ??? ?cout << endl;
?? ??? ?cout << "當提取效率是" << getratio << "時提取了前" << t << "個分量" << endl;???? //getratio特征提取率
?? ??? ?if (t >= 1 && t <= n)
?? ??? ??? ?Project = testpca.getProject(t, x, v);??????????????? //求降維后特征點????? ?
?? ??? ?else
?? ??? ??? ?cout << "error" << endl;
?? ??? ?testpca.saveProject(projectfile, Project, t);???????????? //保存特征點到TXT文件 ?
??? ?
??? ?
??? ?
?? ??? ?//kpca
??? ?
?? ??? ?cout << endl<< "----------------------kpca------------------------" << endl;
?? ??? ?int a;????????????????????????????????????????????????????? //循環用
?? ??? ?int l = 50;???????????????????????????????????????????????? //隨機提取樣本的數目?? ?
?? ??? ?const char *File2 = "test2.txt";
?? ??? ?const char*eigenvectors = "eigen.txt";???????????????????? //特征值和特征向量存儲文件名稱
?? ??? ?const char *projectfile2 = "kpcaproject.txt";????????????? //降維后特征點文件存儲名稱
?? ??? ?SourceData pdata;
?? ??? ?double? gaussparameter;??????????????????????????????????? //高斯核參數
?? ??? ?double **K, **KL;?????????????????????????????????????????? //高斯核矩陣k及修正核矩陣?? ?
?? ??? ?KPCA kpca(3, 2);
?? ??? ?pdata = kpca.getdata(File2);?????????????????????????????? //獲取外部數據
?? ??? ?x = pdata.data;
?? ??? ?m = pdata.m;
?? ??? ?n = pdata.n;
?? ??? ?A = new double[m];
?? ??? ?B = new double[m];
??? ?
?? ??? ?KPCA? testkpca(m, n);??????????????????????????????????????? //對象?? ?
?? ??? ?gaussparameter = testkpca.getvar(x, m, n, l, 100, 800);?????? //求高斯核參數??? 通過對隨機樣本的最大特征提取效率獲取高斯徑向基函數的參數
?? ??? ?cout << "高斯核參數: " << gaussparameter << endl;
?? ??? ?K = testkpca.getkernelmatrix(x, gaussparameter, 1);????????? //求核矩陣
?? ??? ?KL = testkpca.modifykernelmatrix(K);??????????????????????? //求修正核矩陣?? ?
?? ??? ?c = new double*[m];???????????????????????????????????????? //定義c、v二維數組
?? ??? ?for (a = 0; a<m; a++)
?? ??? ??? ?c[a] = new double[m];
?? ??? ?v = new double*[m];
?? ??? ?for (a = 0; a<m; a++)
?? ??? ??? ?v[a] = new double[m];
?? ??? ?for (a = 0; a<m; a++)??????????????????????????????????????? //修正核矩陣放入c
?? ??? ??? ?for (j = 0; j<m; j++)
?? ??? ??? ??? ?c[a][j] = KL[a][j];
?? ??? ?a = testkpca.jcb(c, v, eps, 10000);?? ???????????????????????? //求取特征值和特征向量
?? ??? ?cout << "計算特征值的迭代次數為" << a << endl;
?? ??? ?if (a != -1)
?? ??? ?{
?? ??? ??? ?for (a = 0; a<m; a++)
?? ??? ??? ??? ?A[a] = c[a][a];???????????????????????????????????? //特征值存入A
?? ??? ?}
?? ??? ?else
?? ??? ??? ?cout << "不能求得特征值和特征向量" << endl;
?? ??? ?testkpca.zhengjiao(v);?? ?????????????????????????????????? //正交化特征向量
?? ??? ?testkpca.saveeigenvectors(A, v, eigenvectors);
?? ??? ?testkpca.selectionsort(A, v);???????????????????????????? //特征值和特征向量排序?? ?
?? ??? ?t = testkpca.selectcharactor(A, getratio, B);??????????? //提取特征值?? ?
??? ?
?? ??? ?cout << "特征值的累計貢獻率是" << endl;
?? ??? ?for (a = 0; a<m; a++)
?? ??? ??? ?cout << B[a] << "? ";
?? ??? ?cout << endl;
?? ??? ?cout << "當提取效率為" << getratio << "時提取了前" << t << "個分量" << endl;
?? ??? ?if (t >= 1 && t <= m)
?? ??? ??? ?Project = testkpca.getProject(t, KL, v);??????????????? //求降維后特征點
?? ??? ?else
?? ??? ??? ?cout << "error" << endl;
?? ??? ?testkpca.saveProject(projectfile2, Project, t);?????????????? //存入TXT文件
??? }
結果分析
工程目錄
4.1、pca原始線性數據集,即工程目錄下test1.txt文件,共6維數據,每個維度150個特征點,部分數據截圖如下:
經過pca算法降維后,生成工程目錄下pcaproject.txt文件,數據變為4維:
4.2:kpca原始非線性數據集,即工程目錄下test2.txt文件,共6維數據,每個維度150個特征點,部分數據截圖如下:
經過kpca算法降維后,生成工程目錄下kpcaproject.txt文件,數據變為2維:
?
————————————————
版權聲明:本文為CSDN博主「陌上花開1111」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u010442908/article/details/81182405
總結
以上是生活随笔為你收集整理的数据降维(PCA、KPCA、PPCA)及C++实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一分钟了解 Matlab求两个矩阵的相关
- 下一篇: 回声消除技术