最近對PCA主成分分析做了一定的了解,對PCA基礎和簡單的代碼做了小小的總結
有很多博客都做了詳細的介紹,這里也參考了這些大神的成果:
http://blog.sina.com.cn/s/blog_75e063c101014aob.html 這個博客opencv簡單實現了PCA,對PCA關鍵技術做了詳細的分析
http://blog.sina.com.cn/s/blog_4b9b714a0100hc8o.html 這篇文章介紹了opencv實現PCA的相關函數
http://blog.csdn.net/huangxy10/article/details/7912189 這篇文章給出了一個PCA的opencv代碼實現的例子
http://blog.csdn.net/augusdi/article/details/9005276/ 講的比較詳細
先把實驗的代碼貼出來(主要是參考上面博客的代碼)
1 #include <iostream> 2 #include <opencv2/highgui/highgui.hpp> 3 #include <opencv2/core/core.hpp> 4 #include <opencv/cv.hpp> 5 6 using namespace std; 7 using namespace cv; 8 9 float Coordinates[50]={2.5,0.5,2.2,1.9,3.1,2.3,2.0,1.0,1.5,1.1, 10 2.4,0.7,2.9,2.2,3.0,2.7,1.6,1.1,1.6,0.9, 11 2.1,0.4,2.7,2.2,3.4,2.5,1.3,1.2,1.5,0.8, 12 2.0,0.2,2.4,2.3,3.1,2.3,1.4,1.9,1.1,1.8, 13 1.9,0.3,2.8,2.2,1.1,2.7,4.4,1.5,1.8,1.8 14 }; 15 16 void PrintMatrix(CvMat *Matrix,int Rows,int Cols); 17 18 int main() 19 { 20 CvMat *Vector1; 21 CvMat *AvgVector; 22 CvMat *EigenValue_Row; 23 CvMat *EigenVector; 24 25 Vector1=cvCreateMat(5,10,CV_32FC1); 26 cvSetData(Vector1,Coordinates,Vector1->step); //給vector1賦值(樣本矩陣) 27 AvgVector=cvCreateMat(1,10,CV_32FC1); //這個用處還不知道 28 EigenValue_Row=cvCreateMat(1,5,CV_32FC1); //每個數表示一個特征值,5是選取的樣本數和維度中較小的數 29 EigenVector=cvCreateMat(5,10,CV_32FC1); //每一行表示一個特征向量,5是選取的樣本數和維度中較小的數 30 31 //PCA的實現函數 32 cvCalcPCA(Vector1,AvgVector,EigenValue_Row,EigenVector,CV_PCA_DATA_AS_ROW); 33 34 CvMat *Vector2 = cvCreateMat(5,5,CV_32FC1); 35 //cvProjectPCA(Vector1,AvgVector,EigenVector,Vector2); //選擇前面的特征向量(主成分) 36 37 printf("原始樣本矩陣:\n"); 38 PrintMatrix(Vector1,Vector1->rows,Vector1->cols); 39 printf("----------------------\n"); 40 printf("----------------------\n"); 41 printf("特征值:\n"); 42 PrintMatrix(EigenValue_Row,EigenValue_Row->rows,EigenValue_Row->cols); 43 printf("----------------------\n"); 44 printf("特征向量:\n"); 45 PrintMatrix(EigenVector,EigenVector->rows,EigenVector->cols); 46 47 system("pause"); 48 return 0; 49 } 50 void PrintMatrix(CvMat *Matrix,int Rows,int Cols) 51 { 52 for(int i=0;i<Rows;i++) 53 { 54 for(int j=0;j<Cols;j++) 55 { 56 printf("%.4f ",cvGet2D(Matrix,i,j).val[0]); 57 } 58 printf("\n"); 59 } 60 }
上面的主要的函數是cvCalcPCA(Vector1,AvgVector,EigenValue_Row,EigenVector,CV_PCA_DATA_AS_ROW);功能是計算特征值和特征向量
CV_PCA_DATA_AS_ROW:是以列為主的資料的排列
Vector1:所有樣本組成的矩陣(這里有5個樣本,每個樣本是10維的特征向量)
AvgVector:空的平均數向量(不懂)
EigenValue_Row:存放求出的特征值
EigenVector:存放特征向量
另外,函數cvProjectPCA()和函數cvBackProjectPCA(),可以通過矩陣的乘法實現樣本特征的降維和重新轉回原來維度的坐標系。
PCA的技術介紹:
PCA是主成分分析,主要用於降噪和去冗余(降維),對於一系列sample(n個樣本)的feature(m維)組成的多維向量,多維向量里的某些元素本身沒有區分性,比如某個元素在所有的sample中都為1,或者與1相差不大,那么這個元素本身就沒有區分性,用它來做特征區分,貢獻非常小。所以我們的目的是找那些變化大的元素,即方差大的那些維,而去除變化不大的維,從而使feature留下的都是區分能力強的,而且計算量也變小了。
協方差矩陣:
協方差用來描述二維數據,要想描述多維的數據就把所有維度進行兩兩求協方差,也就組成了協方差矩陣。協方差矩陣度量的是維度與維度之間的關系,而不是樣本與樣本的關系。
可見協方差矩陣是一個對稱的矩陣,對角線上是各個維度的方差。是各個維度擁有的能量。降噪:是把協方差矩陣對角化。去冗余:取出對角化之后最大特征值上的維度。如果對角線上值比較小,說明在所有樣本上變化不明顯,對區分不同樣本作用不大,是冗余的。
因為協方差矩陣的特征值的大小代表了這個維度上的能量,找出最大的特征值即為主分量。
協方差矩陣對角線上表示每一維的方差(可以表示這一維的能量),非對角線上的值就是每兩個維度之間的相關性。去除噪聲就是要減小相關性把非對角線的值減小。通過矩陣對角化來完成。對角化后的矩陣,對角線上的值是協方差矩陣的特征值:它是每個維度上的新方差(表示能量),這樣就把各維度間的相關性減到最小。
利用特征向量矩陣進行降維:
如果選取了p個特征值可以表示所有的99%以上(或者超過95%等都行,看自己的要求),那么最大的p個特征值的特征向量就組成了m*p的矩陣。我們知道樣本是m維的,拿樣本向量與這個m*p的矩陣相乘,就得到一個p維的特征,這就完成了降維。
