Completed
Branch master (87ccc1)
by Chris
08:42
created

tests.stats.test_stats_confusion_table   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 603
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 417
dl 0
loc 603
rs 8.64
c 0
b 0
f 0
wmc 47

How to fix   Complexity   

Complexity

Complex classes like tests.stats.test_stats_confusion_table often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
3
# Copyright 2014-2018 by Christopher C. Little.
4
# This file is part of Abydos.
5
#
6
# Abydos is free software: you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation, either version 3 of the License, or
9
# (at your option) any later version.
10
#
11
# Abydos is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with Abydos. If not, see <http://www.gnu.org/licenses/>.
18
19
"""abydos.tests.test_stats_confusion_table.
20
21
This module contains unit tests for abydos.stats.confusion_table
22
"""
23
24
from __future__ import division, unicode_literals
25
26
import unittest
27
from math import isnan, sqrt
28
29
from abydos.stats.confusion_table import ConfusionTable
30
31
32
UNIT_TABLE = ConfusionTable(1, 1, 1, 1)
33
NULL_TABLE = ConfusionTable(0, 0, 0, 0)
34
SCALE_TABLE = ConfusionTable(1, 2, 3, 4)
35
# https://en.wikipedia.org/wiki/Confusion_matrix#Table_of_confusion
36
CATSNDOGS_TABLE = ConfusionTable(5, 17, 2, 3)
37
# https://en.wikipedia.org/wiki/Sensitivity_and_specificity#Worked_example
38
WORKED_EG_TABLE = ConfusionTable(20, 1820, 180, 10)
39
VERY_POOR_TABLE = ConfusionTable(0, 0, 200, 200)
40
41
ALL_TABLES = (UNIT_TABLE, NULL_TABLE, SCALE_TABLE, CATSNDOGS_TABLE,
42
              WORKED_EG_TABLE, VERY_POOR_TABLE)
43
44
# def ct2arrays(ct):
45
#     y_pred = []
46
#     y_true = []
47
#     y_pred += [1]*ct.tpos
48
#     y_true += [1]*ct.tpos
49
#     y_pred += [0]*ct.tneg
50
#     y_true += [0]*ct.tneg
51
#     y_pred += [1]*ct.fpos
52
#     y_true += [0]*ct.fpos
53
#     y_pred += [0]*ct.fneg
54
#     y_true += [1]*ct.fneg
55
#     return y_pred, y_true
56
57
58
class ConstructorTestCases(unittest.TestCase):
59
    """Test abydos.stats.confusion_table.ConfusionTable constructors."""
60
61
    def test_constructors(self):
62
        """Test abydos.stats.confusion_table.ConfusionTable constructors."""
63
        self.assertEqual(ConfusionTable(), ConfusionTable())
64
        self.assertEqual(ConfusionTable(), ConfusionTable(0))
65
        self.assertEqual(ConfusionTable(), ConfusionTable(0, 0))
66
        self.assertEqual(ConfusionTable(), ConfusionTable(0, 0, 0))
67
        self.assertEqual(ConfusionTable(), ConfusionTable(0, 0, 0, 0))
68
        self.assertNotEquals(ConfusionTable(), ConfusionTable(1))
69
        self.assertNotEquals(ConfusionTable(), ConfusionTable(0, 1))
70
        self.assertNotEquals(ConfusionTable(), ConfusionTable(0, 0, 1))
71
        self.assertNotEquals(ConfusionTable(), ConfusionTable(0, 0, 0, 1))
72
73
        # test int constructor & __eq__ by value
74
        self.assertEqual(SCALE_TABLE, ConfusionTable(1, 2, 3, 4))
75
        # test tuple constructor
76
        self.assertEqual(SCALE_TABLE, ConfusionTable((1, 2, 3, 4)))
77
        self.assertEqual(SCALE_TABLE, ConfusionTable((1, 2, 3, 4), 5, 6, 7))
78
        # test list constructor
79
        self.assertEqual(SCALE_TABLE, ConfusionTable([1, 2, 3, 4]))
80
        self.assertEqual(SCALE_TABLE, ConfusionTable([1, 2, 3, 4], 5, 6, 7))
81
        # test dict constructor
82
        self.assertEqual(SCALE_TABLE, ConfusionTable({'tp': 1, 'tn': 2,
83
                                                      'fp': 3, 'fn': 4}))
84
        self.assertEqual(SCALE_TABLE, ConfusionTable({'tp': 1, 'tn': 2,
85
                                                      'fp': 3, 'fn': 4},
86
                                                     5, 6, 7))
87
        self.assertEqual(NULL_TABLE, ConfusionTable({}))
88
        self.assertEqual(NULL_TABLE, ConfusionTable({'pt': 1, 'nt': 2,
89
                                                     'pf': 3, 'nf': 4}))
