3 %>@brief Calculates Fisher
's Linear Discriminant vectors (loadings).
5 %> If either data or pieces is passed, the scatter matrixes will be
8 %> The rank of @c S_W (within-class scatter matrix) will be tested, and if it is lower
9 %> than the dimensionality of the problem (i.e., number of features), PCA
10 %> will be run first to project the data onto a space where the within-class
11 %> scatter matrix (say @c S_W_PCA) will be non-singular and then the obtained
12 %> LDA loadings will be projected back to the original space.
14 %> The equation to solve [1]:
17 %> S_B*w = lambda*S_W*w
20 %> There are rank(S_B) (at most no_classes-1) different w's.
22 %> <h3>References:</h3>
23 %> [1] R. O. Duda, P. E. Hart, and D. G. Stork, Pattern Classification, 2nd ed. New York: John Wiley & Sons, 2001.
25 %> [2] T. Hastie, J. H. Friedman, and R. Tibshirani, The Elements of Statistical Learning, 2nd ed. New York: Springer, 2007.
29 %> @param data Dataset
30 %> @param flag_sphere=0. Deac
32 %> @param n_max Maximum number of loadings vectors to be returned
33 %> @return <em>[W_star]</em> or <em>[W_star, lambdas]</em>
35 function [W_star, varargout] =
fisher_ld(data, flag_sphere, flag_modified_s_b, P, n_max)
40 irerror('Cannot run LDA on dataset with less than 2 classes!');
43 if ~exist('flag_modified_s_b', 'var')
44 flag_modified_s_b = 0;
52 flag_p = any(P(:) ~= 0);
54 flag_n_max = nargin >= 5 && ~isempty(n_max);
59 [V, D] = eig(S_B, S_W);
61 no_lambdas = size(D, 2);
63 % Creates an index table and sorts it by eigenvalue in ascending order
64 % (because sortrows() hasn't a descending order option)
66 [vv, ii] = sort(lambdas, 'descend');
68 % % % if numel(vv) < data.nc-1
69 % % % % disp('OLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLHAAAAA');
75 % Returns the nc-1 vectors corresponding to the c-1 largest eigenvalues
77 % eigenvectors in descending order of eigenvalue
78 W_star = V(:, ii(1:min([data.nc-1, n_max, data.nf])));
80 W_star = V(:, ii(1:min([data.nc-1, data.nf])));
84 W_star = V(:, ii(1:min(size(V, 2), n_max)));
91 % % % % % % % % % % % % % % % % % % % % % %> keyboard;
92 % % % % % % % % % % % % % % % % % % % % % lambdas(:, 2) = (1:no_lambdas)';
93 % % % % % % % % % % % % % % % % % % % % % lambdas = sortrows(lambdas);
94 % % % % % % % % % % % % % % % % % % % % %
95 % % % % % % % % % % % % % % % % % % % % % % sweeps the [lambda, index] table backwards in search for no_classes-1
96 % % % % % % % % % % % % % % % % % % % % % % largest and properly numeric eigenvalues
97 % % % % % % % % % % % % % % % % % % % % % W_star = zeros(data.nf, data.nc-1);
98 % % % % % % % % % % % % % % % % % % % % % lambdas2 = zeros(no_lambdas, 1);
99 % % % % % % % % % % % % % % % % % % % % % maxlambda = max(lambdas(:, 1));
100 % % % % % % % % % % % % % % % % % % % % % no_found = 0;
101 % % % % % % % % % % % % % % % % % % % % % for i = no_lambdas:-1:1
102 % % % % % % % % % % % % % % % % % % % % % lambda = lambdas(i, 1);
103 % % % % % % % % % % % % % % % % % % % % % % if lambda ~= NaN & lambda ~= Inf & lambda > maxlambda*1e-6
104 % % % % % % % % % % % % % % % % % % % % % no_found = no_found+1;
105 % % % % % % % % % % % % % % % % % % % % %
106 % % % % % % % % % % % % % % % % % % % % % v_temp = V(:, lambdas(i, 2));
107 % % % % % % % % % % % % % % % % % % % % % W_star(:, no_found) = v_temp/norm(v_temp);
108 % % % % % % % % % % % % % % % % % % % % % lambdas2(no_found) = lambdas(i, 1);
109 % % % % % % % % % % % % % % % % % % % % %
110 % % % % % % % % % % % % % % % % % % % % % if no_found >= 3 %data.nc-1
111 % % % % % % % % % % % % % % % % % % % % % break;
112 % % % % % % % % % % % % % % % % % % % % % end;
113 % % % % % % % % % % % % % % % % % % % % % % end;
114 % % % % % % % % % % % % % % % % % % % % % end;
115 % % % % % % % % % % % % % % % % % % % % %
116 % % % % % % % % % % % % % % % % % % % % %
117 % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % Don't mess here again, JULIO, this needs to be like that, unnormalized
118 % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % W_star =
adjust_unitnorm(W_star);
119 % % % % % % % % % % % % % % % % % % % % % % W_star = adjust_turn(W_star);
120 % % % % % % % % % % % % % % % % % % % % %
121 % % % % % % % % % % % % % % % % % % % % % if no_found < (data.nc-1)
122 % % % % % % % % % % % % % % % % % % % % % W_star = W_star(:, 1:no_found);
123 % % % % % % % % % % % % % % % % % % % % % end
183 %
irerror(
'Cannot run LDA on dataset with less than 2 classes!');
186 %
if ~exist(
'flag_modified_s_b',
'var')
187 % flag_modified_s_b = 0;
199 % % S_W = diag(diag(S_W));
201 % % S_W = eye(size(S_W, 1)); %> HACK let
's try to see how it is dealt with if S_W is an eye
204 % flag_deficient = rank(S_W) < length(S_W);
206 % if flag_sphere && flag_deficient
207 % error('Cannot make S_W spherical because it is singular!
');
211 % [V, lambdas] = eig_ordered(S_W);
213 % V_ = V/sqrt(diag(lambdas));
216 % [S_B, S_W] = data_calculate_scatters(data, flag_modified_s_b, P);
220 % fprintf('Fisher
''s LDA will be calculated in PC eigenspace because rank(S_W) = %>d which is lower than %>d\n
', rsw, length(S_W));
223 % [loadings_pca, scores] = princomp2(data.X);
224 % no_factors = size(scores, 2);
226 % if rsw < no_factors
227 % fprintf('PCA Scores matrix will be truncated from %>d to %>d columns to match rank of S_W.\n
', no_factors, rsw);
228 % scores = scores(:, 1:rsw);
229 % loadings_pca = loadings_pca(:, 1:rsw);
230 % elseif no_factors < rsw
231 % fprintf('Actually, the number of PCA factors derived (%>d) was even lower than %>d said before.\n', no_factors, rsw);
240 % no_classes = rank(S_B)+1;
243 % rank_S_W = rank(S_W);
244 % %> if rank_S_W < nf
245 % %> error('Cannot calculate Fisher Linear Discriminant because rank(S_W) = %>d which is lower than %>d.\n', rank_S_W, nf);
249 % %> %> [V, D] = eigs(S_B, no_classes-1);
250 % %> [V, D] = eig(S_B);
251 % %> V = V(:, 1:(no_classes-1));
252 % %> D = D(:, 1:(no_classes-1));
254 % %> OPTS.tol = 1e-50;
255 % [V, D] = eigs(S_B, S_W, no_classes-1);
257 % % [V, D] = eig(S_B, S_W);
259 % no_lambdas = size(D, 2);
261 % % Creates an index table and sorts it by eigenvalue in ascending order
262 % % (because sortrows() hasn't a descending order option)
265 % lambdas(:, 2) = (1:no_lambdas)';
266 % lambdas = sortrows(lambdas);
268 % % sweeps the [lambda, index] table backwards in search for no_classes-1
269 % % largest and properly numeric eigenvalues
270 % W_star = zeros(nf, no_lambdas);
271 % lambdas2 = zeros(no_lambdas, 1);
273 % for i = no_lambdas:-1:1
274 % lambda = lambdas(i, 1);
275 % if lambda ~= NaN & lambda ~= Inf & lambda > 0
276 % no_found = no_found+1;
278 % v_temp = V(:, lambdas(i, 2));
279 % W_star(:, no_found) = v_temp/norm(v_temp);
280 % lambdas2(no_found) = lambdas(i, 1);
285 % W_star = V_*W_star;
289 % W_star = loadings_pca*W_star;
292 % % % % % % % % % % Don't mess here again, JULIO, this needs to be like that, unnormalized
294 % W_star = adjust_turn(W_star);
300 % varargout(1) = {lambdas2};
303 % fprintf(
'INFO: F-LDA applied (pre-processing: ''%s'').\n', s);
function adjust_unitnorm(in L)
function irverbose(in s, in level)
function calculate_scatters(in X, in classes, in flag_modified_s_b, in P)
function data_calculate_scatters(in data, in flag_modified_s_b, in P)
function fisher_ld(in data, in flag_sphere, in flag_modified_s_b, in P, in n_max)