LDA.m
5.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
function [subspaceData]=LDA(X,classNo,varargin)
% [subspaceData]=LDA(X,classNo)
%
% LDA method for learning a subspace that seeks to maximize the Fisher
% seperability measure. 'X' is d x n matrix, where d is the feature
% vector size, and n is the number of instaces. 'classNo' is a n x 1
% vector that indicates which class/subject each instance belongs to.
%
% Optional parameters:
% 'EnergyRetain' - percentage of variance (0.0 to 1.0) to retain in the initial
% PCA step. (default = 0.98)
%
% 'do_direct' - Whether or not to perform Direct LDA (default = false)
%
% 'FixedRetain' - Keep a fixed number of eigenvectors in the initial PCA.
% If used, then specify number to keep (e.g. 100)
%
%
% 'DominantEig' - whether or not to use the dominant eigenvector method. If
% the d >> n, then this should be set to true.
% (default = true)
%
% 'SkipPCA' - whether of not to skip the PCA step. If Sw is believed to
% be non-singular then PCA step can be safely skipped.
% (default = false)
%
% 'ScaleW' - the factor by which to scale the within-class scatter matrix.
% This controls the importance of the between and within
% class scatter to each other in the fisher criterion
%
% The output 'subspaceData' is a struct that contains the following important fields:
% subspaceData.mean - d x 1 vector containing the mean of the training data
% subspaceData.W - d x k LDA projection matrix, where k is the number of
% subspace dimensions
%
%
% Algorithm based on Fukanaga's LDA method. This code was orginally written by Zhifeng Li,
% and has since been modified and improved by Brendan Klare.
%
%
useFixedEnergy = false;
doDominantEig = true;
doPCA = true;
useFixedEig = false;
energyPercentage = .98;
ScaleW = 1;
doDLDA = false;
do_null = false;
cnt = 1;
while cnt < length(varargin)
switch varargin{cnt}
case 'EnergyRetain'
useFixedEnergy = true;
energyPercentage = varargin{cnt+1};
case 'FixedRetain'
useFixedEig = true;
fixedEig = varargin{cnt+1};
case 'DominantEig'
doDominantEig = varargin{cnt+1};
case 'SkipPCA'
doPCA = ~varargin{cnt+1};
case 'ScaleW'
ScaleW = varargin{cnt+1};
case 'do_direct'
do_null = varargin{cnt+1};
otherwise
fprintf('Error, unknown argument %s\n',varargin{cnt});
return
end
cnt = cnt + 2;
end
[FeatureLength SampleNumber]=size(X);
% ClassNum=round(SampleNumber/2);
[a1 a2 classNo] = unique(classNo);
ClassNum = max(classNo);
%Calculate eigenspace from X
if doPCA
if ~doDominantEig
[eigenvalues, eigenvectors, Mean_Vector]=PCA2(X);
else
[eigenvalues, eigenvectors, Mean_Vector, V1]=PCA(X);
end
if useFixedEnergy
d1 = cumsum(eigenvalues)./sum(eigenvalues);
[a nEigs] = max(d1 > energyPercentage);
elseif useFixedEig
nEigs = fixedEig;
else
nEigs = min(FeatureLength,SampleNumber - 1);
end
%Select eigenvectors
Select_eigenvectors=eigenvectors(:,1:nEigs);
eigenvalues = eigenvalues(1:nEigs);
%Project the sample data on to the eigenvectors
W=Select_eigenvectors'*(X-repmat(Mean_Vector,1,SampleNumber));
else
W = X;
Mean_Vector = zeros(size(X,1),1);
nEigs = size(X,1);
Select_eigenvectors = eye(size(X,1));
eigenvalues = ones(size(X,1),1);
end
%Caculate the centers for each class
ClassCenters = zeros(nEigs,ClassNum);
for i = 1:ClassNum
ClassCenters(:,i) = mean(W(:,classNo == i),2);
end
for i = 1:ClassNum,
W(:,classNo == i) = W(:,classNo == i) - repmat(ClassCenters(:,i),1,sum(classNo == i));
end
if ScaleW ~= 1
W = ScaleW .* W;
end
[W_val, W_vec, W_m]=PCA2(W);
if ~do_null
nDim2 = min(nEigs,SampleNumber - ClassNum);
SW_val=W_val(1:nDim2);
SW_vec=W_vec(:,1:nDim2);
SW_vec=SW_vec./(repmat(SW_val',[size(SW_vec,1) 1]).^0.5);
else
nDim2 = nEigs;
SW_val = W_val;
SW_vec = W_vec;
if nEigs > SampleNumber - ClassNum
SW_val(SampleNumber-ClassNum+1:end) = SW_val(SampleNumber-ClassNum)/2;
end
d1 = cumsum(W_val)/sum(W_val);
[d1 start_idx] = max(d1 > .1);
SW_vec = SW_vec(:,start_idx:end);
SW_val = SW_val(start_idx:end);
nDim2 = size(SW_vec,2);
SW_vec=SW_vec./(repmat(SW_val',[size(SW_vec,1) 1]).^0.15);
end
m = mean(W,2);
M=repmat(m(:),1,ClassNum);
mean2 = m;
B=SW_vec'*(ClassCenters-M);
% Between_Class_Matrix=B*B';
[B_val,B_vec,B_m]=PCA2(B);
nDim3 = min(ClassNum-1,nDim2);
SB_vec=B_vec(:,1:nDim3);
subspaceData.mean = Mean_Vector(:);
subspaceData.mean2 = mean2(:);
subspaceData.W1 = Select_eigenvectors;
subspaceData.D1 = eigenvalues;
subspaceData.W2 = SW_vec;
subspaceData.W3 = SB_vec;
subspaceData.W = (subspaceData.W3' * subspaceData.W2' * subspaceData.W1')';