90
91
        # test __eq__ by id()
92
        self.assertTrue(SCALE_TABLE == SCALE_TABLE)
93
        self.assertFalse(CATSNDOGS_TABLE == SCALE_TABLE)
94
        # test __eq__ by tuple
95
        self.assertTrue(SCALE_TABLE == (1, 2, 3, 4))
96
        self.assertFalse(CATSNDOGS_TABLE == (1, 2, 3, 4))
97
        # test __eq__ by list
98
        self.assertTrue(SCALE_TABLE == [1, 2, 3, 4])
99
        self.assertFalse(CATSNDOGS_TABLE == [1, 2, 3, 4])
100
        # test __eq__ by dict
101
        self.assertTrue(SCALE_TABLE == {'tp': 1, 'tn': 2,
102
                                        'fp': 3, 'fn': 4})
103
        self.assertFalse(CATSNDOGS_TABLE == {'tp': 1, 'tn': 2,
104
                                             'fp': 3, 'fn': 4})
105
        # test __eq__ with non-ConfusionTable/tuple/list/dict
106
        self.assertFalse(SCALE_TABLE == 5)
107
108
        # test invalid tuple constructor
109
        self.assertRaises(AttributeError, ConfusionTable, (1, 2,))
110
111
112
class CastTestCases(unittest.TestCase):
113
    """Test abydos.stats.confusion_table.ConfusionTable cast methods."""
114
115
    def test_to_tuple(self):
116
        """Test abydos.stats.confusion_table.ConfusionTable.to_tuple."""
117
        self.assertIsInstance(SCALE_TABLE.to_tuple(), tuple)
118
        self.assertEqual(SCALE_TABLE.to_tuple(), (1, 2, 3, 4))
119
        self.assertEqual(list(SCALE_TABLE.to_tuple()), [1, 2, 3, 4])
120
121
    def test_to_dict(self):
122
        """Test abydos.stats.confusion_table.ConfusionTable.to_dict."""
123
        self.assertIsInstance(SCALE_TABLE.to_dict(), dict)
124
        self.assertEqual(SCALE_TABLE.to_dict(), {'tp': 1, 'tn': 2,
125
                                                 'fp': 3, 'fn': 4})
126
127
    def test_str(self):
128
        """Test abydos.stats.confusion_table.ConfusionTable._str_."""
129
        self.assertIsInstance(str(SCALE_TABLE), str)
130
        self.assertEqual(str(SCALE_TABLE), 'tp:1, tn:2, fp:3, fn:4')
131
132
133
class PopulationTestCases(unittest.TestCase):
134
    """Test abydos.stats.confusion_table.ConfusionTable population methods."""
135
136
    def test_correct_pop(self):
137
        """Test abydos.stats.confusion_table.ConfusionTable.correct_pop."""
138
        self.assertEqual(UNIT_TABLE.correct_pop(), 2)
139
        self.assertEqual(NULL_TABLE.correct_pop(), 0)
140
        self.assertEqual(SCALE_TABLE.correct_pop(), 3)
141
        self.assertEqual(CATSNDOGS_TABLE.correct_pop(), 22)
142
        self.assertEqual(WORKED_EG_TABLE.correct_pop(), 1840)
143
144
    def test_error_pop(self):
145
        """Test abydos.stats.confusion_table.ConfusionTable.error_pop."""
146
        self.assertEqual(UNIT_TABLE.error_pop(), 2)
147
        self.assertEqual(NULL_TABLE.error_pop(), 0)
148
        self.assertEqual(SCALE_TABLE.error_pop(), 7)
149
        self.assertEqual(CATSNDOGS_TABLE.error_pop(), 5)
150
        self.assertEqual(WORKED_EG_TABLE.error_pop(), 190)
151
152
    def test_test_pos_pop(self):
153
        """Test abydos.stats.confusion_table.ConfusionTable.test_pos_pop."""
154
        self.assertEqual(UNIT_TABLE.test_pos_pop(), 2)
155
        self.assertEqual(NULL_TABLE.test_pos_pop(), 0)
156
        self.assertEqual(SCALE_TABLE.test_pos_pop(), 4)
157
        self.assertEqual(CATSNDOGS_TABLE.test_pos_pop(), 7)
158
        self.assertEqual(WORKED_EG_TABLE.test_pos_pop(), 200)
159
160
    def test_test_neg_pop(self):
161
        """Test abydos.stats.confusion_table.ConfusionTable.test_neg_pop."""
162
        self.assertEqual(UNIT_TABLE.test_neg_pop(), 2)
163
        self.assertEqual(NULL_TABLE.test_neg_pop(), 0)
164
        self.assertEqual(SCALE_TABLE.test_neg_pop(), 6)
165
        self.assertEqual(CATSNDOGS_TABLE.test_neg_pop(), 20)
