%% (Internal) Pretty-Display results of a classification experiment % % [dsResult ConfusionMat lablist global_performances ] = DisplayResults( varargin ) % % Arguments: % % - dsResult % % - bWithFeatMat % % - priors % % - TrueLabels % % - ClassifiedLabels % % - datasetName % % - ClassLabels % % - class_filter % % - SupportDataset % % - TrainedMapping % % Output: % % - SupportDataset % % - TrainedMapping % % - SupportDataset % % - TrainedMapping % % Example % % % \ecg-kit\common\prtools_addins\roc_detection.m (Line 137) % [~, this_iter_cm] = DisplayResults( 'TrueLabels', typical_lablist(true_labels,:), ... % 'class_filter', class_filter, ... % 'ClassifiedLabels', typical_lablist(Labels,:), ... % 'ClassLabels', typical_lablist); % % % \ecg-kit\common\a2hbc\scripts\ResultsForAllDatabases.m (Line 83) % [~,~,~, global_performances] = DisplayResults( ... % 'dsResult', nansum(ConfusionMatrix,4), ... % 'datasetName', DB_name, ... % 'ClassLabels', Lablist); % % See also DisplayResults, ResultsForAllDatabases, roc_detection % % Author: Mariano Llamedo Soria llamedom@electron.frba.utn.edu.ar % Version: 0.1 beta % Last update: 14/5/2014 % Birthdate : 21/4/2015 % Copyright 2008-2015 % function [dsResult ConfusionMat lablist global_performances ] = DisplayResults( varargin ) p = inputParser; % Create instance of inputParser class. p.addParamValue('dsResult', [], @(x)( isnumeric(x) | isa(x,'prdataset') ) ); p.addParamValue('bWithFeatMat', true, @islogical); p.addParamValue('priors', [], @isnumeric); p.addParamValue('TrueLabels', [], @(x)(isnumeric(x) || ischar(x))); p.addParamValue('ClassifiedLabels', [], @(x)(isnumeric(x) || ischar(x))); p.addParamValue('datasetName', [], @ischar); p.addParamValue('ClassLabels', [], @(x)( ischar(x) )); p.addParamValue('class_filter', [], @(x)( ischar(x) )); p.addParamValue('SupportDataset', [], @(x)( isa(x,'prdataset') )); p.addParamValue('TrainedMapping', [], @(x)( isa(x,'prmapping') && istrained(x)) ); try p.parse( varargin{:}); catch MyError rethrow(MyError); end dsResult = p.Results.dsResult; bWithFeatMat = p.Results.bWithFeatMat; priors = p.Results.priors; TrueLabels = p.Results.TrueLabels; ClassifiedLabels = p.Results.ClassifiedLabels; datasetName = p.Results.datasetName; ClassLabels = p.Results.ClassLabels; SupportDataset = p.Results.SupportDataset; w_TrainedMapping = p.Results.TrainedMapping; class_filter = p.Results.class_filter; labels_not_learned_idx = []; cant_iter = 1; global_performances = []; if( isdataset(dsResult) ) if( ~isempty(w_TrainedMapping) ) dsTrain_lablist = getlabels(w_TrainedMapping); dsTest_lablist = getlablist(dsResult); [labels_not_learned labels_not_learned_idx ] = setdiff(dsTest_lablist, dsTrain_lablist, 'rows'); dsResult = dsResult * w_TrainedMapping; %Hago esto para que no batchee ... % dsResult = map(dsResult, w_TrainedMapping, 500e3); else dsTest_lablist = getlablist(dsResult); [labels_not_learned labels_not_learned_idx ] = setdiff(dsTest_lablist, ClassLabels, 'rows'); end if(bWithFeatMat) % confmat(dsResult) confmat_new(dsResult) end if( isempty(datasetName) ) datasetName = getname(dsResult); end [ConfusionMat, ~,lablist] = confmat_new(dsResult); % [ConfusionMat, ~, lablist] = confmat(dsResult); if( size(lablist,1) < size(ConfusionMat,2) ) %hay clase reject bRejectClass = true; rejected = ConfusionMat(:,end); not_labeled = ConfusionMat(end,:); ConfusionMat = ConfusionMat(1:end-1,1:end-1); else bRejectClass = false; end priors = getprior(dsResult); elseif( isempty(dsResult) && ~isempty(TrueLabels) && ~isempty(ClassifiedLabels) ) if( isempty(ClassLabels) ) confmat_new(TrueLabels, ClassifiedLabels); [ConfusionMat, ~, lablist] = confmat_new(TrueLabels, ClassifiedLabels); else [labels_not_learned labels_not_learned_idx ] = setdiff( unique(TrueLabels, 'rows'), ClassLabels, 'rows'); if( ischar(TrueLabels) && ischar(ClassifiedLabels) ) confmat_new(TrueLabels, ClassifiedLabels, 'count', 1, ClassLabels ); [ConfusionMat, ~, lablist] = confmat_new(TrueLabels, ClassifiedLabels, 'count', 1, ClassLabels ); elseif( isnumeric(TrueLabels) && isnumeric(ClassifiedLabels) ) confmat_new(ClassLabels(TrueLabels,:), ClassLabels(ClassifiedLabels,:)); [ConfusionMat, ~, lablist] = confmat_new(ClassLabels(TrueLabels,:), ClassLabels(ClassifiedLabels,:) ); else error('Tipo de datos no permitidos en las etiquetas.' ) end end if( size(lablist,1) < size(ConfusionMat,2) ) %hay clase reject bRejectClass = true; rejected = ConfusionMat(:,end); not_labeled = ConfusionMat(end,:); ConfusionMat = ConfusionMat(1:end-1,1:end-1); else bRejectClass = false; end elseif( isnumeric(dsResult) ) ConfusionMat = dsResult; iCantClases = size(ConfusionMat,2); bRejectClass = false; if( ~isempty(SupportDataset) ) datasetName = getname(SupportDataset); priors = getprior(SupportDataset); lablist = getlablist(SupportDataset); else if( isempty(priors) ) %Equal priors warning('Assumnig equal priors.') priors = ones(iCantClases,1)/iCantClases; end if( isempty(ClassLabels) ) lablist = [ repmat('Class ', iCantClases, 1) num2str((1:iCantClases)')]; else lablist = ClassLabels; end end cant_iter = size(ConfusionMat,3); DisplayConfusionMatrix(ConfusionMat, lablist); else error('Argumentos no reconocidos'); end %filtro de clases if( isempty(class_filter) ) %todas las clases class_filter_idx = 1:size(lablist,1); else [~, class_filter_idx ] = intersect(cellstr(lablist), cellstr(class_filter)); class_filter_idx = rowvec(class_filter_idx); % ConfusionMat_orig = ConfusionMat; % lablist_orig = lablist; % % cant_clases_filt = length(class_filter_idx); % ConfusionMat = zeros(cant_clases_filt); % % for ii = 1:cant_clases_filt % ConfusionMat(ii,:) = ConfusionMat_orig(class_filter_idx(ii), class_filter_idx); % ConfusionMat(:,ii) = ConfusionMat_orig(class_filter_idx, class_filter_idx(ii)); % end % lablist = lablist_orig(class_filter_idx,:); end %Las seņalo ya que requieren un tratamiento especial segun AAMI-EC57. Unknown_idx = find(strcmpi(cellstr(lablist),'Unknown')); Fusion_idx = find(strcmpi(cellstr(lablist),'Fusion')); Supra_idx = find(strcmpi(cellstr(lablist),'Supraventricular')); Ventri_idx = find(strcmpi(cellstr(lablist),'Ventricular')); % %Ignoramos la clase Unknown para el calculo de resultados si existe. % Unknown_idx = find(strcmpi(cellstr(lablist),'Unknown')); % % if( ~isempty(Unknown_idx) ) % %Elimino esa clase. % lablist_orig = lablist; % lablist(Unknown_idx,:) = []; % ConfusionMat_orig = ConfusionMat; % ConfusionMat(Unknown_idx,:,:) = []; % ConfusionMat(:,Unknown_idx,:) = []; % end %Corrregiremos la matriz de confusion si hay clases no aprendidas. Cant_real_x_clase = squeeze(sum(ConfusionMat,2)); Cant_predecida_x_clase = squeeze(sum(ConfusionMat,1)); ClasesPresentes_idx = find(Cant_real_x_clase > 0); ClasesPredichas_idx = find(Cant_predecida_x_clase > 0); if( ~isempty(labels_not_learned_idx) ) %las clases no aprendidas, hago como que no estan presentes para la contabilizacion de %resultados. ClasesPresentes_idx(labels_not_learned_idx) = []; %y por otro lado agrupo en la diagonal las clasificaciones de las %clases que no fueron aprendidas. % esto es por si quisiera contabilizarlo como acierto, creo que % directamente hay que ignorarlo % for ii = find((ClasesPredichas_idx(:))') % ConfusionMat(ii,ii) = ConfusionMat(ii,ii) + ConfusionMat(labels_not_learned_idx,ii); % ConfusionMat(labels_not_learned_idx,ii) = 0; % end %anulo las clases no entrenadas para que no contabilicen en los %resultados. ConfusionMat(labels_not_learned_idx,:) = 0; Cant_real_x_clase = sum(ConfusionMat,2); Cant_predecida_x_clase = sum(ConfusionMat)'; ClasesPresentes_idx = find(Cant_real_x_clase ~= 0); ClasesPredichas_idx = find(Cant_predecida_x_clase ~= 0); end %Una vuelta para mostrar los resultados balanceados y otra %desbalanceados. for jj = 1:2 performance = []; if(jj == 1) strAux = ['Balanced Results for ' datasetName]; else strAux = ['Unbalanced Results for ' datasetName]; end disp(strAux) disp( repmat('-',1,length(strAux)) ); if(bRejectClass) strPerfMeasures = '| Se +P Rej |'; else if( cant_iter == 1 ) % strPerfMeasures = '| Se +P FPR |'; strPerfMeasures = '| Se +P |'; else strPerfMeasures = '| Se +P |'; end end iFieldWidth = length(strPerfMeasures) - 4; iLablistWidth = size(lablist,2); for ii = class_filter_idx fprintf(1, [ '| ' lablist(ii,1:min(iFieldWidth, iLablistWidth)) repmat(' ', 1, iFieldWidth-iLablistWidth) ' |' ]); end if(bRejectClass) fprintf(1, [ '| TOTALS |\n' ]); else if( cant_iter == 1 ) fprintf(1, [ '| TOTALS |\n' ]); else fprintf(1, [ '| TOTALS |\n' ]); end end for ii = class_filter_idx fprintf(1, strPerfMeasures); end if(bRejectClass) fprintf(1, [ '| Acc | Se | +P | Reject |\n' ]); else if( cant_iter == 1 ) fprintf(1, [ '| Acc | Se | +P |\n' ]); else fprintf(1, [ '| Acc | Se | +P |\n' ]); end end ConfusionMat_bal = zeros(size(ConfusionMat)); if(jj == 1) %Balanceamos las clases para que las mediciones de performance no %tengan sesgo k_x_clase = repmat(max(Cant_real_x_clase, [], 1), size(Cant_real_x_clase, 1), 1) ; k_x_clase(ClasesPresentes_idx) = k_x_clase(ClasesPresentes_idx) ./ Cant_real_x_clase(ClasesPresentes_idx); if( cant_iter == 1) ConfusionMat_bal = ConfusionMat .* repmat( k_x_clase, 1, size(ConfusionMat,2) ); else ConfusionMat_bal = cellfun( @(a,b)(round( a .* repmat( b, 1, size(a,2) ))), mat2cell(ConfusionMat, size(ConfusionMat,1), size(ConfusionMat,2), ones(1,size(ConfusionMat,3))) , reshape(mat2cell(k_x_clase, size(k_x_clase,1), ones(1,size(k_x_clase,2)) ), [1 1 size(k_x_clase,2)] ) , 'UniformOutput', false); ConfusionMat_bal = cell2mat(ConfusionMat_bal); end if(bRejectClass) rejected_bal = rejected(ClasesPresentes_idx) .* k_x_clase; end else % ConfusionMat_bal(ClasesPresentes_idx,:) = ConfusionMat(ClasesPresentes_idx,:); ConfusionMat_bal = ConfusionMat; if(bRejectClass) rejected_bal = rejected(ClasesPresentes_idx); end end for ii = class_filter_idx if( sum(Cant_real_x_clase(ii,:)) == 0 ) if(bRejectClass) fprintf(1, '| -- -- -- |' ); aux = nan(1,3); else if( cant_iter > 1 ) fprintf(1, '| --( --)%% --( --)%% |' ); aux = nan(1,4); else fprintf(1, '| -- -- |' ); aux = nan(1,2); end end else iTP = squeeze(ConfusionMat_bal(ii,ii,:)); iFN = colvec(sum(squeeze(ConfusionMat_bal(ii,:,:)))) - iTP; PosPred = colvec(sum(squeeze(ConfusionMat_bal(:,ii,:)))); % AAMI special treatment for P+ calculation if( ~isempty(Supra_idx) && ~isempty(Unknown_idx) && Supra_idx == ii ) %Descuento los unknown PosPred = PosPred - colvec(squeeze(ConfusionMat_bal(Unknown_idx,ii,:))); end if( ~isempty(Ventri_idx) && Ventri_idx == ii ) if( ~isempty(Unknown_idx) ) %Descuento los unknown PosPred = PosPred - colvec(squeeze(ConfusionMat_bal(Unknown_idx,ii,:))); end if( ~isempty(Fusion_idx) ) %Descuento los unknown PosPred = PosPred - colvec(squeeze(ConfusionMat_bal(Fusion_idx,ii,:))); end end if( PosPred ~= 0) PosPred = iTP./PosPred*100; else PosPred = zeros(1,cant_iter); end % iFP = sum(ConfusionMat_bal(:,ii)) - iTP; % iTN = sum(sum(ConfusionMat_bal)) - sum(ConfusionMat_bal(ii,:)) - sum(ConfusionMat_bal(:,ii)) + iTP; if(bRejectClass) aux = [iTP/(iTP+iFN)*100, PosPred, rejected_bal(ii)/(rejected_bal(ii)+iTP+iFN)*100 ]; fprintf(1, [ '| %3.0f%% %3.0f%% %3.0f%% |' ], aux); else if( cant_iter > 1 ) aux = [ median(iTP./(iTP+iFN))*100, mad(iTP./(iTP+iFN),1)*100, median(PosPred), mad(PosPred,1) ]; fprintf(1, [ '| %3.0f(%3.0f)%% %3.0f(%3.0f)%% |' ], aux ); else aux = [ iTP/(iTP+iFN)*100, PosPred ]; fprintf(1, [ '| %3.0f%% %3.0f%% |' ], aux ); end end end performance = [ performance aux]; end priors = priors(:); if( cant_iter == 1) Aciertos = diag(ConfusionMat_bal); else Aciertos = cellfun(@(a)(diag(a)), mat2cell(ConfusionMat_bal, size(ConfusionMat_bal,1), size(ConfusionMat_bal,2), ones(1,size(ConfusionMat_bal,3))), 'UniformOutput', false ); Aciertos = squeeze(cell2mat(Aciertos)); end Cant_real_x_clase_bal = colvec(squeeze(sum(ConfusionMat_bal,2))); Cant_predecida_x_clase_bal = colvec(squeeze(sum(ConfusionMat_bal))); ClasesPresentes_bal_idx = find(Cant_real_x_clase_bal ~= 0); ClasesPredichas_bal_idx = find(Cant_predecida_x_clase_bal ~= 0); if(bRejectClass) aux = [ ... (sum(Aciertos(ClasesPresentes_bal_idx))/sum(sum(ConfusionMat_bal)))*100, ... mean(Aciertos(ClasesPresentes_bal_idx)./Cant_real_x_clase_bal(ClasesPresentes_bal_idx))*100, ... mean(Aciertos(ClasesPredichas_bal_idx)./Cant_predecida_x_clase_bal(ClasesPredichas_bal_idx))*100, ... sum(rejected_bal)/(sum(rejected_bal) + sum(sum(ConfusionMat_bal)))*100 ]; fprintf(1, [ '| %3.0f%% | %3.0f%% | %3.0f%% | %3.0f%% |' ], aux); else if( cant_iter > 1 ) aux_s = nan(size(Aciertos)); aux_s(ClasesPresentes_bal_idx) = Aciertos(ClasesPresentes_bal_idx)./Cant_real_x_clase_bal(ClasesPresentes_bal_idx); aux_s = nanmean(aux_s,1); aux_p = nan(size(Aciertos)); aux_p(ClasesPresentes_bal_idx) = 0; aux_p(ClasesPredichas_bal_idx) = colvec(Aciertos(ClasesPredichas_bal_idx)./Cant_predecida_x_clase_bal(ClasesPredichas_bal_idx)); ... % %funciona mal cuando no predice una clase % aux_p(ClasesPresentes_bal_idx) = Aciertos(ClasesPresentes_bal_idx)./Cant_predecida_x_clase_bal(ClasesPresentes_bal_idx); aux_p = nanmean( aux_p ,1); aux = [ ... median(colvec(sum(Aciertos))./squeeze(sum(sum(ConfusionMat_bal,1),2)))*100, ... mad(colvec(sum(Aciertos))./squeeze(sum(sum(ConfusionMat_bal,1),2)),1)*100, ... median(aux_s)*100, ... mad(aux_s,1)*100, ... median(aux_p)*100, ... mad(aux_p,1)*100 ]; fprintf(1, [ '| %3.0f(%3.0f)%% | %3.0f(%3.0f)%% | %3.0f(%3.0f)%% |' ], aux); else aux = [ ... (sum(Aciertos(ClasesPresentes_bal_idx))/sum(sum(ConfusionMat_bal)))*100, ... mean(Aciertos(ClasesPresentes_bal_idx)./Cant_real_x_clase_bal(ClasesPresentes_bal_idx))*100, ... mean([Aciertos(ClasesPredichas_bal_idx)./Cant_predecida_x_clase_bal(ClasesPredichas_bal_idx); zeros(abs(length(ClasesPresentes_bal_idx)-length(ClasesPredichas_bal_idx)),1) ])*100 ... ... % %funciona mal cuando no predice una clase ... % mean(Aciertos(ClasesPresentes_bal_idx)./Cant_predecida_x_clase_bal(ClasesPresentes_bal_idx))*100 ... ]; fprintf(1, [ '| %3.0f%% | %3.0f%% | %3.0f%% |' ], aux ); end end performance = [ performance aux]; global_performances(jj,:) = performance; fprintf(1, '\n\n'); end if( bRejectClass && any( not_labeled > 0 ) ) warning( ['Se encontraron ' num2str( sum(not_labeled) ) ' datos no etiquetados.' ] ) end % if( ~isempty(Unknown_idx) ) % %Vuelvo al estado original la CM y el lablist. % lablist = lablist_orig ; % ConfusionMat = ConfusionMat_orig ; % end %% Debug, borrarme % fprintf(1, 'Debug:\n'); % % fprintf(1, repmat([repmat('%3.0f\t', 1, size(performance,2)) '\n'], 1,size(performance,1)), performance' ); %% FIN Debug, borrarme