Source code for pycaps.verify.MulticlassContingencyTable
import numpy as np
__author__ = 'David John Gagne <djgagne@ou.edu>'
[docs]def mct_main():
# Contingency Table from Wilks (2011) Table 8.3
table = np.array([[50, 91, 71],
[47, 2364, 170],
[54, 205, 3288]])
mct = MulticlassContingencyTable(table, n_classes=table.shape[0],
class_names = np.arange(table.shape[0]).astype(str))
print mct.peirce_skill_score()
print mct.gerrity_score()
[docs]class MulticlassContingencyTable(object):
"""
This class is a container for a contingency table containing more than 2 classes.
The contingency table is stored in table as a numpy array with the rows corresponding to forecast categories,
and the columns corresponding to observation categories.
"""
def __init__(self, table=None, n_classes=2, class_names=("1", "0")):
self.table = table
self.n_classes = n_classes
self.class_names = class_names
if table is None:
self.table = np.zeros((self.n_classes, self.n_classes), dtype=int)
def __add__(self, other):
assert self.n_classes == other.n_classes, "Number of classes does not match"
return MulticlassContingencyTable(self.table + other.table,
n_classes=self.n_classes,
class_names=self.class_names)
[docs] def peirce_skill_score(self):
"""
Multiclass Peirce Skill Score (also Hanssen and Kuipers score, True Skill Score)
"""
n = float(self.table.sum())
nf = self.table.sum(axis=1)
no = self.table.sum(axis=0)
correct = float(self.table.trace())
return (correct / n - (nf * no).sum() / n ** 2) / (1 - (no * no).sum() / n ** 2)
[docs] def gerrity_score(self):
"""
Gerrity Score, which weights each cell in the contingency table by its observed relative frequency.
:return:
"""
k = self.table.shape[0]
n = float(self.table.sum())
p_o = self.table.sum(axis=0) / n
p_sum = np.cumsum(p_o)[:-1]
a = (1.0 - p_sum) / p_sum
s = np.zeros(self.table.shape, dtype=float)
for (i, j) in np.ndindex(*s.shape):
if i == j:
s[i, j] = 1.0 / (k - 1.0) * (np.sum(1.0 / a[0:j]) + np.sum(a[j:k-1]))
elif i < j:
s[i, j] = 1.0 / (k - 1.0) * (np.sum(1.0 / a[0:i]) - (j - i) + np.sum(a[j:k-1]))
else:
s[i, j] = s[j, i]
return np.sum(self.table / float(self.table.sum()) * s)
[docs] def heidke_skill_score(self):
n = float(self.table.sum())
nf = self.table.sum(axis=1)
no = self.table.sum(axis=0)
correct = float(self.table.trace())
return (correct / n - (nf * no).sum() / n ** 2) / (1 - (nf * no).sum() / n ** 2)
if __name__ == "__main__":
mct_main()