-
Notifications
You must be signed in to change notification settings - Fork 3
/
pcamat.m
358 lines (316 loc) · 11.8 KB
/
pcamat.m
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
function [E, D] = pcamat(vectors, firstEig, lastEig, s_interactive, ...
s_verbose);
%PCAMAT - Calculates the pca for data
%
% [E, D] = pcamat(vectors, firstEig, lastEig, ...
% interactive, verbose);
%
% Calculates the PCA matrices for given data (row) vectors. Returns
% the eigenvector (E) and diagonal eigenvalue (D) matrices containing the
% selected subspaces. Dimensionality reduction is controlled with
% the parameters 'firstEig' and 'lastEig' - but it can also be done
% interactively by setting parameter 'interactive' to 'on' or 'gui'.
%
% ARGUMENTS
%
% vectors Data in row vectors.
% firstEig Index of the largest eigenvalue to keep.
% Default is 1.
% lastEig Index of the smallest eigenvalue to keep.
% Default is equal to dimension of vectors.
% interactive Specify eigenvalues to keep interactively. Note that if
% you set 'interactive' to 'on' or 'gui' then the values
% for 'firstEig' and 'lastEig' will be ignored, but they
% still have to be entered. If the value is 'gui' then the
% same graphical user interface as in FASTICAG will be
% used. Default is 'off'.
% verbose Default is 'on'.
%
%
% EXAMPLE
% [E, D] = pcamat(vectors);
%
% Note
% The eigenvalues and eigenvectors returned by PCAMAT are not sorted.
%
% This function is needed by FASTICA and FASTICAG
% For historical reasons this version does not sort the eigenvalues or
% the eigen vectors in any ways. Therefore neither does the FASTICA or
% FASTICAG. Generally it seams that the components returned from
% whitening is almost in reversed order. (That means, they usually are,
% but sometime they are not - depends on the EIG-command of matlab.)
% @(#)$Id: pcamat.m,v 1.5 2003/12/15 18:24:32 jarmo Exp $
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Default values:
if nargin < 5, s_verbose = 'on'; end
if nargin < 4, s_interactive = 'off'; end
if nargin < 3, lastEig = size(vectors, 1); end
if nargin < 2, firstEig = 1; end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Check the optional parameters;
switch lower(s_verbose)
case 'on'
b_verbose = 1;
case 'off'
b_verbose = 0;
otherwise
error(sprintf('Illegal value [ %s ] for parameter: ''verbose''\n', s_verbose));
end
switch lower(s_interactive)
case 'on'
b_interactive = 1;
case 'off'
b_interactive = 0;
case 'gui'
b_interactive = 2;
otherwise
error(sprintf('Illegal value [ %s ] for parameter: ''interactive''\n', ...
s_interactive));
end
oldDimension = size (vectors, 1);
if ~(b_interactive)
if lastEig < 1 | lastEig > oldDimension
error(sprintf('Illegal value [ %d ] for parameter: ''lastEig''\n', lastEig));
end
if firstEig < 1 | firstEig > lastEig
error(sprintf('Illegal value [ %d ] for parameter: ''firstEig''\n', firstEig));
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Calculate PCA
% Calculate the covariance matrix.
if b_verbose, fprintf ('Calculating covariance...\n'); end
covarianceMatrix = cov(vectors', 1);
% Calculate the eigenvalues and eigenvectors of covariance
% matrix.
[E, D] = eig (covarianceMatrix);
% The rank is determined from the eigenvalues - and not directly by
% using the function rank - because function rank uses svd, which
% in some cases gives a higher dimensionality than what can be used
% with eig later on (eig then gives negative eigenvalues).
rankTolerance = 1e-7;
maxLastEig = sum (diag (D) > rankTolerance);
if maxLastEig == 0,
fprintf (['Eigenvalues of the covariance matrix are' ...
' all smaller than tolerance [ %g ].\n' ...
'Please make sure that your data matrix contains' ...
' nonzero values.\nIf the values are very small,' ...
' try rescaling the data matrix.\n'], rankTolerance);
error ('Unable to continue, aborting.');
end
% Sort the eigenvalues - decending.
eigenvalues = flipud(sort(diag(D)));
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Interactive part - command-line
if b_interactive == 1
% Show the eigenvalues to the user
hndl_win=figure;
bar(eigenvalues);
title('Eigenvalues');
% ask the range from the user...
% ... and keep on asking until the range is valid :-)
areValuesOK=0;
while areValuesOK == 0
firstEig = input('The index of the largest eigenvalue to keep? (1) ');
lastEig = input(['The index of the smallest eigenvalue to keep? (' ...
int2str(oldDimension) ') ']);
% Check the new values...
% if they are empty then use default values
if isempty(firstEig), firstEig = 1;end
if isempty(lastEig), lastEig = oldDimension;end
% Check that the entered values are within the range
areValuesOK = 1;
if lastEig < 1 | lastEig > oldDimension
fprintf('Illegal number for the last eigenvalue.\n');
areValuesOK = 0;
end
if firstEig < 1 | firstEig > lastEig
fprintf('Illegal number for the first eigenvalue.\n');
areValuesOK = 0;
end
end
% close the window
close(hndl_win);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Interactive part - GUI
if b_interactive == 2
% Show the eigenvalues to the user
hndl_win = figure('Color',[0.8 0.8 0.8], ...
'PaperType','a4letter', ...
'Units', 'normalized', ...
'Name', 'FastICA: Reduce dimension', ...
'NumberTitle','off', ...
'Tag', 'f_eig');
h_frame = uicontrol('Parent', hndl_win, ...
'BackgroundColor',[0.701961 0.701961 0.701961], ...
'Units', 'normalized', ...
'Position',[0.13 0.05 0.775 0.17], ...
'Style','frame', ...
'Tag','f_frame');
b = uicontrol('Parent',hndl_win, ...
'Units','normalized', ...
'BackgroundColor',[0.701961 0.701961 0.701961], ...
'HorizontalAlignment','left', ...
'Position',[0.142415 0.0949436 0.712077 0.108507], ...
'String','Give the indices of the largest and smallest eigenvalues of the covariance matrix to be included in the reduced data.', ...
'Style','text', ...
'Tag','StaticText1');
e_first = uicontrol('Parent',hndl_win, ...
'Units','normalized', ...
'Callback',[ ...
'f=round(str2num(get(gcbo, ''String'')));' ...
'if (f < 1), f=1; end;' ...
'l=str2num(get(findobj(''Tag'',''e_last''), ''String''));' ...
'if (f > l), f=l; end;' ...
'set(gcbo, ''String'', int2str(f));' ...
], ...
'BackgroundColor',[1 1 1], ...
'HorizontalAlignment','right', ...
'Position',[0.284831 0.0678168 0.12207 0.0542535], ...
'Style','edit', ...
'String', '1', ...
'Tag','e_first');
b = uicontrol('Parent',hndl_win, ...
'Units','normalized', ...
'BackgroundColor',[0.701961 0.701961 0.701961], ...
'HorizontalAlignment','left', ...
'Position',[0.142415 0.0678168 0.12207 0.0542535], ...
'String','Range from', ...
'Style','text', ...
'Tag','StaticText2');
e_last = uicontrol('Parent',hndl_win, ...
'Units','normalized', ...
'Callback',[ ...
'l=round(str2num(get(gcbo, ''String'')));' ...
'lmax = get(gcbo, ''UserData'');' ...
'if (l > lmax), l=lmax; fprintf([''The selected value was too large, or the selected eigenvalues were close to zero\n'']); end;' ...
'f=str2num(get(findobj(''Tag'',''e_first''), ''String''));' ...
'if (l < f), l=f; end;' ...
'set(gcbo, ''String'', int2str(l));' ...
], ...
'BackgroundColor',[1 1 1], ...
'HorizontalAlignment','right', ...
'Position',[0.467936 0.0678168 0.12207 0.0542535], ...
'Style','edit', ...
'String', int2str(maxLastEig), ...
'UserData', maxLastEig, ...
'Tag','e_last');
% in the first version oldDimension was used instead of
% maxLastEig, but since the program would automatically
% drop the eigenvalues afte maxLastEig...
b = uicontrol('Parent',hndl_win, ...
'Units','normalized', ...
'BackgroundColor',[0.701961 0.701961 0.701961], ...
'HorizontalAlignment','left', ...
'Position',[0.427246 0.0678168 0.0406901 0.0542535], ...
'String','to', ...
'Style','text', ...
'Tag','StaticText3');
b = uicontrol('Parent',hndl_win, ...
'Units','normalized', ...
'Callback','uiresume(gcbf)', ...
'Position',[0.630697 0.0678168 0.12207 0.0542535], ...
'String','OK', ...
'Tag','Pushbutton1');
b = uicontrol('Parent',hndl_win, ...
'Units','normalized', ...
'Callback',[ ...
'gui_help(''pcamat'');' ...
], ...
'Position',[0.767008 0.0678168 0.12207 0.0542535], ...
'String','Help', ...
'Tag','Pushbutton2');
h_axes = axes('Position' ,[0.13 0.3 0.775 0.6]);
set(hndl_win, 'currentaxes',h_axes);
bar(eigenvalues);
title('Eigenvalues');
uiwait(hndl_win);
firstEig = str2num(get(e_first, 'String'));
lastEig = str2num(get(e_last, 'String'));
% close the window
close(hndl_win);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% See if the user has reduced the dimension enought
if lastEig > maxLastEig
lastEig = maxLastEig;
if b_verbose
fprintf('Dimension reduced to %d due to the singularity of covariance matrix\n',...
lastEig-firstEig+1);
end
else
% Reduce the dimensionality of the problem.
if b_verbose
if oldDimension == (lastEig - firstEig + 1)
fprintf ('Dimension not reduced.\n');
else
fprintf ('Reducing dimension...\n');
end
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Drop the smaller eigenvalues
if lastEig < oldDimension
lowerLimitValue = (eigenvalues(lastEig) + eigenvalues(lastEig + 1)) / 2;
else
lowerLimitValue = eigenvalues(oldDimension) - 1;
end
lowerColumns = diag(D) > lowerLimitValue;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Drop the larger eigenvalues
if firstEig > 1
higherLimitValue = (eigenvalues(firstEig - 1) + eigenvalues(firstEig)) / 2;
else
higherLimitValue = eigenvalues(1) + 1;
end
higherColumns = diag(D) < higherLimitValue;
% Combine the results from above
selectedColumns = lowerColumns & higherColumns;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% print some info for the user
if b_verbose
fprintf ('Selected [ %d ] dimensions.\n', sum (selectedColumns));
end
if sum (selectedColumns) ~= (lastEig - firstEig + 1),
error ('Selected a wrong number of dimensions.');
end
if b_verbose
fprintf ('Smallest remaining (non-zero) eigenvalue [ %g ]\n', eigenvalues(lastEig));
fprintf ('Largest remaining (non-zero) eigenvalue [ %g ]\n', eigenvalues(firstEig));
fprintf ('Sum of removed eigenvalues [ %g ]\n', sum(diag(D) .* ...
(~selectedColumns)));
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Select the colums which correspond to the desired range
% of eigenvalues.
E = selcol(E, selectedColumns);
D = selcol(selcol(D, selectedColumns)', selectedColumns);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Some more information
if b_verbose
sumAll=sum(eigenvalues);
sumUsed=sum(diag(D));
retained = (sumUsed / sumAll) * 100;
fprintf('[ %g ] %% of (non-zero) eigenvalues retained.\n', retained);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function newMatrix = selcol(oldMatrix, maskVector);
% newMatrix = selcol(oldMatrix, maskVector);
%
% Selects the columns of the matrix that marked by one in the given vector.
% The maskVector is a column vector.
% 15.3.1998
if size(maskVector, 1) ~= size(oldMatrix, 2),
error ('The mask vector and matrix are of uncompatible size.');
end
numTaken = 0;
for i = 1 : size (maskVector, 1),
if maskVector(i, 1) == 1,
takingMask(1, numTaken + 1) = i;
numTaken = numTaken + 1;
end
end
newMatrix = oldMatrix(:, takingMask);