166
        self.assertEqual(WORKED_EG_TABLE.test_neg_pop(), 1830)
167
168
    def test_cond_pos_pop(self):
169
        """Test abydos.stats.confusion_table.ConfusionTable.cond_pos_pop."""
170
        self.assertEqual(UNIT_TABLE.cond_pos_pop(), 2)
171
        self.assertEqual(NULL_TABLE.cond_pos_pop(), 0)
172
        self.assertEqual(SCALE_TABLE.cond_pos_pop(), 5)
173
        self.assertEqual(CATSNDOGS_TABLE.cond_pos_pop(), 8)
174
        self.assertEqual(WORKED_EG_TABLE.cond_pos_pop(), 30)
175
176
    def test_cond_neg_pop(self):
177
        """Test abydos.stats.confusion_table.ConfusionTable.cond_neg_pop."""
178
        self.assertEqual(UNIT_TABLE.cond_neg_pop(), 2)
179
        self.assertEqual(NULL_TABLE.cond_neg_pop(), 0)
180
        self.assertEqual(SCALE_TABLE.cond_neg_pop(), 5)
181
        self.assertEqual(CATSNDOGS_TABLE.cond_neg_pop(), 19)
182
        self.assertEqual(WORKED_EG_TABLE.cond_neg_pop(), 2000)
183
184
    def test_population(self):
185
        """Test abydos.stats.confusion_table.ConfusionTable.population."""
186
        self.assertEqual(UNIT_TABLE.population(), 4)
187
        self.assertEqual(NULL_TABLE.population(), 0)
188
        self.assertEqual(SCALE_TABLE.population(), 10)
189
        self.assertEqual(CATSNDOGS_TABLE.population(), 27)
190
        self.assertEqual(WORKED_EG_TABLE.population(), 2030)
191
192
193
class StatisticalRatioTestCases(unittest.TestCase):
194
    """Test abydos.stats.confusion_table.ConfusionTable ratio methods."""
195
196
    def test_precision(self):
197
        """Test abydos.stats.confusion_table.ConfusionTable.precision."""
198
        self.assertEqual(UNIT_TABLE.precision(), 0.5)
199
        self.assertTrue(isnan(NULL_TABLE.precision()))
200
        self.assertAlmostEqual(SCALE_TABLE.precision(), 0.25)
201
        self.assertAlmostEqual(CATSNDOGS_TABLE.precision(), 5/7)
202
        self.assertAlmostEqual(WORKED_EG_TABLE.precision(), 0.1)
203
204
    def test_precision_gain(self):
205
        """Test abydos.stats.confusion_table.ConfusionTable.precision_gain."""
206
        self.assertEqual(UNIT_TABLE.precision_gain(), 1)
207
        self.assertTrue(isnan(NULL_TABLE.precision_gain()))
208
        self.assertAlmostEqual(SCALE_TABLE.precision_gain(), 0.25/0.5)
209
        self.assertAlmostEqual(CATSNDOGS_TABLE.precision_gain(), (5/7)/(8/27))
210
        self.assertAlmostEqual(WORKED_EG_TABLE.precision_gain(), 0.1/(30/2030))
211
212
    def test_recall(self):
213
        """Test abydos.stats.confusion_table.ConfusionTable.recall."""
214
        self.assertEqual(UNIT_TABLE.recall(), 0.5)
215
        self.assertTrue(isnan(NULL_TABLE.recall()))
216
        self.assertAlmostEqual(SCALE_TABLE.recall(), 0.2)
217
        self.assertAlmostEqual(CATSNDOGS_TABLE.recall(), 5/8)
218
        self.assertAlmostEqual(WORKED_EG_TABLE.recall(), 2/3)
219
220
    def test_specificity(self):
221
        """Test abydos.stats.confusion_table.ConfusionTable.specificity."""
222
        self.assertEqual(UNIT_TABLE.specificity(), 0.5)
223
        self.assertTrue(isnan(NULL_TABLE.specificity()))
224
        self.assertAlmostEqual(SCALE_TABLE.specificity(), 0.4)
225
        self.assertAlmostEqual(CATSNDOGS_TABLE.specificity(), 17/19)
226
        self.assertAlmostEqual(WORKED_EG_TABLE.specificity(), 0.91)
227
228
    def test_npv(self):
229
        """Test abydos.stats.confusion_table.ConfusionTable.npv."""
230
        self.assertEqual(UNIT_TABLE.npv(), 0.5)
231
        self.assertTrue(isnan(NULL_TABLE.npv()))
232
        self.assertAlmostEqual(SCALE_TABLE.npv(), 1/3)
233
        self.assertAlmostEqual(CATSNDOGS_TABLE.npv(), 17/20)
234
        self.assertAlmostEqual(WORKED_EG_TABLE.npv(), 182/183)
235
236
    def test_fallout(self):
237
        """Test abydos.stats.confusion_table.ConfusionTable.fallout."""
238
        self.assertEqual(UNIT_TABLE.fallout(), 0.5)
239
        self.assertTrue(isnan(NULL_TABLE.fallout()))
240
        self.assertAlmostEqual(SCALE_TABLE.fallout(), 0.6)
241
        self.assertAlmostEqual(CATSNDOGS_TABLE.fallout(), 2/19)
242
        self.assertAlmostEqual(WORKED_EG_TABLE.fallout(), 0.09)
243
244
    def test_fdr(self):
245
        """Test abydos.stats.confusion_table.ConfusionTable.fdr."""
246
        self.assertEqual(UNIT_TABLE.fdr(), 0.5)
247
        self.assertTrue(isnan(NULL_TABLE.fdr()))
248
        self.assertAlmostEqual(SCALE_TABLE.fdr(), 0.75)
249
        self.assertAlmostEqual(CATSNDOGS_TABLE.fdr(), 2/7)
250
        self.assertAlmostEqual(WORKED_EG_TABLE.fdr(), 0.9)
251
252
    def test_accuracy(self):
253
        """Test abydos.stats.confusion_table.ConfusionTable.accuracy."""
254
        self.assertEqual(UNIT_TABLE.accuracy(), 0.5)
255
        self.assertTrue(isnan(NULL_TABLE.accuracy()))
256
        self.assertAlmostEqual(SCALE_TABLE.accuracy(), 3/10)
257
        self.assertAlmostEqual(CATSNDOGS_TABLE.accuracy(), 22/27)
258
        self.assertAlmostEqual(WORKED_EG_TABLE.accuracy(), 184/203)
259
260
    def test_accuracy_gain(self):
261
        """Test abydos.stats.confusion_table.ConfusionTable.accuracy_gain."""
262
        self.assertEqual(UNIT_TABLE.accuracy_gain(), 1)
263
        self.assertTrue(isnan(NULL_TABLE.accuracy_gain()))
264
        self.assertAlmostEqual(SCALE_TABLE.accuracy_gain(),
265
                               (3/10)/((5/10)**2+(5/10)**2))
266
        self.assertAlmostEqual(CATSNDOGS_TABLE.accuracy_gain(),
267
                               (22/27)/((8/27)**2+(19/27)**2))
268
        self.assertAlmostEqual(WORKED_EG_TABLE.accuracy_gain(),
269
                               (184/203)/((30/2030)**2+(2000/2030)**2))
270
271
    def test_balanced_accuracy(self):
272
        """Test abydos.stats.confusion_table.ConfusionTable.balanced_accuracy."""  # noqa: E501
273
        self.assertEqual(UNIT_TABLE.balanced_accuracy(), 0.5)
274
        self.assertTrue(isnan(NULL_TABLE.balanced_accuracy()))
275
        self.assertAlmostEqual(SCALE_TABLE.balanced_accuracy(), 0.3)
276
        self.assertAlmostEqual(CATSNDOGS_TABLE.balanced_accuracy(), 231/304)
277
        self.assertAlmostEqual(WORKED_EG_TABLE.balanced_accuracy(), 473/600)
278
279
    def test_informedness(self):
280
        """Test abydos.stats.confusion_table.ConfusionTable.informedness."""
281
        self.assertEqual(UNIT_TABLE.informedness(), 0)
282
        self.assertTrue(isnan(NULL_TABLE.informedness()))
283
        self.assertAlmostEqual(SCALE_TABLE.informedness(), -0.4)
284
        self.assertAlmostEqual(CATSNDOGS_TABLE.informedness(), 79/152)
285
        self.assertAlmostEqual(WORKED_EG_TABLE.informedness(), 2/3-0.09)
286
287
    def test_markedness(self):
288
        """Test abydos.stats.confusion_table.ConfusionTable.markedness."""
289
        self.assertEqual(UNIT_TABLE.markedness(), 0)
290
        self.assertTrue(isnan(NULL_TABLE.markedness()))
291
        self.assertAlmostEqual(SCALE_TABLE.markedness(), -5/12)
292
        self.assertAlmostEqual(CATSNDOGS_TABLE.markedness(), 79/140)
293
        self.assertAlmostEqual(WORKED_EG_TABLE.markedness(), 173/1830)
294
295
296
class PrMeansTestCases(unittest.TestCase):
297
    """Test abydos.stats.confusion_table.ConfusionTable PR methods."""
298
299
    prre = tuple(((i.precision(), i.recall()) for i in ALL_TABLES))
300
301
    def test_pr_amean(self):
302
        """Test abydos.stats.confusion_table.ConfusionTable.pr_amean."""
303
        self.assertEqual(UNIT_TABLE.pr_amean(), 0.5)
