最近一個朋友問這方面的一些問題,其實之前也就很粗略的看了下fisher,真正幫別人解答問題的時候才知道原來自己也有很多東西不懂。下面小結下自己對fisher判別的理解:
其實fisher和PCA差不多,熟悉PCA的人都知道,PCA其實就是在尋找一個子空間。這個空間怎么來的呢,先求協方差矩陣,然后求這個協方差矩陣的特征空間(特征向量對應的空間),選取最大的特征值對應的特征向量組成特征子空間(比如說k個,相當於這個子空間有k維,每一維代表一個特征,這k個特征基本上可以涵蓋90%以上的信息)。那么我們把樣本投影在這個子空間,原來那么多維的信息就可以用這k維的信息代替了,也就是說降維了。至於PCA為啥要用求協方差矩陣然后求特征子空間的方法,這個數學上有證明,記得在某篇文章上看過,有興趣的可以找找,看看證明。
那么fisher空間又是怎么一回事呢,其實fisher判別和PCA是在做類似的一件事,都是在找子空間。不同的是,PCA是找一個低維的子空間,樣本投影在這個空間基本不丟失信息。而fisher是尋找這樣的一個空間,樣本投影在這個空間上,類內距離最小,類間距離最大。那么怎么求這個空間呢,類似於PCA,求最大特征值對應的特征向量組成的空間。 當我們取最大幾個特征值對應的特征向量組成特征空間時(這里指出,最佳投影軸的個數d<=c-1,這里c是類別數),最佳投影矩陣如下:
其實在文章Eigenfaces vs Fisherfaces :recognition using class specific linear projection中給出了PCA和LDA比較直觀的解釋,文中對一個二維的數據進行分析,PCA和LDA都是把二維數據降到一個一維空間,那么其實PCA使得數據投影在這個一維空間總的離散度最大,我的理解是這樣的,如果數據在某一維上比較離散,說明這維特征對數據的影響比較大,也就是說這維特征是主成分。而LDA呢,數據投影在這個空間,類內離散度最小,類間離散度最大,數據變得線性可分,如文中所說:
假設我們給定C類樣本,我們先求sw(類內離散度)和sb(類間離散度),如下所示:
那么樣本投影在新的投影空間中類間離散度為:
樣本投影在新的投影空間中類內離散度為:
那么只要我們最大化就可以使得樣本投影在這個空間上類內離散度最小,類間離散度最大,其中,w就是我們要找的投影方向。但是問題就來了,如果sw是一個奇異矩陣,那么這個式子是求不出來的。所以就有高人想到用這個式子代替:
這里的B是一個權衡因子,權衡類間距離和類內距離誰的比重大,試驗中可以根據需要調節。也就是說,只要我們可以根據梯度下降法迭代w,使得最大化,這個w就是我們所要求的最好的投影方向。在fisher中最大特征值對應的特征向量就是最佳投影方向,如果我們取最大k個特征值對應的特征向量作為投影方向,那么最終樣本就投影到了這樣的一個k維子空間,在這個子空間里面類內最小,類間最大。
另外還有一種方法來解決sw的奇異性引起的問題,比如如果我們試驗中處理的數據時人臉圖片,由於人臉圖片之間相關性很大,所以sw很容易就是一個奇異矩陣,但是如果我們先用PCA對樣本進行降維,去掉相關性,那么這樣我們再用LDA就不會遇到sw奇異性的為題了,實際中這種方法也是很常用的,在用LDA的時候往往先使用PCA降維。
好了,下面來給出fisher的一個簡單的matlab代碼:
main.m
1: clear; clc;
2: %定義兩類樣本的空間范圍
3: x1min=2;x1max=6;
4: y1min=-4,y1max=0;
5: x2min=6,x2max=10;
6: y2min=2,y2max=6;
7: %產生兩類2D空間的樣本
8: c1=createSwatch(x1min,x1max,y1min,y1max,100);
9: c2=createSwatch(x2min,x2max,y2min,y2max,80);
10: %獲取最佳投影方向
11: w=fisher_w(c1,c2);
12: %計算將樣本投影到最佳方向上以后的新坐標
13: cm1=c1(1,:)*w(1)+c1(2,:)*w(2);
14: cm2=c2(1,:)*w(1)+c2(2,:)*w(2);
15: cc1=[w(1)*cm1;w(2)*cm1];
16: cc2=[w(1)*cm2;w(2)*cm2];
17: %打開圖形窗口
18: figure;
19: %繪制多圖
20: hold on;
21: %繪制第一類的樣本
22: plot(c1(1,:),c1(2,:),'rp');
23: %繪制第二類的樣本
24: plot(c2(1,:),c2(2,:),'bp');
25: %繪制第一類樣本投影到最佳方向上的點
26: plot(cc1(1,:),cc1(2,:),'r+');
27: %繪制第二類樣本投影到最佳方向上的點
28: plot(cc2(1,:),cc2(2,:),'b+');
29: w=10*w;
30: %畫出最佳方向
31: line([-w(1),w(1)],[-w(2),w(2)],'color','k');
32: axis([-10,10,-10,10]);
33: grid on;
34: hold off;
fisher_w.m
1: function w = fisher_w(c1,c2)
2: %利用Fisher准則函數確定最佳投影方向
3: %c1和c2分別為兩類樣本的樣本矩陣
4: %得到樣本矩陣的尺寸信息
5: %樣本矩陣的行數代表樣本的維數
6: %樣本矩陣的列數代表樣本的個數
7: size1=size(c1);
8: size2=size(c2);
9: %計算兩類樣本的均值向量
10: m1=sum(c1,2)/size1(2);
11: m2=sum(c2,2)/size2(2);
12: %樣本向量減去均值向量
13: c1=c1-m1(:,ones(1,size1(2)));
14: c2=c2-m2(:,ones(1,size2(2)));
15: %計算各類的類內離散度矩陣
16: S1=c1*c1.';
17: S2=c2*c2.';
18: %計算總類內離散度矩陣
19: Sw=S1+S2;
20: %計算最佳投影方向向量
21: w=Sw^-1*(m1-m2);
22: %將向量長度變成1
23: w=w/sqrt(sum(w.^2));
24: end
1: function swatch=createSwatch(xmin,xmax,ymin,ymax,num,varargin)
2:
3: xlen = abs(xmax - xmin);
4: ylen = abs(ymax - ymin);
5:
6: if numel(varargin)>0 && isa(varargin{1},'function_handle')
7: f = varargin{1};
8: else
9: f = @rand;
10: end
11: swatch=[xlen*f(1,num)+min(xmax,xmin);ylen*f(1,num)+min(ymax,ymin)];
12:
13: end
14:
實驗效果如下: