-
Notifications
You must be signed in to change notification settings - Fork 0
/
Risk.py
111 lines (94 loc) · 4.43 KB
/
Risk.py
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
# Subjects(Difficulty) -> Annotations -> Classifiers(Skill)
import scipy.stats as scistats
import numpy as np
from Annotations import Annotations
from AnnotationModels import AnnotationModelBase, AnnotationPriorBase
from Subjects import Subject, Subjects
class LossModelBase():
"""Base class. Subclasses evaluate the loss associated with predicting a label
given a nominal true label. Note that the loss model should include the case when
the predicted and true labels are equal.
"""
def __init__(self):
pass
def __call__(self, trueLabel, predictedLabel):
pass
class LossModelBinary(LossModelBase):
def __init__(self, falsePosLoss=1, falseNegLoss=1):
self._falsePosLoss = falsePosLoss
self._falseNegLoss = falseNegLoss
def __call__(self, trueLabel, predictedLabel):
if trueLabel and not predictedLabel:
# False Negative
return self._falseNegLoss
elif predictedLabel and not trueLabel:
#False positive
return self._falsePosLoss
else:
return 0
@property
def falsePosLoss(self):
return self._falsePosLoss
@falsePosLoss.setter
def falsePosLoss(self, falsePosLoss):
self._falsePosLoss = falsePosLoss
@property
def falseNegLoss(self):
return self._falseNegLoss
@falseNegLoss.setter
def falseNegLoss(self, falseNegLoss):
self._falseNegLoss = falseNegLoss
class Risk():
"""Computes a metric that can be used to define decision thresholds for each
subject based on its classification history.
"""
def __call__(self, annotations, subject, lossModel, annotationModel,
annotationPriorModel):
"""Evaluate the risk.
Arguments:
-- annotations - Annotations class encapsulating all annotations pertaining to this
subject.
-- subject - Subject class encapsulating the information about this subject.
-- lossModel - Subclass of LossModelBase that quantifies the loss of predicting
a label given a nominal true label.
-- annotationModel - Subclass of AnnotationModelBase that computes the posterior
probability of a particuler classifier assigning a particular label given a
specific true label, given the annotation history of all classifiers.
-- annotationModel - Subclass of AnnotationPriorBase that computes the prior
probability of any classifier assigning a particular label given a specific true
label.
"""
if not isinstance(annotations, Annotations):
raise TypeError(
'The annotations argument must be of type {}. Type {} passed.'.
format(type(Annotations).__name__, type(annotations)))
if not isinstance(subject, Subject):
raise TypeError(
'The subject argument must be of type {}. Type {} passed.'.
format(type(Subject).__name__, type(subject)))
if not issubclass(type(lossModel), LossModelBase):
raise TypeError(
'The lossModel argument must inherit from {}. Type {} passed.'.
format(type(LossModelBase).__name__, type(lossModel)))
if not issubclass(type(annotationModel), AnnotationModelBase):
raise TypeError(
'The annotationModel argument must inherit from {}. Type {} passed.'.
format(type(AnnotationModelBase).__name__, type(annotationModel)))
if not issubclass(type(annotationPriorModel), AnnotationPriorBase):
raise TypeError(
'The annotationPriorModel argument must inherit from {}. Type {} passed.'.
format(type(AnnotationPriorBase).__name__, type(annotationPriorModel)))
trueLabelRisks = []
posteriorProbSum = 0
for trueLabel in annotations.getUniqueLabels():
posteriorProb = annotationPriorModel(trueLabel) * np.prod([
annotationModel(trueLabel, annotation)
for annotation in annotations.items()
])
# print('posteriorProb =>', posteriorProb, 'lossModel(trueLabel, subject.trueLabel) =>', lossModel(trueLabel, subject.trueLabel))
# print(trueLabel, subject.trueLabel)
trueLabelRisks.append(
(lossModel(trueLabel, subject.trueLabel) * posteriorProb))
posteriorProbSum += posteriorProb
risk = np.sum(trueLabelRisks)/posteriorProbSum
return risk