304
        self.assertTrue(isnan(NULL_TABLE.pr_amean()))
305
        self.assertAlmostEqual(SCALE_TABLE.pr_amean(), 0.225)
306
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_amean(), 0.6696428571428572)
307
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_amean(), 0.3833333333333333)
308
        self.assertAlmostEqual(VERY_POOR_TABLE.pr_amean(), 0.0)
309
310
    def test_pr_gmean(self):
311
        """Test abydos.stats.confusion_table.ConfusionTable.pr_gmean."""
312
        self.assertEqual(UNIT_TABLE.pr_gmean(), 0.5)
313
        self.assertTrue(isnan(NULL_TABLE.pr_gmean()))
314
        self.assertAlmostEqual(SCALE_TABLE.pr_gmean(), 0.22360679774997899)
315
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_gmean(), 0.66815310478106094)
316
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_gmean(), 0.25819888974716115)
317
        self.assertAlmostEqual(VERY_POOR_TABLE.pr_gmean(), 0.0)
318
319
    def test_pr_hmean(self):
320
        """Test abydos.stats.confusion_table.ConfusionTable.pr_hmean."""
321
        self.assertEqual(UNIT_TABLE.pr_hmean(), 0.5)
322
        self.assertTrue(isnan(NULL_TABLE.pr_hmean()))
323
        self.assertAlmostEqual(SCALE_TABLE.pr_hmean(), 0.22222222222222221)
324
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_hmean(), 0.66666666666666663)
325
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_hmean(), 0.17391304347826086)
326
        self.assertAlmostEqual(VERY_POOR_TABLE.pr_hmean(), 0.0)
327
328
    def test_pr_qmean(self):
329
        """Test abydos.stats.confusion_table.ConfusionTable.pr_qmean."""
330
        self.assertEqual(UNIT_TABLE.pr_qmean(),
331
                         sqrt(sum(i**2 for i in self.prre[0])/2))
332
        self.assertTrue(isnan(NULL_TABLE.pr_qmean()))
333
        self.assertAlmostEqual(SCALE_TABLE.pr_qmean(),
334
                               sqrt(sum(i**2 for i in self.prre[2])/2))
335
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_qmean(),
336
                               sqrt(sum(i**2 for i in self.prre[3])/2))
337
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_qmean(),
338
                               sqrt(sum(i**2 for i in self.prre[4])/2))
339
        self.assertAlmostEqual(VERY_POOR_TABLE.pr_qmean(), 0.0)
340
341
    def test_pr_cmean(self):
342
        """Test abydos.stats.confusion_table.ConfusionTable.pr_cmean."""
343
        self.assertEqual(UNIT_TABLE.pr_cmean(), 0.5)
344
        self.assertTrue(isnan(NULL_TABLE.pr_cmean()))
345
        self.assertAlmostEqual(SCALE_TABLE.pr_cmean(), 41/180)
346
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_cmean(), 113/168)
347
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_cmean(), 409/690)
348
349
    def test_pr_lmean(self):
350
        """Test abydos.stats.confusion_table.ConfusionTable.pr_lmean."""
351
        self.assertEqual(UNIT_TABLE.pr_lmean(), 0.5)
352
        self.assertTrue(isnan(NULL_TABLE.pr_lmean()))
353
        self.assertAlmostEqual(SCALE_TABLE.pr_lmean(), 0.2240710058862275)
354
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_lmean(), 0.6686496151266621)
355
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_lmean(), 0.2986983802717959)
356
        self.assertAlmostEqual(VERY_POOR_TABLE.pr_lmean(), 0.0)
357
358
    def test_pr_imean(self):
359
        """Test abydos.stats.confusion_table.ConfusionTable.pr_imean."""
360
        self.assertEqual(UNIT_TABLE.pr_imean(), 0.5)
361
        self.assertTrue(isnan(NULL_TABLE.pr_imean()))
362
        self.assertAlmostEqual(SCALE_TABLE.pr_imean(), 0.224535791730617)
363
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_imean(), 0.6691463467789889)
364
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_imean(), 0.34277561539033635)
365
        self.assertTrue(isnan(VERY_POOR_TABLE.pr_imean()))
366
367
    def test_pr_seiffert_mean(self):
368
        """Test abydos.stats.confusion_table.ConfusionTable.pr_seiffert_mean."""  # noqa: E501
369
        self.assertTrue(isnan(UNIT_TABLE.pr_seiffert_mean()))
370
        self.assertTrue(isnan(NULL_TABLE.pr_seiffert_mean()))
371
        self.assertAlmostEqual(SCALE_TABLE.pr_seiffert_mean(), 0.2245354073)
372
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_seiffert_mean(),
373
                               0.6691461993)
374
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_seiffert_mean(),
375
                               0.3406355792)
