aggmetrics 0.1.0.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,203 @@
1
+ Metadata-Version: 2.4
2
+ Name: aggmetrics
3
+ Version: 0.1.0.dev0
4
+ Summary: Aggregating classification performance measures for machine learning: indicator matrices and aggregation operators
5
+ Author-email: "Ronaldo C. Prati" <ronaldo.prati@ufabc.edu.br>
6
+ License: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/rcprati/aggmetrics
8
+ Project-URL: Repository, https://github.com/rcprati/aggmetrics
9
+ Project-URL: Documentation, https://aggmetrics.readthedocs.io
10
+ Project-URL: Issues, https://github.com/rcprati/aggmetrics/issues
11
+ Keywords: machine learning,classification,evaluation,performance measures,metrics,multilabel,multiclass,class imbalance,confusion matrix
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: BSD License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
17
+ Requires-Python: >=3.9
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: numpy>=1.20
21
+ Provides-Extra: sklearn
22
+ Requires-Dist: scikit-learn>=1.0; extra == "sklearn"
23
+ Provides-Extra: frame
24
+ Requires-Dist: pandas>=1.3; extra == "frame"
25
+ Provides-Extra: test
26
+ Requires-Dist: pytest>=7.0; extra == "test"
27
+ Requires-Dist: scikit-learn>=1.0; extra == "test"
28
+ Requires-Dist: pandas>=1.3; extra == "test"
29
+ Provides-Extra: docs
30
+ Requires-Dist: sphinx>=5.0; extra == "docs"
31
+ Requires-Dist: furo; extra == "docs"
32
+ Provides-Extra: all
33
+ Requires-Dist: scikit-learn>=1.0; extra == "all"
34
+ Requires-Dist: pandas>=1.3; extra == "all"
35
+ Dynamic: license-file
36
+
37
+ # aggmetrics
38
+
39
+ **Aggregating classification performance measures for machine learning: indicator matrices and aggregation operators.**
40
+
41
+ Any binary performance measure expressible in terms of the four confusion-matrix
42
+ counts is extended to multiclass, multilabel, ordinal, cost-sensitive and
43
+ soft-label settings by substituting one of a small set of aggregation operators.
44
+ Micro-, macro- and exemplar-averaging (and pooling across cross-validation folds)
45
+ become instances of a single construction rather than separate conventions.
46
+
47
+ The package also reports when a measure is being used outside the range where it
48
+ behaves as commonly assumed — which is the part that is hard to get from a
49
+ formula library.
50
+
51
+ ```python
52
+ import numpy as np
53
+ from aggmetrics import IndicatorMatrix, diagnose
54
+
55
+ y_true = np.array([0, 1, 2, 2, 1, 0])
56
+ y_pred = np.array([0, 2, 2, 1, 1, 1])
57
+ im = IndicatorMatrix(y_true, y_pred, task='multiclass')
58
+
59
+ im.compute('f1', 'macro') # 0.5222
60
+ im.compute('f1', 'micro') # 0.5 -- equals accuracy on single-label data
61
+ im.compute('mcc', 'macro') # macro-MCC: no standard implementation exists
62
+ im.compute('informedness', 'micro')
63
+ im.accuracy() # 0.5
64
+
65
+ im.report() # DataFrame: measures x operators
66
+ ```
67
+
68
+ ## Installation
69
+
70
+ ```bash
71
+ pip install aggmetrics # core, requires only numpy
72
+ pip install "aggmetrics[all]" # adds scikit-learn and pandas support
73
+ ```
74
+
75
+ ## Why not just use `sklearn.metrics`?
76
+
77
+ `sklearn` exposes four `average` values for a fixed list of measures. The
78
+ correspondence is exact — `'micro'`, `'macro'`, `'weighted'` and `'samples'` are
79
+ Σ₁, Σₘ with uniform weights, Σₘ with prevalence weights and Σₙ respectively — but
80
+ the combinations available are a subset of those the construction generates, and
81
+ nothing in the library tells you when a combination is misleading.
82
+
83
+ Three things this package adds:
84
+
85
+ **Any measure under any operator.** Macro-MCC, exemplar-Jaccard, micro-informedness,
86
+ weighted G-mean. 21 binary measures × 4 operators, without special-casing.
87
+
88
+ **Structural properties as first-class data.** Each measure records whether it is
89
+ *aggregation-decomposable*, whether it is skew-invariant, and whether its value at
90
+ `tp = 0` depends on `tn`. These determine which identities apply.
91
+
92
+ ```python
93
+ from aggmetrics import get_measure, list_measures
94
+
95
+ list_measures(decomposable=True) # micro == denominator-weighted macro
96
+ get_measure('mcc').decomposable # False
97
+ get_measure('recall').bayes_threshold() # 0.0 -- maximised by predicting all positive
98
+ get_measure('mcc').attainable_floor(10) # -0.111, not -1
99
+ ```
100
+
101
+ **The generative claim, as an operation.** Supply a binary formula; the properties
102
+ that decide which identities apply are *derived*, not declared:
103
+
104
+ ```python
105
+ from aggmetrics import register_measure, infer_properties
106
+
107
+ def prevalence_threshold(tp, fp, fn, tn):
108
+ r, s = tp / (tp + fn), tn / (tn + fp)
109
+ return (np.sqrt(r * (1 - s)) + s - 1) / (r + s - 1)
110
+
111
+ m = register_measure('prevalence_threshold', prevalence_threshold)
112
+ m.decomposable # False -- inferred by fitting <a,v>/<b,v> and validating
113
+ m.skew_invariant # True -- a function of recall and specificity
114
+ m.bayes_threshold() # None -- no closed form outside the decomposable class
115
+
116
+ im.compute('prevalence_threshold', 'exemplar') # usable immediately
117
+ ```
118
+
119
+ Inference is checked against the 21 measures whose properties are known
120
+ analytically — `verify_inference()` — and all 21 agree, with recovered coefficients
121
+ accurate to 4.2e-15. The check paid for itself: it found two errors in our own hand
122
+ annotations (error rate and FPR both retain a `tn` dependence at `tp = 0`, so both
123
+ *flatter* a wholly wrong classifier, reaching 2/m and 1/(m-1) respectively).
124
+
125
+ **Diagnostics.** `diagnose()` flags the traps:
126
+
127
+ ```python
128
+ y = np.arange(500) % 10
129
+ yhat = (y + 1) % 10 # every single prediction is wrong
130
+ im = IndicatorMatrix(y, yhat, task='multiclass')
131
+
132
+ im.compute('label_accuracy', 'micro') # 0.800 (!)
133
+ im.compute('mcc', 'micro') # -0.111 (!)
134
+ im.accuracy() # 0.000
135
+
136
+ for f in diagnose(im):
137
+ print(f)
138
+ # [warning] inflated_floor: 'label_accuracy' cannot fall below 0.8000 on this
139
+ # 10-class one-hot problem even if every prediction is wrong ...
140
+ # [note] micro_collapse: micro-precision, micro-recall and micro-F1 are all
141
+ # equal to accuracy ...
142
+ # [warning] degenerate_optimum: 'recall' is maximised at threshold 0.000 ...
143
+ ```
144
+
145
+ Checks currently implemented: pooled value outside the per-class range;
146
+ `tn`-dependent measures on one-hot multiclass data; micro-collapse on single-label
147
+ data; undefined per-class entries and the size of the convention effect; measures
148
+ whose optimal decision rule is not the Bayes rule for 0/1 loss.
149
+
150
+ ## Features
151
+
152
+ - **21 binary measures**, resolvable by name or alias (`iou` → `jaccard`, `dice` → `f1`),
153
+ plus `register_measure` for your own, with properties inferred.
154
+ - **Four operators**: `micro`, `macro`, `weighted`, `exemplar`.
155
+ - **Explicit undefined-value conventions**: `exclude` (default), `zero`
156
+ (`sklearn`'s behaviour), `one`, `nan`. The choice is a parameter, not a default
157
+ buried in the implementation.
158
+ - **Soft ground truth** via t-norms, with `marginal_defect()` showing that only the
159
+ product t-norm preserves the marginals.
160
+ - **Cost matrices**, recovering MAE and MSE as special cases.
161
+ - **Observation masks** for partial labels, semi-supervised evaluation and abstention.
162
+ - **scikit-learn scorers** via `make_scorer`, usable in `cross_val_score` and
163
+ `GridSearchCV`.
164
+ - **AI Agent Skills included** (`.agents/skills/aggmetrics-guide/`), providing machine-readable
165
+ runbooks, axiomatic invariants, and diagnostic protocols for AI coding assistants.
166
+
167
+ ## The test suite verifies the theory
168
+
169
+ Each result of the companion paper is an executable test, so a change that breaks
170
+ a theorem breaks a test:
171
+
172
+ ```bash
173
+ python -m pytest tests/test_theory.py -v
174
+ ```
175
+
176
+ | Test | Result verified |
177
+ |---|---|
178
+ | `test_theorem1_holds_for_decomposable` | micro = denominator-weighted macro, 15 measures × 3 samples |
179
+ | `test_theorem1_fails_for_non_decomposable` | the identity has no extension beyond that class |
180
+ | `test_theorem2_product_is_uniquely_marginally_consistent` | only the product t-norm preserves marginals |
181
+ | `test_theorem5_micro_collapse` | micro-P = micro-R = micro-F₁ = accuracy, single-label |
182
+ | `test_proposition5_thresholds` | Bayes threshold `(β+δ)/(α+β+γ+δ)` |
183
+ | `test_proposition7_floors` | attainable floors under one-hot encoding |
184
+ | `test_proposition2_recall_prior_free_specificity_not` | one-vs-rest skew behaviour |
185
+ | `test_corollary5_gap_is_normalised_covariance` | the micro–macro gap identity |
186
+ | `test_theorem3_mae_and_mse_as_cost_matrices` | ordinal losses as cost matrices |
187
+ | `test_inference_reproduces_every_annotation` | inference recovers all 21 analytic annotations |
188
+
189
+ 138 tests, no skips.
190
+
191
+ ## Examples
192
+
193
+ ```bash
194
+ python examples/quickstart.py
195
+ ```
196
+
197
+ ## Citing
198
+
199
+ Please cite both the software and the companion paper; see `CITATION.cff`.
200
+
201
+ ## License
202
+
203
+ BSD 3-Clause.
@@ -0,0 +1,13 @@
1
+ aggmetrics/__init__.py,sha256=sNcuut_3lyhaGmPdfg8dBRCvpQFjqEWqz5cndq_ecoc,2768
2
+ aggmetrics/aggregation.py,sha256=lzDROGNlOgbl8ZEu0PgN8CyEM7-K_clxPUzcEhzwjCc,8620
3
+ aggmetrics/core.py,sha256=OO4p7CDfoP20w9JbFZxSyu51ONqrlSjvbmPcPdgBO5I,15691
4
+ aggmetrics/diagnostics.py,sha256=s65hgdXbPTRDJNi01JJHmI-fVIqVl5Mcjvp2mmZm6pc,13440
5
+ aggmetrics/inference.py,sha256=Q7pPTX-wOpZPnMEiiTGwMfD0pBkUH--r4_uAwLpzi8o,13615
6
+ aggmetrics/measures.py,sha256=s3WcPZ85aiq3w4wzzf94_mRmErDTNTjj5m8XKZ8eeT0,13586
7
+ aggmetrics/sklearn_compat.py,sha256=dHIoChd7OFHXR_J2GFQrMeW-sg8zN7UiygnNafhy7-k,3396
8
+ aggmetrics/tnorms.py,sha256=jN_ar6XfG55Thi9igypKsQDPB_hk3IcUCi3bIk4yR9c,3674
9
+ aggmetrics-0.1.0.dev0.dist-info/licenses/LICENSE,sha256=ZrA8zubLlbGMZUl3UeJbDFPD1u4mgs9MoMXRMQNIcg0,1524
10
+ aggmetrics-0.1.0.dev0.dist-info/METADATA,sha256=qX5Mrn8GTmTwdlYqIMnAa2nJXYroUub7JR9r-Wg-Qm8,8728
11
+ aggmetrics-0.1.0.dev0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
12
+ aggmetrics-0.1.0.dev0.dist-info/top_level.txt,sha256=CHCjg30FAscOgGgqmN7mu1MckrPVNphD6pG6BY_Di0s,11
13
+ aggmetrics-0.1.0.dev0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, Ronaldo C. Prati
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its contributors
17
+ may be used to endorse or promote products derived from this software without
18
+ specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1 @@
1
+ aggmetrics