PCA介紹
主成分分析 (Principal Component Analysis ,簡稱 PCA)是最常用的一種降維方法。
算法介紹
代碼
function [p_d_mat,project_mat,allmean]=PCA2(initialize_mat,p)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%輸入:
% initialize_mat: 原高維矩陣 m*n m代表特徵 n代表樣本數
% p: 要求降維後矩陣的維數
%輸出:
%p_d_mat: 降維後的p維矩陣
%project_mat: 投影矩陣
%allmean: 均值
%%%%%%%%%%%%%%%%%%%%%%%% by LiSR %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%關於PCA2(initialize_mat,p)處理函數的說明
%1、對initialize_mat每一個特徵維度求均值,然後減去均值得meanmat
%2、對meanmat'*meanmat求特徵向量與特徵值
%3、找出最大的特徵值與特徵向量,計算投影矩陣,project_mat=meanmat*max_v/sqrt(sigma) (爲了特徵向量單位陣)
%4、計算降維後的矩陣 p_d_mat=project_mat'*meanmat;
%5、除以p_d_mat矩陣最大的奇異值
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[features,rows]=size(initialize_mat);%原矩陣的特徵(維)數,和列數 size返回行與列
allmean=mean(initialize_mat,2);%按列求原矩陣的均值 2代表按列求均值
meanmat=zeros(features,rows);%初始化均值矩陣
%計算差值,原矩陣所有列減去均值
for i=1:rows
meanmat(:,i)=initialize_mat(:,i)-allmean;
end
%利用差值矩陣構建協方差矩陣,即C=meanmat*meanmat';
%然後計算C的特徵值和特徵向量。由於C的維數過大,計算代價太大,
%利用奇異值分解原理求得協方差矩陣C=meanmat*meanmat'的特徵值和特徵向量
%即,利用求meanmat'*meanmat的特徵值、向量求原協方差矩陣meanmat*meanmat'
%的特徵值和特徵向量
%[U,S,V]=svd(meanmat)
%注:Matlab中,求解出來的特徵值是默認從大到小排序了的,而自然的,特徵向量也是與排序後特徵值相對應的。
[v,smat]=eig(meanmat'*meanmat);%求得特徵向量所組成的v矩陣和特徵值
%把特徵值取出,放到數組中,按升序排列
w=1:rows;
for i=1:rows
w(i)=smat(i,i);
end
project_mat=zeros(features,p);%初始化投影矩陣
max_v=v(:,rows-p+1:rows); %取最大的特徵值對應的特徵向量
%計算奇異值
sigma=sqrt(w(rows-p+1:rows));
%計算投影矩陣,U_i=A*V_i/sqrt(sigma) 對其歸一化
for i=1:p
project_mat(:,i)=meanmat*max_v(:,i)/sigma(i);
end
%計算降維後的矩陣
p_d_mat=project_mat'*meanmat;
%L_2 歸一 norm->返回A的最大奇異值,即max(svd(A))
for i=1:size(p_d_mat,2)
p_d_mat(:,i)=p_d_mat(:,i)/norm(p_d_mat(:,i)); %假設A是一個矩陣,那麼norm(A)或者norm(A,2)計算的就是A的2範數;
end
end
主函數
%pca+svm測試
%% a litte clean work
close all;
clear;
clc;
format compact;
%% load data 加載PaviaU數據集
%數據說明:訓練集共有1800個樣本,測試集有900個樣本
%數據樣本共有9種地表類型
load('PaviaU_gt.mat');
load('PaviaU.mat');
clsCnt = 9;
trnNum = 200;
%轉化成svm訓練所需要的格式
train_x = [];
train_y = [];
test_x = [];
test_y = [];
mm = max(max(max(paviaU)));
for i = 1 :clsCnt
temp = getpixel(paviaU,paviaU_gt,i);
clsNum = size(temp,1);
%trnNum = ceil(clsNum*trnPer);
tstNum = clsNum - trnNum;
train_x = [ train_x ; temp(1:trnNum,:) ];
cls_lab = zeros(trnNum,1);
cls_lab(:,1) = i;
train_y = [ train_y ; cls_lab];
test_x = [ test_x ; temp(trnNum+1:trnNum+100,:) ];
cls_lab = zeros(100,1);
cls_lab(:,1) = i;
test_y = [ test_y ; cls_lab];
end
%首先求取特徵數
feature_num=size(train_x,2);
%準確度記錄
Accuracy_record_train = [];
Accuracy_record_test = [];
%從103個特徵中選取1~103個特徵
for num=1:20
tic
%分別是訓練集與測試集以及相應的標籤
traindata = double(train_x/mm);
testdata = double(test_x/mm);
trainlabel=train_y;
testlabel=test_y;
%% 進行pca數據預處理
fprintf('iter %d',num);
%兩種計算PCA的方法
[traindata_pca,project_mat,allmean]=PCA_mine(traindata',num);
test_samples=size(testdata,1);
for i=1:test_samples
testdata_meanmat(:,i)=testdata(i,:)-allmean'; %testdata 103*1
end
testdata_pca=project_mat'*testdata_meanmat;
% 利用訓練集合建立分類模型
%-s 代表svm類型
%-t代表 核函數類型
%-c 設置C-SVC epsilon-SVR n-SVR懲罰參數 默認爲1
%-g 設置核函數中 gamma的值
%model = svmtrain(trainlabel,traindata,'-s 0 -t 2 -c 1.2 -g 2.8');
%model = svmtrain(trainlabel,traindata,'-s 0 -t 1 -c 1.2 -g 2.8');
model = svmtrain(trainlabel,traindata_pca','-s 0 -t 1 -c 1.2 -g 2.8');
% 利用建立的svm模型看其在訓練集合上的分類效果
[ptrain,acctrain,dec_values1] = svmpredict(trainlabel,traindata_pca',model);
% 預測測試集合標籤
[ptest,acctest,dec_values2] = svmpredict(testlabel,testdata_pca',model);
%記錄準確度
Accuracy_record_train=[Accuracy_record_train,acctrain(1)];
Accuracy_record_test=[Accuracy_record_test,acctest(1)];
%%
toc;
end
%% 繪製測試集 訓練集準確度曲線
x = 1:1:20;
%x = 1:1:feature_num;
%y = sin(x);
plot(x,Accuracy_record_train)
hold on
y2 = cos(x);
plot(x,Accuracy_record_test,'r:')
grid on
xlabel('pca降維後的特徵數')
ylabel('準確度')
%axis([xmin xmax ymin ymax]); % 設置座標軸在指定的區間
%legend('訓練集準確度','測試集準確度') %爲圖片添加圖例
title('pca降維後的特徵數與svm分類準確度的關係示意圖') %添加圖像標題
text(1.5,0.3,'測試集準確度') %將'測試集準確度'這個註解加到座標中的某個位置
gtext('測試集準確度') % 用鼠標的光標定位,將'測試集準確度'這個註解放在你鼠標點擊的地方
text(1.5,0.3,'訓練集準確度') %將'測試集準確度'這個註解加到座標中的某個位置
gtext('訓練集準確度') % 用鼠標的光標定位,將'測試集準確度'這個註解放在你鼠標點擊的地方