376
        self.assertTrue(isnan(VERY_POOR_TABLE.pr_seiffert_mean()))
377
378
    def test_pr_lehmer_mean(self):
379
        """Test abydos.stats.confusion_table.ConfusionTable.pr_lehmer_mean."""
380
        self.assertEqual(UNIT_TABLE.pr_lehmer_mean(3), 0.5)
381
        self.assertTrue(isnan(NULL_TABLE.pr_lehmer_mean(3)))
382
        self.assertAlmostEqual(SCALE_TABLE.pr_lehmer_mean(3), 189/820)
383
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_lehmer_mean(3), 4275/6328)
384
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_lehmer_mean(3), 8027/12270)
385
386
        self.assertEqual(UNIT_TABLE.pr_lehmer_mean(), 0.5)
387
        self.assertTrue(isnan(NULL_TABLE.pr_lehmer_mean()))
388
        self.assertAlmostEqual(SCALE_TABLE.pr_lehmer_mean(), 41/180)
389
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_lehmer_mean(), 113/168)
390
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_lehmer_mean(), 409/690)
391
392
        self.assertEqual(UNIT_TABLE.pr_lehmer_mean(2), 0.5)
393
        self.assertTrue(isnan(NULL_TABLE.pr_lehmer_mean(2)))
394
        self.assertAlmostEqual(SCALE_TABLE.pr_lehmer_mean(2), 41/180)
395
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_lehmer_mean(2), 113/168)
396
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_lehmer_mean(2), 409/690)
397
398
        # check equivalences to other specific means
399
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_lehmer_mean(0),
400
                               WORKED_EG_TABLE.pr_hmean())
401
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_lehmer_mean(0.5),
402
                               WORKED_EG_TABLE.pr_gmean())
403
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_lehmer_mean(1),
404
                               WORKED_EG_TABLE.pr_amean())
405
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_lehmer_mean(2),
406
                               WORKED_EG_TABLE.pr_cmean())
407
408
    def test_pr_heronian_mean(self):
409
        """Test abydos.stats.confusion_table.ConfusionTable.pr_heronian_mean."""  # noqa: E501
410
        self.assertEqual(UNIT_TABLE.pr_heronian_mean(), 0.5)
411
        self.assertTrue(isnan(NULL_TABLE.pr_heronian_mean()))
412
        self.assertAlmostEqual(SCALE_TABLE.pr_heronian_mean(), 0.2245355992)
413
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_heronian_mean(),
414
                               0.6691462730)
415
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_heronian_mean(),
416
                               0.3416218521)
417
        self.assertEqual(VERY_POOR_TABLE.pr_heronian_mean(), 0)
418
419
    def test_pr_hoelder_mean(self):
420
        """Test abydos.stats.confusion_table.ConfusionTable.pr_hoelder_mean."""
421
        self.assertEqual(UNIT_TABLE.pr_hoelder_mean(), 0.5)
422
        self.assertTrue(isnan(NULL_TABLE.pr_hoelder_mean()))
423
        self.assertAlmostEqual(SCALE_TABLE.pr_hoelder_mean(),
424
                               0.22638462845343543)
425
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_hoelder_mean(),
426
                               0.6711293026059334)
427
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_hoelder_mean(),
428
                               0.4766783215358364)
429
430
        self.assertEqual(UNIT_TABLE.pr_hoelder_mean(0), 0.5)
431
        self.assertTrue(isnan(NULL_TABLE.pr_hoelder_mean(0)))
432
        self.assertAlmostEqual(SCALE_TABLE.pr_hoelder_mean(0),
433
                               0.22360679774997899)
434
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_hoelder_mean(0),
435
                               0.66815310478106094)
436
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_hoelder_mean(0),
437
                               0.25819888974716115)
438
439
        self.assertEqual(UNIT_TABLE.pr_hoelder_mean(1), 0.5)
440
        self.assertTrue(isnan(NULL_TABLE.pr_hoelder_mean(1)))
441
        self.assertAlmostEqual(SCALE_TABLE.pr_hoelder_mean(1), 9/40)
442
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_hoelder_mean(1), 75/112)
443
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_hoelder_mean(1), 23/60)
444
445
        self.assertEqual(UNIT_TABLE.pr_hoelder_mean(2), 0.5)
446
        self.assertTrue(isnan(NULL_TABLE.pr_hoelder_mean(2)))
447
        self.assertAlmostEqual(SCALE_TABLE.pr_hoelder_mean(2),
448
                               0.22638462845343543)
449
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_hoelder_mean(2),
450
                               0.6711293026059334)
451
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_hoelder_mean(2),
452
                               0.4766783215358364)
453
454
        self.assertEqual(UNIT_TABLE.pr_hoelder_mean(3), 0.5)
455
        self.assertTrue(isnan(NULL_TABLE.pr_hoelder_mean(3)))
