本文使用LDA作爲分類器在matlab下做實驗。
其中投影轉換矩陣W按照LDA的經典理論生成,如下的LDA函數,並返回各個類的投影后的(k-1)維的類均值。
LDA.m代碼如下:
function [W,centers]=LDA(Input,Target)
% Ipuut: n*d matrix,each row is a sample;
% Target: n*1 matrix,each is the class label
% W: d*(k-1) matrix,to project samples to (k-1) dimention
% cneters: k*(k-1) matrix,the means of each after projection
% 初始化
[n dim]=size(Input);
ClassLabel=unique(Target);
k=length(ClassLabel);
nGroup=NaN(k,1); % group count
GroupMean=NaN(k,dim); % the mean of each value
W=NaN(k-1,dim); % the final transfer matrix
centers=zeros(k,k-1); % the centers of mean after projection
SB=zeros(dim,dim); % 類間離散度矩陣
SW=zeros(dim,dim); % 類內離散度矩陣
% 計算類內離散度矩陣和類間離散度矩陣
for i=1:k
group=(Target==ClassLabel(i));
nGroup(i)=sum(double(group));
GroupMean(i,:)=mean(Input(group,:));
tmp=zeros(dim,dim);
for j=1:n
if group(j)==1
t=Input(j,:)-GroupMean(i,:);
tmp=tmp+t'*t;
end
end
SW=SW+tmp;
end
m=mean(GroupMean);
for i=1:k
tmp=GroupMean(i,:)-m;
SB=SB+nGroup(i)*tmp'*tmp;
end
% % W 變換矩陣由v的最大的K-1個特徵值所對應的特徵向量構成
% v=inv(SW)*SB;
% [evec,eval]=eig(v);
% [x,d]=cdf2rdf(evec,eval);
% W=v(:,1:k-1);
% 通過SVD也可以求得
% 對K=(Hb,Hw)'進行奇異值分解可以轉換爲對Ht進行奇異值分解.P再通過K,U,sigmak求出來
% [P,sigmak,U]=svd(K,'econ');=>[U,sigmak,V]=svd(Ht,0);
[U,sigmak,V]=svd(SW,0);
t=rank(SW);
R=sigmak(1:t,1:t);
P=SB'*U(:,1:t)*inv(R);
[Q,sigmaa,W]=svd(P(1:k,1:t))
Y(:,1:t)=U(:,1:t)*inv(R)*W;
W=Y(:,1:k-1);
% 計算投影后的中心值
for i=1:k
group=(Target==ClassLabel(i));
centers(i,:)=mean(Input(group,:)*W);
end
因爲LDA是二類分類器,需要推廣到多類的問題。常用的方法one-vs-all方法訓練K個分類器(這個方法在綜合時不知道怎麼處理?),以及任意兩個分類配對訓練分離器最後得到k(k-1)/2個的二類分類器。本文采用訓練後者對樣本進行訓練得到模型model。在代碼中,model爲數組struct。
用於訓練的函數LDATraining.m
function [model,k,ClassLabel]=LDATraining(input,target)
% input: n*d matrix,representing samples
% target: n*1 matrix,class label
% model: struct type(see codes below)
% k: the total class number
% ClassLabel: the class name of each class
%
model=struct;
[n dim]=size(input);
ClassLabel=unique(target);
k=length(ClassLabel);
t=1;
for i=1:k-1
for j=i+1:k
model(t).a=i;
model(t).b=j;
g1=(target==ClassLabel(i));
g2=(target==ClassLabel(j));
tmp1=input(g1,:);
tmp2=input(g2,:);
in=[tmp1;tmp2];
out=ones(size(in,1),1);
out(1:size(tmp1,1))=0;
% tmp3=target(g1);
% tmp4=target(g2);
% tmp3=repmat(tmp3,length(tmp3),1);
% tmp4=repmat(tmp4,length(tmp4),1);
% out=[tmp3;tmp4];
[w m]=LDA(in,out);
model(t).W=w;
model(t).means=m;
t=t+1;
end
end
在預測時,使用訓練時生成的模型進行k(k-1)/2次預測,最後選擇最多的分類作爲預測結果。在處理二類分類器預測時,通過對預測樣本作W的投影變換再比較與兩個類的均值進行比較得到(不知道有沒有更好的辦法?)
用於預測的函數LDATesting.m
function target=LDATesting(input,k,model,ClassLabel)
% input: n*d matrix,representing samples
% target: n*1 matrix,class label
% model: struct type(see codes below)
% k: the total class number
% ClassLabel: the class name of each class
[n dim]=size(input);
s=zeros(n,k);
target=zeros(n,1);
for j=1:k*(k-1)/2
a=model(j).a;
b=model(j).b;
w=model(j).W;
m=model(j).means;
for i=1:n
sample=input(i,:);
tmp=sample*w;
if norm(tmp-m(1,:))<norm(tmp-m(2,:))
s(i,a)=s(i,a)+1;
else
s(i,b)=s(i,b)+1;
end
end
end
for i=1:n
pos=1;
maxV=0;
for j=1:k
if s(i,j)>maxV
maxV=s(i,j);
pos=j;
end
end
target(i)=ClassLabel(pos);
end
示例代碼爲:
function target=test(in,out,t)
[model,k,ClassLabel]=LDATraining(in,out);
target=LDATesting(t,k,model,ClassLabel);
實驗中對USPS數據集進行了測試,效果不怎麼好,正確率才39%左右,而這個數據集使用KNN算法可以達到百分之百九十的正確率,汗!