|
a |
|
b/python/evaluation_AAMI.py |
|
|
1 |
#!/usr/bin/env python |
|
|
2 |
|
|
|
3 |
""" |
|
|
4 |
train_SVM.py |
|
|
5 |
|
|
|
6 |
VARPA, University of Coruna |
|
|
7 |
Mondejar Guerra, Victor M. |
|
|
8 |
26 Oct 2017 |
|
|
9 |
""" |
|
|
10 |
|
|
|
11 |
from sklearn import metrics |
|
|
12 |
import numpy as np |
|
|
13 |
|
|
|
14 |
class performance_measures: |
|
|
15 |
def __init__(self, n): |
|
|
16 |
self.n_classes = n |
|
|
17 |
self.confusion_matrix = np.empty([]) |
|
|
18 |
self.Recall = np.empty(n) |
|
|
19 |
self.Precision = np.empty(n) |
|
|
20 |
self.Specificity = np.empty(n) |
|
|
21 |
self.Acc = np.empty(n) |
|
|
22 |
self.F_measure = np.empty(n) |
|
|
23 |
|
|
|
24 |
self.gmean_se = 0.0 |
|
|
25 |
self.gmean_p = 0.0 |
|
|
26 |
|
|
|
27 |
self.Overall_Acc = 0.0 |
|
|
28 |
self.kappa = 0.0 |
|
|
29 |
self.Ij = 0.0 |
|
|
30 |
self.Ijk = 0.0 |
|
|
31 |
|
|
|
32 |
|
|
|
33 |
|
|
|
34 |
# Compute Cohen' kappa from a confussion matrix |
|
|
35 |
# Kappa value: |
|
|
36 |
# < 0.20 Poor |
|
|
37 |
# 0.21-0.40 Fair |
|
|
38 |
# 0.41-0.60 Moderate |
|
|
39 |
# 0.61-0.80 Good |
|
|
40 |
# 0.81-1.00 Very good |
|
|
41 |
def compute_cohen_kappa(confusion_matrix): |
|
|
42 |
prob_expectedA = np.empty(len(confusion_matrix)) |
|
|
43 |
prob_expectedB = np.empty(len(confusion_matrix)) |
|
|
44 |
prob_observed = 0 |
|
|
45 |
|
|
|
46 |
for n in range(0, len(confusion_matrix)): |
|
|
47 |
prob_expectedA[n] = sum(confusion_matrix[n,:]) / sum(sum(confusion_matrix)) |
|
|
48 |
prob_expectedB[n] = sum(confusion_matrix[:,n]) / sum(sum(confusion_matrix)) |
|
|
49 |
|
|
|
50 |
prob_observed = prob_observed + confusion_matrix[n][n] |
|
|
51 |
|
|
|
52 |
prob_expected = np.dot(prob_expectedA, prob_expectedB) |
|
|
53 |
prob_observed = prob_observed / sum(sum(confusion_matrix)) |
|
|
54 |
|
|
|
55 |
kappa = (prob_observed - prob_expected) / (1 - prob_expected) |
|
|
56 |
|
|
|
57 |
return kappa, prob_observed, prob_expected |
|
|
58 |
|
|
|
59 |
# Compute the performance measures following the AAMI recommendations. |
|
|
60 |
# Using sensivity (recall), specificity (precision) and accuracy |
|
|
61 |
# for each class: (N, SVEB, VEB, F) |
|
|
62 |
def compute_AAMI_performance_measures(predictions, gt_labels): |
|
|
63 |
n_classes = 4 #5 |
|
|
64 |
pf_ms = performance_measures(n_classes) |
|
|
65 |
|
|
|
66 |
# TODO If conf_mat no llega a clases 4 por gt_labels o predictions... |
|
|
67 |
# hacer algo para que no falle el codigo... |
|
|
68 |
# NOTE: added labels=[0,1,2,3])... |
|
|
69 |
|
|
|
70 |
# Confussion matrix |
|
|
71 |
conf_mat = metrics.confusion_matrix(gt_labels, predictions, labels=[0,1,2,3]) |
|
|
72 |
conf_mat = conf_mat.astype(float) |
|
|
73 |
pf_ms.confusion_matrix = conf_mat |
|
|
74 |
|
|
|
75 |
# Overall Acc |
|
|
76 |
pf_ms.Overall_Acc = metrics.accuracy_score(gt_labels, predictions) |
|
|
77 |
|
|
|
78 |
# AAMI: Sens, Spec, Acc |
|
|
79 |
# N: 0, S: 1, V: 2, F: 3 # (Q: 4) not used |
|
|
80 |
for i in range(0, n_classes): |
|
|
81 |
TP = conf_mat[i,i] |
|
|
82 |
FP = sum(conf_mat[:,i]) - conf_mat[i,i] |
|
|
83 |
TN = sum(sum(conf_mat)) - sum(conf_mat[i,:]) - sum(conf_mat[:,i]) + conf_mat[i,i] |
|
|
84 |
FN = sum(conf_mat[i,:]) - conf_mat[i,i] |
|
|
85 |
|
|
|
86 |
if i == 2: # V |
|
|
87 |
# Exceptions for AAMI recomendations: |
|
|
88 |
# 1 do not reward or penalize a classifier for the classification of (F) as (V) |
|
|
89 |
FP = FP - conf_mat[i][3] |
|
|
90 |
|
|
|
91 |
pf_ms.Recall[i] = TP / (TP + FN) |
|
|
92 |
pf_ms.Precision[i] = TP / (TP + FP) |
|
|
93 |
pf_ms.Specificity[i] = TN / (TN + FP); # 1-FPR |
|
|
94 |
pf_ms.Acc[i] = (TP + TN) / (TP + TN + FP + FN) |
|
|
95 |
|
|
|
96 |
if TP == 0: |
|
|
97 |
pf_ms.F_measure[i] = 0.0 |
|
|
98 |
else: |
|
|
99 |
pf_ms.F_measure[i] = 2 * (pf_ms.Precision[i] * pf_ms.Recall[i] )/ (pf_ms.Precision[i] + pf_ms.Recall[i]) |
|
|
100 |
|
|
|
101 |
# Compute Cohen's Kappa |
|
|
102 |
pf_ms.kappa, prob_obsv, prob_expect = compute_cohen_kappa(conf_mat) |
|
|
103 |
|
|
|
104 |
# Compute Index-j recall_S + recall_V + precision_S + precision_V |
|
|
105 |
pf_ms.Ij = pf_ms.Recall[1] + pf_ms.Recall[2] + pf_ms.Precision[1] + pf_ms.Precision[2] |
|
|
106 |
|
|
|
107 |
# Compute Index-jk |
|
|
108 |
w1 = 0.5 |
|
|
109 |
w2 = 0.125 |
|
|
110 |
pf_ms.Ijk = w1 * pf_ms.kappa + w2 * pf_ms.Ij |
|
|
111 |
|
|
|
112 |
return pf_ms |
|
|
113 |
|
|
|
114 |
|
|
|
115 |
# Export to filename.txt file the performance measure score |
|
|
116 |
def write_AAMI_results(performance_measures, filename): |
|
|
117 |
|
|
|
118 |
f = open(filename, "w") |
|
|
119 |
|
|
|
120 |
f.write("Ijk: " + str(format(performance_measures.Ijk, '.4f')) + "\n") |
|
|
121 |
f.write("Ij: " + str(format(performance_measures.Ij, '.4f'))+ "\n") |
|
|
122 |
f.write("Cohen's Kappa: " + str(format(performance_measures.kappa, '.4f'))+ "\n\n") |
|
|
123 |
|
|
|
124 |
# Conf matrix |
|
|
125 |
f.write("Confusion Matrix:"+ "\n\n") |
|
|
126 |
f.write("\n".join(str(elem) for elem in performance_measures.confusion_matrix.astype(int))+ "\n\n") |
|
|
127 |
|
|
|
128 |
f.write("Overall ACC: " + str(format(performance_measures.Overall_Acc, '.4f'))+ "\n\n") |
|
|
129 |
|
|
|
130 |
f.write("mean Acc: " + str(format(np.average(performance_measures.Acc[:]), '.4f'))+ "\n") |
|
|
131 |
f.write("mean Recall: " + str(format(np.average(performance_measures.Recall[:]), '.4f'))+ "\n") |
|
|
132 |
f.write("mean Precision: " + str(format(np.average(performance_measures.Precision[:]), '.4f'))+ "\n") |
|
|
133 |
|
|
|
134 |
|
|
|
135 |
f.write("N:"+ "\n\n") |
|
|
136 |
f.write("Sens: " + str(format(performance_measures.Recall[0], '.4f'))+ "\n") |
|
|
137 |
f.write("Prec: " + str(format(performance_measures.Precision[0], '.4f'))+ "\n") |
|
|
138 |
f.write("Acc: " + str(format(performance_measures.Acc[0], '.4f'))+ "\n") |
|
|
139 |
|
|
|
140 |
f.write("SVEB:"+ "\n\n") |
|
|
141 |
f.write("Sens: " + str(format(performance_measures.Recall[1], '.4f'))+ "\n") |
|
|
142 |
f.write("Prec: " + str(format(performance_measures.Precision[1], '.4f'))+ "\n") |
|
|
143 |
f.write("Acc: " + str(format(performance_measures.Acc[1], '.4f'))+ "\n") |
|
|
144 |
|
|
|
145 |
f.write("VEB:"+ "\n\n") |
|
|
146 |
f.write("Sens: " + str(format(performance_measures.Recall[2], '.4f'))+ "\n") |
|
|
147 |
f.write("Prec: " + str(format(performance_measures.Precision[2], '.4f'))+ "\n") |
|
|
148 |
f.write("Acc: " + str(format(performance_measures.Acc[2], '.4f'))+ "\n") |
|
|
149 |
|
|
|
150 |
f.write("F:"+ "\n\n") |
|
|
151 |
f.write("Sens: " + str(format(performance_measures.Recall[3], '.4f'))+ "\n") |
|
|
152 |
f.write("Prec: " + str(format(performance_measures.Precision[3], '.4f'))+ "\n") |
|
|
153 |
f.write("Acc: " + str(format(performance_measures.Acc[3], '.4f'))+ "\n") |
|
|
154 |
|
|
|
155 |
|
|
|
156 |
f.close() |