456
        self.assertAlmostEqual(SCALE_TABLE.pr_hoelder_mean(3),
457
                               0.2277441728906747)
458
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_hoelder_mean(3),
459
                               0.6726059172248808)
460
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_hoelder_mean(3),
461
                               0.5297282909519099)
462
463
        # check equivalences to other specific means
464
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_hoelder_mean(-1),
465
                               WORKED_EG_TABLE.pr_hmean())
466
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_hoelder_mean(0),
467
                               WORKED_EG_TABLE.pr_gmean())
468
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_hoelder_mean(1),
469
                               WORKED_EG_TABLE.pr_amean())
470
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_hoelder_mean(2),
471
                               WORKED_EG_TABLE.pr_qmean())
472
473
    def test_pr_agmean(self):
474
        """Test abydos.stats.confusion_table.ConfusionTable.pr_agmean.
475
476
        Test values computed via http://arithmeticgeometricmean.blogspot.de/
477
        """
478
        self.assertEqual(UNIT_TABLE.pr_agmean(), 0.5)
479
        self.assertTrue(isnan(NULL_TABLE.pr_agmean()))
480
        self.assertAlmostEqual(SCALE_TABLE.pr_agmean(), 0.2243028580287603)
481
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_agmean(), 0.6688977735879823)
482
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_agmean(), 0.3176780357448827)
483
        self.assertAlmostEqual(VERY_POOR_TABLE.pr_agmean(), 0.0)
484
485
    def test_pr_ghmean(self):
486
        """Test abydos.stats.confusion_table.ConfusionTable.pr_ghmean."""
487
        self.assertEqual(UNIT_TABLE.pr_ghmean(), 0.5)
488
        self.assertTrue(isnan(NULL_TABLE.pr_ghmean()))
489
        self.assertAlmostEqual(SCALE_TABLE.pr_ghmean(), 0.2229128974)
490
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_ghmean(), 0.6674092650)
491
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_ghmean(), 0.2098560781)
492
        self.assertAlmostEqual(VERY_POOR_TABLE.pr_ghmean(), 0.0)
493
494
    def test_pr_aghmean(self):
495
        """Test abydos.stats.confusion_table.ConfusionTable.pr_aghmean."""
496
        self.assertEqual(UNIT_TABLE.pr_aghmean(), 0.5)
497
        self.assertTrue(isnan(NULL_TABLE.pr_aghmean()))
498
        self.assertAlmostEqual(SCALE_TABLE.pr_aghmean(), 0.2236067977)
499
        self.assertAlmostEqual(CATSNDOGS_TABLE.pr_aghmean(), 0.6681531047)
500
        self.assertAlmostEqual(WORKED_EG_TABLE.pr_aghmean(), 0.2581988897)
501
        self.assertAlmostEqual(VERY_POOR_TABLE.pr_aghmean(), 0.0)
502
503
504
class StatisticalMeasureTestCases(unittest.TestCase):
505
    """Test abydos.stats.confusion_table.ConfusionTable stats functions."""
506
507
    prre = tuple(((i.precision(), i.recall()) for i in ALL_TABLES))
508
509
    def test_fbeta_score(self):
510
        """Test abydos.stats.confusion_table.ConfusionTable.fbeta_score."""
511
        self.assertEqual(UNIT_TABLE.fbeta_score(1), 0.5)
512
        self.assertTrue(isnan(NULL_TABLE.fbeta_score(1)))
513
        self.assertAlmostEqual(SCALE_TABLE.fbeta_score(1), 2/9)
514
        self.assertAlmostEqual(CATSNDOGS_TABLE.fbeta_score(1), 2/3)
515
        self.assertAlmostEqual(WORKED_EG_TABLE.fbeta_score(1), 4/23)
516
        self.assertRaises(AttributeError, UNIT_TABLE.fbeta_score, -1)
517
518
    def test_f2_score(self):
519
        """Test abydos.stats.confusion_table.ConfusionTable.f2_score."""
520
        self.assertEqual(UNIT_TABLE.f2_score(), 0.5)
521
        self.assertTrue(isnan(NULL_TABLE.f2_score()))
522
        self.assertAlmostEqual(SCALE_TABLE.f2_score(), 5/24)
523
        self.assertAlmostEqual(CATSNDOGS_TABLE.f2_score(), 25/39)
524
        self.assertAlmostEqual(WORKED_EG_TABLE.f2_score(), 5/16)
525
526
    def test_fhalf_score(self):
527
        """Test abydos.stats.confusion_table.ConfusionTable.fhalf_score."""
528
        self.assertEqual(UNIT_TABLE.fhalf_score(), 0.5)
529
        self.assertTrue(isnan(NULL_TABLE.fhalf_score()))
530
        self.assertAlmostEqual(SCALE_TABLE.fhalf_score(), 5/21)
