-
Notifications
You must be signed in to change notification settings - Fork 0
0030 cohen kappa keeps scikit learns expected matrix orientation
Status: accepted · Date: 2026-08-14
cohen_kappa_score computes an expected cell as outer(s0, s1)[row, col] / n
with s0 the column sums and s1 the row sums — colSums[row] * rowSums[col] / n, the transpose of what a reader would reach for first,
outer(rowSums, colSums). Every KappaWeighting this package defines
(None, Linear, Quadratic) is
symmetric in row and col, so summing the weighted expected matrix gives the
same total either way and both orientations pass every oracle case. The
scikit-learn orientation is used anyway, and spelled out as
colSums[row] * rowSums[col] / total rather than simplified, so a later
reader does not "fix" what only looks backwards and, on some future asymmetric
weighting, silently changes the answer.
Linear and Quadratic weighting measure a distance between class
positions in ConfusionMatrix.Labels, not between the class values
themselves, so a weighted kappa depends on that order. A full reversal of the
label order preserves every position's distance to every other position and
so always returns the same kappa; an arbitrary permutation that is not a
reversal generally changes it, though a sufficiently symmetric matrix can
happen to be invariant under one anyway. KappaWeighting.None only asks
whether two positions are equal, so it never depends on the order at all.
Score(ConfusionMatrix) scores exactly the classes the matrix holds: cells,
sums and total all come from the ConfusionMatrix.Labels-sized view, so a
label subset that dropped samples contributes none of them, not even to a
denominator. cohen_kappa_score does take a labels= argument, so a reference
value exists for such a matrix: on the fixture
CohenKappaTests.YTrue/YPred (7 samples, 3 classes, unrestricted kappa
0.575757575758), restricting to labels=[1, 2] drops every sample touching
label 0 and leaves a diagonal — perfect agreement — so the restricted kappa is
1.0, matching cohen_kappa_score(y_true, y_pred, labels=[1, 2]) exactly.
That is agreement measured on one fixture, not a general guarantee: the rule
implemented is "score what the matrix holds", stated without reference to what
any full-label-set scikit-learn call would say.
Compute the expected cell as colSums[row] * rowSums[col] / total, matching
scikit-learn's outer(s0, s1) / n term for term rather than the more
intuitive outer(rowSums, colSums). Read KappaWeighting.Linear/Quadratic
as a function of label position, not label value, and document the
order-dependence rather than sorting it away. Score a matrix's own label view,
never the full observed set, whether or not scikit-learn's labels= argument
exists for the same call shape.
- The
<remarks>onCohenKappa.Score(ConfusionMatrix, ...)and theWeightloop's inline comment both carry a pointer here instead of restating the orientation and order-dependence arguments. -
The orientation is not verified by anything, and cannot be. All three
weightings are symmetric, so the two orientations return the same kappa on
all 78 corpus fixture × weighting combinations the theory runs — the choice
rests on term-for-term correspondence with
cohen_kappa_score'souter(s0, s1), not on a test that would fail if it were transposed. Only an asymmetric weighting could tell them apart, and this package defines none. - Value parity is verified by
CohenKappaTests.Matches_sklearn_cohen_kappa_score(the oracle theory, unweighted and both weightings),Unweighted_kappa_is_invariant_under_any_permutation_of_the_labels,A_restricted_label_set_reads_over_the_matrix_it_holds(the[1, 2]→1.0case above), and the permutation-dependence test attests/DataNet.Metrics.Tests/CohenKappaTests.cs:61-77forLinear/Quadratic.
- 0001-target-framework
- 0002-unicode-comparison-unit
- 0003-provenance-and-licensing
- 0004-levenshtein-myers-backlog
- 0005-hamming-jellyfish-divergence
- 0006-ratcliff-autojunk
- 0007-metaphone-scope
- 0008-italian-enza-nltk-divergence
- 0009-sample-consumes-a-local-feed
- 0010-stop-word-list-provenance
- 0011-persistence-format
- 0012-per-package-versioning
- 0013-sentencepiece-parity-scope
- 0014-precompiled-normalizer
- 0015-sonar-rules-in-the-build
- 0016-metrics-package-placement
- 0017-bpe-parity-scope
- 0018-multiclass-roc-auc-parallelism-is-opt-in
- 0019-the-net-analysers-run-in-the-build-too
- 0020-normalize-is-a-projection-not-a-parameter
- 0021-multioutput-is-a-method-not-an-enum
- 0022-added-token-matching-flags
- 0023-byte-level-decode-substitutes
- 0024-weighted-median-averages-within-scikit-learns-epsilon
- 0025-quickselect-replaces-a-full-sort-for-the-median
- 0026-r2-and-explainedvariance-split-their-undefined-cases-differently
- 0027-r2-and-explainedvariance-vectorize-only-a-single-output
- 0028-log1p-is-kahans-identity-not-math-log-1-plus-x
- 0029-balanced-accuracy-adjusted-is-left-to-ieee-754-at-the-edge
- 0030-cohen-kappa-keeps-scikit-learns-expected-matrix-orientation
- 0031-nosamplecorrect-mirrors-numpys-float64-upcast
- 0032-fbeta-substitutes-tp-predicted-and-support-algebraically
- 0033-compensated-sum-is-neumaiers-variant
- 0034-dropout-is-refused-for-want-of-a-user
- 0035-a-null-pre-split-is-removed-with-invert-not-isolated
- 0036-a-member-may-ship-without-an-oracle-if-it-says-so
- 0037-the-guards-run-before-the-commit
- 0038-the-gate-confronts-an-exception-tag-with-the-page-that-documents-it
- 0039-mutual-information-returns-zero-on-an-empty-input
- 0040-a-curve-is-a-sealed-class-per-curve
- 0041-one-sample-file-per-public-class
- 0042-phonetic-encoders-refuse-a-null-word
- 0043-the-equality-table-is-sized-to-the-pattern
- 0044-compression-belongs-to-the-caller
- 0045-a-console-call-carries-its-reason-on-the-line
- 0046-check-adr-immutable-runs-in-ci-only
- 0047-one-gate-per-kernel-not-one-per-alphabet
- 0048-the-gate-depends-on-the-kernel-and-the-alphabet
- 0049-two-gates-per-kernel-tested-where-the-width-is-known
- 0050-the-sentencepiece-bpe-lineage-stays-a-bpe-model
- benchmark_latest
- decisions
- equivalence
- matplotlib
- migration
- nightly_run
- numpy
- pandas
- performance
- pytorch
- seaborn
- sklearn
- statsmodels