1 %> @brief Estimation logs base
class.
3 %> Records hits 3D matrix (:)(:)x(time)
5 properties(SetAccess=
private)
11 %> =0. Whether or not to record the "supports" (confidence levels issued by classifiers).
12 %> The default behaviour is to only count the hits for each "time" instant. Recording all the individual
13 %> supports can generate a lot of data, but will allow one to plot the
distribution of supports later.
18 %> Whether there is a "refuse-to-decide" potential situation (usually the @ref
decider of the
object that
19 %> generated the @ref
estlog has a threshold > 0). It is automatically determined by verifying whether there is a non-zero element in the first column
23 properties(SetAccess=protected)
24 %> Same size
as hits, but it is a cell of vectors.
26 %> Whether the class is able to produce the sensitivity and specificity figures
30 properties % (SetAccess=protected)
31 %> 3D matrix: (number of groups)x(number of classes in @c labels_cols + 1)x(time)
36 function flag = get.flag_rejected(o)
37 flag = ~isempty(o.hits) && any(o.hits(:, 1, :) > 0);
41 methods(Access=protected) %, Abstract)
43 function o = do_record(o, pars) %
#ok<*INUSD>
46 function z = get_collabels(o) %#ok<*STOUT>
49 function z = get_rowlabels(o)
53 methods(Access=protected)
55 function o = do_allocate(o, tt)
57 % if nargin > 1 && tt > 1
58 %
irverbose('Warning: do_allocate() called with tt > 1 but flag_inc_t is false, will be ignored', 1);
62 o.hits = zeros(numel(o.rowlabels), numel(o.collabels)+1, tt);
64 % o.rpropv(tt).sup = [];
65 o.supports = cell(numel(o.rowlabels), numel(o.collabels)+1, tt);
73 o.classtitle = 'Estimation';
75 o.moreactions = [o.moreactions, {
'extract_confusion'}];
78 %> Getter
for @c collabels property, calls @c get_collabels() .
79 function z =
get.collabels(o)
80 z = o.get_collabels();
83 %> Getter
for @c rowlabels property, calls @c get_rowlabels() .
84 function z =
get.rowlabels(o)
85 z = o.get_rowlabels();
89 function o = record(o, pars)
90 %
if isempty(o.rowlabels)
93 %
if isempty(o.rowlabels)
98 if o.flag_inc_t || o.t == 0
102 if size(o.hits, 3) < o.t
103 o.hits(numel(o.rowlabels), numel(o.collabels)+1, o.t) = 0; % Ellongates hits
106 o = o.do_record(pars);
109 %> @brief Calculates 0/w weights
for (row)x(time)
113 %> @param t =(1:o.t) Time vector to select only a few time instants
114 %> @param normtype = 0
115 %> @arg @c 0 Non-zero weights are all ones
116 %> @arg @c 1 Weights are normalized so the rows add to 1
117 %> @arg @c 2 Weights are normalized so that the columns add to 1
119 %> @
return A (no_rows)x(o.t) matrix of 0/w to be used
as weights.
120 function W = get_weights(o, t, normtype)
122 if ~exist('t', 'var') || isempty(t) || any(t < 1)
123 C = o.hits(:, :, 1:o.t);
127 if nargin < 3 || isempty(normtype)
131 S = permute(sum(C, 2), [1, 3, 2]);
136 CB = sum(B, 2)+realmin; % How many time instants at any row actually have something in that row
137 W = B./repmat(CB, 1, size(B, 2));
139 CB = sum(B, 1)+realmin;
140 W = B./repmat(CB, size(B, 1), 1);
145 %> @brief Flexible function to return a calculation over the "hits" matrix (or parts thereof)
147 %> Example: <code>get_C([], 1, 2, 1)</code> Gets average percentage with discounted rejected items
149 %> @param t =(all). Pre-selection of specific times
150 %> @param flag_perc1 =0. Whether to calculate percentages already at each time instant
151 %> @param
aggr Time-wise Aggregation:
152 %> @arg @c 0 - none</li>
153 %> @arg @c 1 - Sum</li>
154 %> @arg @c 2 - time-wise Sum -> row-wise normalization (rows sum to 1, except if total sum is zero)</li>
155 %> @arg @c 3 - Mean</li>
156 %> @arg @c 4 - Standard Deviation</li></ul></li>
157 %> @param flag_discount_rejected =1. Whether to discount the rejected items from percentages. Only applicable if @c flag_perc is true
160 %> @note Percentual outputs range from 0 to 100, not from 0 to 1
161 function C = get_C(o, t, flag_perc,
aggr, flag_discount_rejected)
163 if nargin < 2 || isempty(t) || any(t < 1)
164 C = o.hits(:, :, 1:o.t);
169 if nargin < 3 || isempty(flag_perc)
173 if nargin < 4 || isempty(aggr)
177 if nargin < 5 || isempty(flag_discount_rejected)
178 flag_discount_rejected = 1;
181 [nrow, ncol, nt] = size(C);
183 if ~flag_perc && flag_discount_rejected
190 S = sum(C(:, :, i), 2);
191 C(:, :, i) = 100*C(:, :, i)./(repmat(S, 1, ncol)+realmin);
194 if flag_discount_rejected
197 C(i, 2:end, j) = 100*C(i, 2:end, j)/(100-C(i, 1, j)+realmin);
208 irerror('EstLog: Invalid aggregation: Sum of percentages does not make sense!');
212 case 2 % time-wise Sum -> row-wise normalization (rows sum to 1, except if total sum is zero)
214 irerror('EstLog: Invalid aggregation: Per-row normalization of percentages does not make sense!');
219 S(S == 0) = 1; % makes 0/0 divisions into 0/1 ones
220 C = C./repmat(S, 1, ncol);
223 irerror('EstLog: Invalid aggregation: Mean of hits does not make sense!');
226 S = sum(sum(C, 2) ~= 0, 3); % counts non-zero t-wise rows for each row
227 C = sum(C, 3)./(repmat(S, 1, ncol)+realmin);
228 case 4 % Standard deviation
230 irerror('EstLog: Invalid aggregation: Standard deviation of hits does not make sense!');
233 T = zeros(nrow, ncol);
236 sel = sum(temp, 2) ~= 0;
237 T(i, :) = std(temp(1, :, sel), [], 3);
241 irerror(sprintf('Invalid option: %d', aggr));
248 %> <li>Aggregation:<ul>
249 %> <li>@c 0 - INVALID</li>
250 %> <li>@c 1 - INVALID</li>
251 %> <li>@c 2 - INVALID</li>
252 %> <li>@c 3 - Mean</li>
253 %> <li>@c 4 - Standard Deviation</li></ul></li>
254 %> <li>@c 5 - Minimum</li></ul></li>
255 %> <li>@c 6 - Maximum</li></ul></li>
258 %> @brief Gets the recorded supports
259 function C = get_C_supp(o, t, aggr)
261 irerror('Not recording supports!');
265 if ~exist('t', 'var') || isempty(t) || sum(t < 1)
268 S = o.supports(:, :, t);
272 [ni, nj, nk] = size(o.supports); %
#ok<NASGU>
292 irerror(sprintf('Invalid option: %d', aggr));
298 function oc = get_confusion_from_C(o, C, flag_perc)
300 oc.collabels = o.get_collabels();
301 oc.rowlabels = o.get_rowlabels();
302 oc.flag_perc = flag_perc;
306 function oc = get_confusion_sup(o, t, aggr)
307 if ~exist('t', 'var')
310 C = o.get_C_supp(t, aggr);
311 oc = o.get_confusion_from_C(C);
315 function oc = get_confusion(o, t, flag_perc, aggr, flag_discount_rejected)
316 if ~exist('t', 'var')
319 if ~exist('flag_perc', 'var')
322 if ~exist('aggr', 'var')
326 if ~exist('flag_discount_rejected', 'var')
327 flag_discount_rejected = 0;
330 C = o.get_C(t, flag_perc, aggr, flag_discount_rejected);
331 oc = o.get_confusion_from_C(C, flag_perc);
334 %> @param flag_individual Whether to print time snapshots
as well.
335 function s = get_insane_html(o, pars)
336 if ~exist('pars', 'var'); pars = struct(); end;
337 if ~isfield(pars, 'flag_individual')
340 flag_individual = pars.flag_individual;
342 if ~isfield(pars, 'flag_discount_rejected')
343 flag_discount_rejected = 0;
345 flag_discount_rejected = pars.flag_discount_rejected;
347 if ~isfield(pars, 'flag_balls')
350 flag_balls = pars.flag_balls;
354 s = ['<h1>', o.get_description(), '</h1>', 10];
358 oc = o.get_confusion([], 1, 3, flag_discount_rejected);
363 s = cat(2, s,
irreport.save_n_close([], 0));
368 s = cat(2, s, '<h2>Confusion Matrices</h2>', 10);
369 s = cat(2, s, '<h3>Overall</h3>', 10);
370 s = cat(2, s, '<h4>Percentages</h4>', 10);
371 s = cat(2, s, '<h5>Mean</h5>', 10);
372 oc = o.get_confusion([], 1, 3, flag_discount_rejected); s = cat(2, s, '<center>', oc.get_html_table(), '</center>');
373 s = cat(2, s, '<h5>Standard Deviation</h5>', 10);
374 oc = o.get_confusion([], 1, 4);
375 s = cat(2, s, '<center>', oc.get_html_table(), '</center>');
376 s = cat(2, s, '<h4>Accumulated hits</h4>', 10);
377 oc = o.get_confusion([], 0, 1); s = cat(2, s, '<center>', oc.get_html_table(), '</center>');
380 s = cat(2, s, '<h4>Supports</h4>', 10);
381 s = cat(2, s, '<h5>Mean</h5>', 10);
382 oc = o.get_confusion_sup([], 3); s = cat(2, s, '<center>', oc.get_html_table(), '</center>');
383 s = cat(2, s, '<h5>Standard Deviation</h5>', 10);
384 oc = o.get_confusion_sup([], 4); s = cat(2, s, '<center>', oc.get_html_table(), '</center>');
386 s = cat(2, s, '<hr/>', 10);
390 ss = {
'Hits',
'Percentages'};
391 s = cat(2, s,
'<h3>Individual</h3>', 10);
393 s = cat(2, s,
'<h4>', ss{i},
'</h4>', 10);
395 oc = o.get_confusion(j, i-1, 0, flag_discount_rejected); s = cat(2, s,
'<center>', oc.get_html_table(),
'</center>');
397 s = cat(2, s,
'<hr/>', 10);
401 s = cat(2, s,
'<h4>Supports (means)</h4>', 10);
403 oc = o.get_confusion_sup(j, 3); s = cat(2, s,
'<center>', oc.get_html_table(),
'</center>');
405 s = cat(2, s,
'<hr/>', 10);
411 %> Generates one dataset per row containing percentages.
412 %> The i-th dataset, j-th feature corresponds to the classification rates of consufion cell (i, j) (rejected
414 function dd = extract_datasets(o)
416 irwarning(
'Are you sure you want to extract datasets from estlog that has less than 10 confusion matrices?');
418 [nr, nf, no] = size(o.hits); %#ok<NASGU>
419 rl = o.get_rowlabels();
420 C = o.get_C([], 1, 0);
421 C = permute(C, [3, 2, 1]);
425 d.title = [
'Row ', int2str(i),
' - ', rl{i}];
427 d.fea_names = strcat(
'Column "', [
'Rejected', o.get_collabels()],
'"');
433 %> Each cell needs be a different dataset because number of supports (therefore dataset
's @c no ) is different for each cell.
435 %> @param ij (number of datasets)x(2) containing coordinates from the confusion matrix to extract supports from.
436 %> Please note that j=1 is the "rejected" column, not the first colummn class.
437 function dd = extract_datasets_sup(o, ij)
439 cl = o.get_collabels();
440 rl = o.get_rowlabels();
445 d.X = [o.supports{i, j, :}]';
447 collabel =
'Rejected';
451 d.title = [
'Supports ', rl{i},
'->', collabel];
453 d.fea_names = {[
'Support ', rl{i},
'->', collabel]};
459 %> Abstract. Classification rate, accuracy, performance or whatever.
460 function z = get_rate(o)
464 %> Abstract. Classification rate vector calculated time-wise.
465 function z = get_rates(o)
466 z = zeros(1, size(o.hits, 3));
469 function oc = extract_confusion(o)
470 oc = o.get_confusion([], 1, 3);
473 %> Whether the values returned by get_rate() and get_rates() are percentages or not. Returns TRUE
474 function z = get_flag_perc(o)
478 function z = get_unit(o)
function irverbose(in s, in level)
Visualization - Balls visualization for Confusion Matrices.
Base class for all ensemble classifiers.
Block that resolves estimato posterior probabilities into classes.
Estimation logs base class.
function distribution(in x, in no_points, in range, in wid)
Property X
[no]x[nf] matrix. Data matrix
Class representing a Confusion matrix.
Analysis Session (AS) base class.