531
        self.assertAlmostEqual(CATSNDOGS_TABLE.fhalf_score(), 25/36)
532
        self.assertAlmostEqual(WORKED_EG_TABLE.fhalf_score(), 10/83)
533
534
    def test_e_score(self):
535
        """Test abydos.stats.confusion_table.ConfusionTable.e_score."""
536
        self.assertEqual(UNIT_TABLE.e_score(), 0.5)
537
        self.assertTrue(isnan(NULL_TABLE.e_score()))
538
        self.assertAlmostEqual(SCALE_TABLE.e_score(), 7/9)
539
        self.assertAlmostEqual(CATSNDOGS_TABLE.e_score(), 1/3)
540
        self.assertAlmostEqual(WORKED_EG_TABLE.e_score(), 19/23)
541
542
    def test_f1_score(self):
543
        """Test abydos.stats.confusion_table.ConfusionTable.f1_score."""
544
        self.assertEqual(UNIT_TABLE.f1_score(), 0.5)
545
        self.assertTrue(isnan(NULL_TABLE.f1_score()))
546
        self.assertAlmostEqual(SCALE_TABLE.f1_score(), 2/9)
547
        self.assertAlmostEqual(CATSNDOGS_TABLE.f1_score(), 2/3)
548
        self.assertAlmostEqual(WORKED_EG_TABLE.f1_score(), 4/23)
549
550
    def test_f_measure(self):
551
        """Test abydos.stats.confusion_table.ConfusionTable.f_measure."""
552
        self.assertEqual(UNIT_TABLE.f_measure(), 0.5)
553
        self.assertTrue(isnan(NULL_TABLE.f_measure()))
554
        self.assertAlmostEqual(SCALE_TABLE.f_measure(), 2/9)
555
        self.assertAlmostEqual(CATSNDOGS_TABLE.f_measure(), 2/3)
556
        self.assertAlmostEqual(WORKED_EG_TABLE.f_measure(), 4/23)
557
558
    def test_g_measure(self):
559
        """Test abydos.stats.confusion_table.ConfusionTable.g_measure."""
560
        self.assertEqual(UNIT_TABLE.g_measure(), 0.5)
561
        self.assertTrue(isnan(NULL_TABLE.g_measure()))
562
        self.assertAlmostEqual(SCALE_TABLE.g_measure(), 0.22360679774997899)
563
        self.assertAlmostEqual(CATSNDOGS_TABLE.g_measure(),
564
                               0.66815310478106094)
565
        self.assertAlmostEqual(WORKED_EG_TABLE.g_measure(),
566
                               0.25819888974716115)
567
568
    def test_mcc(self):
569
        """Test abydos.stats.confusion_table.ConfusionTable.mcc."""
570
        self.assertEqual(UNIT_TABLE.mcc(), 0)
571
        self.assertTrue(isnan(NULL_TABLE.mcc()))
572
        self.assertAlmostEqual(SCALE_TABLE.mcc(), -10/sqrt(600))
573
        self.assertAlmostEqual(CATSNDOGS_TABLE.mcc(), 79/sqrt(21280))
574
        self.assertAlmostEqual(WORKED_EG_TABLE.mcc(), 34600/sqrt(21960000000))
575
576
    def test_significance(self):
577
        """Test abydos.stats.confusion_table.ConfusionTable.significance."""
578
        self.assertEqual(UNIT_TABLE.significance(), 0)
579
        self.assertTrue(isnan(NULL_TABLE.significance()))
580
        self.assertAlmostEqual(SCALE_TABLE.significance(), 5/3)
581
        self.assertAlmostEqual(CATSNDOGS_TABLE.significance(), 79**2/21280*27)
582
        self.assertAlmostEqual(WORKED_EG_TABLE.significance(),
583
                               34600**2/21960000000*2030)
584
585
    def test_kappa_statistic(self):
586
        """Test abydos.stats.confusion_table.ConfusionTable.kappa_statistic."""
587
        def _quick_kappa(acc, racc):
588
            return (acc-racc)/(1-racc)
589
590
        self.assertEqual(UNIT_TABLE.kappa_statistic(), 0)
591
        self.assertTrue(isnan(NULL_TABLE.kappa_statistic()))
592
        self.assertAlmostEqual(SCALE_TABLE.kappa_statistic(),
593
                               _quick_kappa((3/10), (1/2)))
594
        self.assertAlmostEqual(CATSNDOGS_TABLE.kappa_statistic(),
595
                               _quick_kappa((22/27), (436/27**2)))
596
        self.assertAlmostEqual(WORKED_EG_TABLE.kappa_statistic(),
597
                               _quick_kappa((184/203),
598
                                            (((2000*1830)+6000)/2030**2)))
599
600
601
if __name__ == '__main__':
602
    unittest.main()
603