-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpfp_cmmetric.m
136 lines (127 loc) · 4.32 KB
/
pfp_cmmetric.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
function [m] = pfp_cmmetric(cm, metric, varargin)
%PFP_CMMETRIC Confusion matrix metric
%
% [m] = PFP_CMMETRIC(cm, metric, p);
%
% Gets metric from confusion matrixs.
%
% Input
% -----
% [double]
% cm: n-by-4, The four cells of the confusion matrix.
% cm(:, 1) - TN, true negative.
% cm(:, 2) - FP, false positive.
% cm(:, 3) - FN, false negative.
% cm(:, 4) - TP, true positive.
%
% Note that each row of cm construct a confusion matrix, and they are
% evaluated independently.
%
% [char]
% metric: Desired metric, should be one of the following:
% 'pr' - precision, recall
% 'wpr' - weighted precision, recall
% 'rm' - RU, MI
% 'nrm' - normalized RU, MI
% 'f' - F-measure
% 'wf' - weighted F-measure
% 'sd' - semantic distance
% 'nsd' - normalized semantic distance
% 'ss' - sensitivity, 1 - specificity (points on ROC)
% 'acc' - accuracy
%
% (optional) Name, Value pairs
% [double]
% 'beta': used as beta in F_{beta}-measure.
% default: 1
%
% [double]
% 'order': used as the order of semantic distance.
% default: 2
%
% Output
% ------
% [double]
% m: The resulting metric with the size n-by-1 or n-by-2 depending on 'metric'.
%
% See Also
% --------
%[>]pfp_seqcm.m
% check inputs {{{
if nargin < 2
error('pfp_cmmetric:InputCount', 'Expected >= 2 inputs.');
end
% cm
validateattributes(cm, {'double'}, {'ncols', 4}, '', 'cm', 1);
TN = full(cm(:, 1));
FP = full(cm(:, 2));
FN = full(cm(:, 3));
TP = full(cm(:, 4));
% metric
metric_opt = {'pr', 'wpr', 'rm', 'nrm', 'f', 'wf', 'sd', 'nsd', 'ss', 'acc'};
validatestring(metric, metric_opt, '', 'metric', 2);
% }}}
% parse additional inputs {{{
p = inputParser;
defaultBETA = 1;
defaultORDER = 2;
addParameter(p, 'beta', defaultBETA, @(x) validateattributes(x, {'double'}, {'real', 'positive'}));
addParameter(p, 'order', defaultORDER, @(x) validateattributes(x, {'double'}, {'real', 'positive'}));
parse(p, varargin{:});
% }}}
% compute metric {{{
if strcmpi(metric, 'pr') || strcmpi(metric, 'wpr')
% m = [(weighted) precision, (weighted) recall]
% Precision can be NaN for (TP + FP) = 0, no (positive) prediction
% recall can be NaN for (FP + FN) = 0, no (positive) annotation
m = [TP ./ (TP + FP), TP ./ (TP + FN)];
elseif strcmpi(metric, 'rm')
% m = [RU, MI]
% Both RU and MI should never be NaN.
m = [FN, FP]; % ru: weighted FN; mi: weighted FP.
elseif strcmpi(metric, 'nrm')
% m = [normalized RU, normalized MI]
% Both normalized RU and normalized MI could be NaN in the case that no
% (positive) prediction and no (positive) annotation.
m = [FN, FP] ./ repmat(FN + TP + FP, 1, 2);
elseif strcmpi(metric, 'f') || strcmpi(metric, 'wf')
% m = [(weighted) F]
% (Weighted) F can be NaN in any of these 3 cases:
% 1. No predictions: TP = FP = 0
% 2. No annotations: TP = FN = 0
% 3. No true positives: TP = 0 (i.e. pr = rc = 0)
pr_rc = [TP ./ (TP + FP), TP ./ (TP + FN)];
pr = pr_rc(:, 1);
rc = pr_rc(:, 2);
m = (1 + p.Results.beta .^ 2) .* pr .* rc ./ (p.Results.beta .^ 2 .* pr + rc);
elseif strcmpi(metric, 'sd')
% m = [semantic distance]
% SD can never be NaN
ru = FN;
mi = FP;
m = (ru .^ p.Results.order + mi .^ p.Results.order) .^ (1 ./ p.Results.order);
elseif strcmpi(metric, 'nsd')
% m = [normalized semantic distance]
% normalized SD can be NaN when neither (positive) prediction nor (positive)
% annotation.
nru_nmi = [FN, FP] ./ repmat(FN + TP + FP, 1, 2);
nru = nru_nmi(:, 1);
nmi = nru_nmi(:, 2);
m = (nru .^ p.Results.order + nmi .^ p.Results.order) .^ (1 ./ p.Results.order);
elseif strcmpi(metric, 'ss')
% TPR (sensitivity, recall) can be NaN for no (positive) annotations
% FPR (1 - specificity) can be NaN for no (negative) annotations
m = [TP ./ (TP + FN), FP ./ (TN + FP)];
elseif strcmpi(metric, 'acc')
% Accuracy should never be NaN
m = (TN + TP) ./ (TN + TP + FP + FN);
else
error('pfp_cmmetric:UnknownMetric', 'Unknown metric.');
end
% }}}
return
% -------------
% Yuxiang Jiang ([email protected])
% Department of Computer Science
% Indiana University Bloomington
% Last modified: Tue 24 May 2016 02:34:44 PM E