evalaudit 0.2.0__tar.gz → 0.3.0__tar.gz
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.
- {evalaudit-0.2.0 → evalaudit-0.3.0}/.gitignore +2 -1
- evalaudit-0.3.0/CHANGELOG.md +255 -0
- {evalaudit-0.2.0 → evalaudit-0.3.0}/PKG-INFO +80 -31
- {evalaudit-0.2.0 → evalaudit-0.3.0}/README.md +78 -29
- {evalaudit-0.2.0 → evalaudit-0.3.0}/evalaudit/__init__.py +9 -1
- {evalaudit-0.2.0 → evalaudit-0.3.0}/evalaudit/_types.py +96 -28
- {evalaudit-0.2.0 → evalaudit-0.3.0}/evalaudit/audit.py +107 -18
- {evalaudit-0.2.0 → evalaudit-0.3.0}/evalaudit/compare.py +6 -2
- {evalaudit-0.2.0 → evalaudit-0.3.0}/evalaudit/pairwise.py +236 -79
- evalaudit-0.3.0/evalaudit/scores.py +219 -0
- evalaudit-0.3.0/examples/pairwise_cluster_study.py +178 -0
- {evalaudit-0.2.0 → evalaudit-0.3.0}/pyproject.toml +2 -2
- {evalaudit-0.2.0 → evalaudit-0.3.0}/tests/test_agreement.py +1722 -1633
- {evalaudit-0.2.0 → evalaudit-0.3.0}/tests/test_audit.py +406 -1
- {evalaudit-0.2.0 → evalaudit-0.3.0}/tests/test_compare.py +916 -802
- evalaudit-0.3.0/tests/test_confidence.py +120 -0
- {evalaudit-0.2.0 → evalaudit-0.3.0}/tests/test_judge.py +195 -11
- {evalaudit-0.2.0 → evalaudit-0.3.0}/tests/test_pairwise.py +780 -19
- evalaudit-0.3.0/tests/test_scores.py +436 -0
- evalaudit-0.3.0/tests/test_version.py +84 -0
- evalaudit-0.2.0/evalaudit/scores.py +0 -136
- evalaudit-0.2.0/tests/test_scores.py +0 -181
- {evalaudit-0.2.0 → evalaudit-0.3.0}/.github/workflows/tests.yml +0 -0
- {evalaudit-0.2.0 → evalaudit-0.3.0}/LICENSE +0 -0
- {evalaudit-0.2.0 → evalaudit-0.3.0}/evalaudit/agreement.py +0 -0
- {evalaudit-0.2.0 → evalaudit-0.3.0}/evalaudit/judge.py +0 -0
- {evalaudit-0.2.0 → evalaudit-0.3.0}/evalaudit/power.py +0 -0
- {evalaudit-0.2.0 → evalaudit-0.3.0}/examples/.gitkeep +0 -0
- {evalaudit-0.2.0 → evalaudit-0.3.0}/examples/interval_method_study.py +0 -0
- {evalaudit-0.2.0 → evalaudit-0.3.0}/tests/__init__.py +0 -0
- {evalaudit-0.2.0 → evalaudit-0.3.0}/tests/test_power.py +0 -0
- {evalaudit-0.2.0 → evalaudit-0.3.0}/tests/test_readme.py +0 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Every change to evalaudit that a caller can see is recorded here. The format
|
|
4
|
+
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
|
|
5
|
+
version numbers follow [semantic versioning](https://semver.org/). Before 1.0
|
|
6
|
+
a minor version can break things, and 0.3.0 does.
|
|
7
|
+
|
|
8
|
+
The entries for 0.2.1 and earlier were reconstructed from the git history
|
|
9
|
+
after the fact. There were no tags, so they record what the commits say and
|
|
10
|
+
not what was published on a given day.
|
|
11
|
+
|
|
12
|
+
## [0.3.0] - Unreleased
|
|
13
|
+
|
|
14
|
+
0.3.0 changes what `bradley_terry` reports on data you have already run, and
|
|
15
|
+
it turns several calls that used to return numbers into errors. Every
|
|
16
|
+
breaking change is under Changed, marked **Breaking**, with what to do about
|
|
17
|
+
it.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **Breaking.** `bradley_terry` reads separability off the interval on the
|
|
22
|
+
gap between two ratings. Before, a pair was separable when its two rating
|
|
23
|
+
intervals did not overlap. Now a pair is separable when the percentile
|
|
24
|
+
interval on the difference between the two ratings excludes zero. Two
|
|
25
|
+
rating intervals can overlap while the gap between them is well measured,
|
|
26
|
+
because both ratings carry the error of the field average they are
|
|
27
|
+
measured against and that error cancels in the gap. So the old test
|
|
28
|
+
undercounted the pairs the data orders, and the pairs it left out were
|
|
29
|
+
never shown to be unordered. `n_separable` and `separable_pairs` change on
|
|
30
|
+
existing data, usually upward. On the README example they go from 5 of 15
|
|
31
|
+
pairs to 7. Nothing changes in your code. Rerun, and replace any
|
|
32
|
+
separability count you have published.
|
|
33
|
+
|
|
34
|
+
- **Breaking.** `separable_pairs` has two new columns, `ci_low` and
|
|
35
|
+
`ci_high`, the interval on `difference`. They sit between `difference` and
|
|
36
|
+
`p_a_beats_b`, so code that reads columns by position will read the wrong
|
|
37
|
+
ones. Code that selects columns by name is unaffected.
|
|
38
|
+
|
|
39
|
+
- **Breaking.** `bradley_terry` resamples items by default. Before, the
|
|
40
|
+
bootstrap drew single comparisons, which treats judgements of the same
|
|
41
|
+
prompt as independent. Now it draws item ids with replacement and takes
|
|
42
|
+
every comparison made on each drawn item. Where every item carries one
|
|
43
|
+
comparison the default draws the same resamples from the same seed as
|
|
44
|
+
before, and nothing moves. Where items carry several comparisons the
|
|
45
|
+
intervals widen and fewer pairs may separate. On simulated data shaped
|
|
46
|
+
like MT-Bench's human judgements, the old bootstrap covered 88% of the
|
|
47
|
+
time at a nominal 95% once prompts shifted model strength by a spread of
|
|
48
|
+
0.5 on the log-odds scale, and 80% at a spread of 1.0.
|
|
49
|
+
`examples/pairwise_cluster_study.py` has the full table. To reproduce a
|
|
50
|
+
result from an earlier version exactly, pass `resample="comparisons"`.
|
|
51
|
+
|
|
52
|
+
- **Breaking.** `bradley_terry` raises `ValueError` in two cases that 0.2.1
|
|
53
|
+
accepted. Both apply only when `n_boot` is above zero and `resample` is
|
|
54
|
+
left at its default of `"items"`.
|
|
55
|
+
|
|
56
|
+
- Some row has no `item_id`. The item bootstrap has to know which item
|
|
57
|
+
each comparison belongs to.
|
|
58
|
+
- Every row has the same `item_id`. With one item, every resample is the
|
|
59
|
+
full data and every interval would have width zero.
|
|
60
|
+
|
|
61
|
+
This is the change most likely to break a working script, so here is what
|
|
62
|
+
to do. Earlier versions required `item_id` and read it for nothing but a
|
|
63
|
+
count, so a constant, a blank or the row number got past the check and
|
|
64
|
+
changed nothing. Look at what yours holds.
|
|
65
|
+
|
|
66
|
+
- It names the prompt each comparison was made on. Fill in any gaps and
|
|
67
|
+
change nothing else. Your intervals now account for comparisons sharing
|
|
68
|
+
a prompt, which is the reason for the change.
|
|
69
|
+
- It is the row number, or anything else unique per row. Nothing raises
|
|
70
|
+
and nothing moves.
|
|
71
|
+
- It is a constant or a blank. Record the prompt if you can. If you
|
|
72
|
+
cannot, pass `resample="comparisons"` to keep the intervals you had.
|
|
73
|
+
They treat every judgement as independent and run narrow wherever
|
|
74
|
+
prompts carry several, and the summary says so.
|
|
75
|
+
|
|
76
|
+
With `n_boot=0` no resampling happens and any `item_id` is accepted.
|
|
77
|
+
|
|
78
|
+
- **Breaking.** `score_ci(method="t")` raises `ValueError` on three inputs
|
|
79
|
+
it used to return numbers for. What to do depends on the input.
|
|
80
|
+
|
|
81
|
+
- 0/1 data, including all passes and all fails. The interval could run
|
|
82
|
+
past 0% or 100%, or come back with width zero. Use `method="wilson"`,
|
|
83
|
+
which `method="auto"` already picks for 0/1 data.
|
|
84
|
+
- A single score. It came back as NaN bounds behind two RuntimeWarnings.
|
|
85
|
+
One score has no spread, and no method here can put an interval around
|
|
86
|
+
it. Score more items.
|
|
87
|
+
- Continuous scores that are all the same. The interval came back with
|
|
88
|
+
width zero, which claims the observations fixed the mean exactly. Check
|
|
89
|
+
that the scorer is not returning a constant.
|
|
90
|
+
|
|
91
|
+
- **Breaking.** `score_ci(method="wilson")` raises `ValueError` on scores
|
|
92
|
+
that are not 0 or 1. Wilson counts passes, and on other scores it took the
|
|
93
|
+
count by truncating the sum of the scores. Ten scores of 0.99 printed a
|
|
94
|
+
mean of 0.990 beside an interval of 0.596 to 0.982. Use
|
|
95
|
+
`method="bootstrap"` for the interval on a mean, which `method="auto"`
|
|
96
|
+
already picks.
|
|
97
|
+
|
|
98
|
+
- **Breaking.** `score_ci`, `compare_paired` and `compare_independent`
|
|
99
|
+
raise `ValueError` for a confidence level that is not strictly between 0
|
|
100
|
+
and 1, with the message `confidence must be in (0, 1), got ...` that
|
|
101
|
+
`bradley_terry`, `rater_agreement`, `judge_validation` and `audit` already
|
|
102
|
+
used. Before, what came back at `confidence=1.5` depended on the method.
|
|
103
|
+
The bootstrap in all three raised from inside numpy. Wilson and both t
|
|
104
|
+
intervals returned NaN bounds. The two score intervals returned bounds
|
|
105
|
+
clipped to -100% and 100%. The signed-rank interval in `compare_paired`
|
|
106
|
+
returned an ordinary-looking interval under a "150% CI" label, which is
|
|
107
|
+
the case nothing would have flagged. Pass a level strictly between 0 and
|
|
108
|
+
1.
|
|
109
|
+
|
|
110
|
+
- **Breaking.** Several summary strings are reworded, so any test or
|
|
111
|
+
pipeline that matches on them will fail.
|
|
112
|
+
|
|
113
|
+
- `BTResult.summary()` defines separable as "the interval on the gap
|
|
114
|
+
between the two ratings excludes zero". For pairs that do not separate
|
|
115
|
+
it says the data does not establish an order for them, that this does
|
|
116
|
+
not mean the models are level, and that more comparisons could separate
|
|
117
|
+
them. The phrases "meaning their intervals do not overlap", "cannot be
|
|
118
|
+
ordered", "an order the data does not carry" and "a ranking of noise"
|
|
119
|
+
are gone.
|
|
120
|
+
- `BTResult.summary()` adds a sentence when `resample="comparisons"` was
|
|
121
|
+
used on data where items carry several comparisons.
|
|
122
|
+
- `AgreementResult.summary()` for a scale nobody varied now ends "This
|
|
123
|
+
comes from a scale nobody varied. It is not perfect agreement." The old
|
|
124
|
+
ending was "That is not perfect agreement, it is a scale nobody varied."
|
|
125
|
+
- `JudgeValidation.summary()` for a rubric with one label now reads "This
|
|
126
|
+
comes from a rubric with one label in it. It is not perfect agreement."
|
|
127
|
+
The old sentence was "That is not perfect agreement, it is a rubric with
|
|
128
|
+
one label in it."
|
|
129
|
+
|
|
130
|
+
- The Development Status classifier moved from Alpha to Beta.
|
|
131
|
+
|
|
132
|
+
### Added
|
|
133
|
+
|
|
134
|
+
- `bradley_terry(..., resample="items")`, with `"comparisons"` as the other
|
|
135
|
+
choice.
|
|
136
|
+
- `BTResult.pairs`, one row per pair of models with the gap, the interval on
|
|
137
|
+
the gap and a `separable` column. `separable_pairs` is its separable rows.
|
|
138
|
+
- `BTResult.resample`, recording which unit the bootstrap drew. It and
|
|
139
|
+
`pairs` are the last two fields of the dataclass, so building a
|
|
140
|
+
`BTResult` by position still works.
|
|
141
|
+
- `to_elo` stretches the gap intervals with the gaps and carries `pairs` and
|
|
142
|
+
`resample` across.
|
|
143
|
+
- `examples/pairwise_cluster_study.py`, which measures how narrow the
|
|
144
|
+
comparison bootstrap runs on MT-Bench shaped data.
|
|
145
|
+
|
|
146
|
+
### Fixed
|
|
147
|
+
|
|
148
|
+
- Four inputs to `score_ci` and the confidence level in three functions used
|
|
149
|
+
to produce impossible or self-contradicting numbers. They now raise, and
|
|
150
|
+
they are listed under Changed because each one turns a call that returned
|
|
151
|
+
into an error.
|
|
152
|
+
- The `scores` module docstring said the interval at n=50 is roughly plus or
|
|
153
|
+
minus 10 points. It is about 10 at an 85% pass rate and about 13 at 50%.
|
|
154
|
+
- The README Coverage section said the Student-t interval in `score_ci` and
|
|
155
|
+
Welch's interval in `compare_independent` had nothing pinning their bounds.
|
|
156
|
+
Tests matching them against scipy and statsmodels had already landed. It
|
|
157
|
+
now counts fifteen intervals, nine tested for coverage, five pinned
|
|
158
|
+
against a reference and one with nothing pinning its bounds.
|
|
159
|
+
- The README corrected two earlier claims, about simulation coverage and
|
|
160
|
+
about how many checks `audit` runs.
|
|
161
|
+
|
|
162
|
+
### Removed
|
|
163
|
+
|
|
164
|
+
- The non-overlap definition of separability. There is no option to bring
|
|
165
|
+
it back, because the summary built on it made a claim its own docstring
|
|
166
|
+
denied.
|
|
167
|
+
- `AUDIT.md`, an internal review of the package, is no longer tracked, so
|
|
168
|
+
it is not in the source distribution.
|
|
169
|
+
|
|
170
|
+
## [0.2.1] - 2026-09-08
|
|
171
|
+
|
|
172
|
+
Reconstructed from the git history after the fact.
|
|
173
|
+
|
|
174
|
+
### Added
|
|
175
|
+
|
|
176
|
+
- Nothing.
|
|
177
|
+
|
|
178
|
+
### Changed
|
|
179
|
+
|
|
180
|
+
- `__version__` is read from the installed package metadata. 0.2.0 reported
|
|
181
|
+
`__version__` as 0.1.0, because a literal in `__init__.py` had drifted
|
|
182
|
+
from `pyproject.toml`.
|
|
183
|
+
|
|
184
|
+
### Fixed
|
|
185
|
+
|
|
186
|
+
- The length-bias check reported a preference for long answers whatever
|
|
187
|
+
the sign of the fit. The `audit` finding for length now takes its title,
|
|
188
|
+
lead, action and verdict from the fit that decides, with its own lead for
|
|
189
|
+
when the two fits point opposite ways.
|
|
190
|
+
|
|
191
|
+
### Removed
|
|
192
|
+
|
|
193
|
+
- Nothing.
|
|
194
|
+
|
|
195
|
+
## [0.2.0] - 2026-09-07
|
|
196
|
+
|
|
197
|
+
Reconstructed from the git history after the fact.
|
|
198
|
+
|
|
199
|
+
### Added
|
|
200
|
+
|
|
201
|
+
- The `pairwise` module, with `bradley_terry`, `to_elo` and `BTResult`.
|
|
202
|
+
Ratings come with bootstrap intervals and a count of separable pairs.
|
|
203
|
+
Models that fall into groups that never met, and models that never lost
|
|
204
|
+
or never won, get no ratings and a summary naming them. Ties are split or
|
|
205
|
+
dropped, and `ties="davidson"` is refused by name.
|
|
206
|
+
- The README code blocks are run by the test suite and checked against the
|
|
207
|
+
output they show.
|
|
208
|
+
|
|
209
|
+
### Changed
|
|
210
|
+
|
|
211
|
+
- The project URLs point at github.com/mokayahezron/evalaudit.
|
|
212
|
+
- `choix` is a development dependency on Python 3.10 and later, used to
|
|
213
|
+
check the Bradley-Terry fit.
|
|
214
|
+
|
|
215
|
+
### Fixed
|
|
216
|
+
|
|
217
|
+
- Nothing recorded.
|
|
218
|
+
|
|
219
|
+
### Removed
|
|
220
|
+
|
|
221
|
+
- Nothing.
|
|
222
|
+
|
|
223
|
+
## [0.1.x] - 2026-09-04 to 2026-09-07
|
|
224
|
+
|
|
225
|
+
Reconstructed from the git history after the fact. `pyproject.toml` read
|
|
226
|
+
0.1.0 at the first commit, 0.0.1 from the third, and 0.1.0 again from a
|
|
227
|
+
README update made after the audit module landed. Which of these were
|
|
228
|
+
published is not recorded.
|
|
229
|
+
|
|
230
|
+
### Added
|
|
231
|
+
|
|
232
|
+
- `score_ci`, with Wilson, bootstrap and Student-t intervals.
|
|
233
|
+
- `compare_paired` and `compare_independent`. McNemar with Tango's score
|
|
234
|
+
interval for paired binary data, the paired bootstrap, and the signed-rank
|
|
235
|
+
test with the Hodges-Lehmann interval. The score interval, the bootstrap
|
|
236
|
+
and Welch's t for independent samples.
|
|
237
|
+
- `rater_agreement`, Krippendorff's alpha with a bootstrap interval, an item
|
|
238
|
+
disagreement table and a rater dropout table. `cohens_kappa` and
|
|
239
|
+
`fleiss_kappa`.
|
|
240
|
+
- `judge_validation`, `position_bias` and `length_bias`.
|
|
241
|
+
- `detectable_effect` and `min_sample_size`.
|
|
242
|
+
- `audit`, which runs every check the supplied data supports and ranks the
|
|
243
|
+
findings by severity.
|
|
244
|
+
|
|
245
|
+
### Changed
|
|
246
|
+
|
|
247
|
+
- Nothing recorded.
|
|
248
|
+
|
|
249
|
+
### Fixed
|
|
250
|
+
|
|
251
|
+
- Nothing recorded.
|
|
252
|
+
|
|
253
|
+
### Removed
|
|
254
|
+
|
|
255
|
+
- Nothing.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: evalaudit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Statistical validity checks for human-graded AI evaluations. Rater agreement, judge validation, and whether your result holds up.
|
|
5
5
|
Project-URL: Homepage, https://github.com/mokayahezron/evalaudit
|
|
6
6
|
Project-URL: Issues, https://github.com/mokayahezron/evalaudit/issues
|
|
@@ -8,7 +8,7 @@ Author-email: Hezron Mokaya <ondibahezron@gmail.com>
|
|
|
8
8
|
License: MIT
|
|
9
9
|
License-File: LICENSE
|
|
10
10
|
Keywords: annotation-quality,bradley-terry,evaluation,inter-rater-reliability,krippendorff,llm,llm-as-judge,statistics
|
|
11
|
-
Classifier: Development Status ::
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
12
|
Classifier: Intended Audience :: Science/Research
|
|
13
13
|
Classifier: License :: OSI Approved :: MIT License
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -163,9 +163,11 @@ Two rules the library follows throughout:
|
|
|
163
163
|
| `compare` | Does the margin between two systems survive a paired test? |
|
|
164
164
|
| `audit` | Everything except `pairwise`, as a report ranked by what changes the conclusion. |
|
|
165
165
|
|
|
166
|
-
`audit` is the deliverable. It runs
|
|
167
|
-
finds by what changes the conclusion.
|
|
168
|
-
|
|
166
|
+
`audit` is the deliverable. It runs seven checks drawn from five of these
|
|
167
|
+
modules and orders what it finds by what changes the conclusion. `judge`
|
|
168
|
+
supplies three of the seven, since judge-human agreement, position bias and
|
|
169
|
+
length bias are separate findings. Each of those five modules also stands
|
|
170
|
+
alone when you want a single number instead of a report.
|
|
169
171
|
|
|
170
172
|
`pairwise` runs on its own. A leaderboard is a different question from a
|
|
171
173
|
single eval and arrives as a different frame, one row per comparison rather
|
|
@@ -178,18 +180,10 @@ Scores, compare and power are the foundation those three stand on.
|
|
|
178
180
|
|
|
179
181
|
## Status
|
|
180
182
|
|
|
181
|
-
All seven modules are implemented.
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|---|---|
|
|
186
|
-
| `scores` | Implemented |
|
|
187
|
-
| `compare` | Implemented |
|
|
188
|
-
| `agreement` | Implemented |
|
|
189
|
-
| `judge` | Implemented |
|
|
190
|
-
| `power` | Implemented |
|
|
191
|
-
| `audit` | Implemented |
|
|
192
|
-
| `pairwise` | Implemented |
|
|
183
|
+
All seven modules are implemented. CI runs the suite on Python 3.9, 3.11 and
|
|
184
|
+
3.12, including the checks that pin results against outside implementations.
|
|
185
|
+
The examples below are run there too, so what they print here is what they
|
|
186
|
+
print for you.
|
|
193
187
|
|
|
194
188
|
### What `scores` answers
|
|
195
189
|
|
|
@@ -255,17 +249,32 @@ print(bradley_terry(comparisons, seed=0).summary())
|
|
|
255
249
|
```
|
|
256
250
|
|
|
257
251
|
```
|
|
258
|
-
Bradley-Terry ratings for 6 models from 600 comparisons (ties split).
|
|
259
|
-
15 pairs are separable at 95%, meaning
|
|
260
|
-
|
|
261
|
-
|
|
252
|
+
Bradley-Terry ratings for 6 models from 600 comparisons (ties split). 7 of
|
|
253
|
+
15 pairs are separable at 95%, meaning the interval on the gap between the
|
|
254
|
+
two ratings excludes zero. For the other 8 pairs the interval includes zero,
|
|
255
|
+
so this data does not establish an order for those pairs in either
|
|
256
|
+
direction. [...] Ratings are anchored on m1 at 0. Only differences between
|
|
257
|
+
models mean anything [...]
|
|
262
258
|
```
|
|
263
259
|
|
|
264
|
-
Six models make fifteen pairs. Six hundred comparisons separate
|
|
265
|
-
them
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
260
|
+
Six models make fifteen pairs. Six hundred comparisons separate seven of
|
|
261
|
+
them. Five are the weakest model against each of the others, and the other
|
|
262
|
+
two put m1 and m2 above m5. No pair among the top four separates, and the
|
|
263
|
+
fit even rates m4 above m3, the reverse of the strengths the data was drawn
|
|
264
|
+
from. A published board would still print all six in a line, one through
|
|
265
|
+
six, and readers would take that order seriously.
|
|
266
|
+
|
|
267
|
+
`result.pairs` lists all fifteen pairs with the interval on each gap, so the
|
|
268
|
+
eight that do not separate can be read as well as counted.
|
|
269
|
+
|
|
270
|
+
The bootstrap behind those intervals resamples items, taking every comparison
|
|
271
|
+
made on one prompt together, because judgements of the same prompt move
|
|
272
|
+
together. Versions before 0.3.0 resampled single comparisons. On simulated
|
|
273
|
+
data shaped like MT-Bench, 2,575 comparisons over 80 prompts, that covered
|
|
274
|
+
88% where 95% was claimed once prompts shifted model strength by a spread of
|
|
275
|
+
0.5 on the log-odds scale, and 80% at a spread of 1.0.
|
|
276
|
+
`examples/pairwise_cluster_study.py` has the full table. Pass
|
|
277
|
+
`resample="comparisons"` to reproduce an older result.
|
|
269
278
|
|
|
270
279
|
`to_elo` puts the same fit on the 400 point scale people expect and carries
|
|
271
280
|
the intervals across with it. Leaderboards publish Elo without intervals,
|
|
@@ -281,11 +290,32 @@ and named.
|
|
|
281
290
|
## Coverage
|
|
282
291
|
|
|
283
292
|
A statistics package earns trust by showing its intervals cover at the rate
|
|
284
|
-
they claim.
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
293
|
+
they claim. Generate datasets with a known truth, then confirm the 95%
|
|
294
|
+
interval contains it about 95% of the time. Runs per test range from a
|
|
295
|
+
hundred or so to a thousand, set by what each simulation costs.
|
|
296
|
+
|
|
297
|
+
The package builds fifteen intervals and nine of them are tested that way.
|
|
298
|
+
Those nine are the Wilson and bootstrap intervals on a single score, the
|
|
299
|
+
Tango, bootstrap and Hodges-Lehmann intervals on a paired difference, the
|
|
300
|
+
bootstrap intervals on Krippendorff's alpha and on judge-human alpha, and the
|
|
301
|
+
Bradley-Terry intervals on each rating and on each gap between two ratings.
|
|
302
|
+
The gap interval is tested on data where comparisons made on the same prompt
|
|
303
|
+
move together, which is the case its item bootstrap is for.
|
|
304
|
+
|
|
305
|
+
Five more are pinned against a reference instead, which is the sharper test
|
|
306
|
+
where one exists. The score interval for two independent proportions is swept
|
|
307
|
+
against its own p-value over every table at two group sizes, since that
|
|
308
|
+
interval is the test inverted and the two must never disagree about zero. The
|
|
309
|
+
Wilson intervals in `position_bias` and both logistic intervals in
|
|
310
|
+
`length_bias` are matched against `statsmodels`. The Student-t interval in
|
|
311
|
+
`score_ci` is matched against `scipy`, and Welch's interval in
|
|
312
|
+
`compare_independent` against `statsmodels`.
|
|
313
|
+
|
|
314
|
+
The last one has nothing pinning its bounds, and this is the place to say so
|
|
315
|
+
rather than leave you to find out. It is the two-sample bootstrap in
|
|
316
|
+
`compare_independent`.
|
|
317
|
+
|
|
318
|
+
Those tests run in CI and you can read them in `tests/`.
|
|
289
319
|
|
|
290
320
|
---
|
|
291
321
|
|
|
@@ -308,6 +338,25 @@ Python 3.9+, numpy, scipy, pandas. Nothing else.
|
|
|
308
338
|
|
|
309
339
|
---
|
|
310
340
|
|
|
341
|
+
## Who wrote this
|
|
342
|
+
|
|
343
|
+
I'm Hezron Mokaya, a statistician. I have spent years on the task and
|
|
344
|
+
QA side of expert AI evaluation. I
|
|
345
|
+
graded, and I ran quality control on other people's grading. I did not design
|
|
346
|
+
the benchmarks.
|
|
347
|
+
|
|
348
|
+
This package is the work I do for clients, published in the open. I audit AI
|
|
349
|
+
evaluations for statistical validity: rater agreement, pairwise comparison,
|
|
350
|
+
judge validation, and whether the numbers in a report support the claim being
|
|
351
|
+
made from them.
|
|
352
|
+
|
|
353
|
+
If you have an eval you are about to publish, act on, or defend, I take that
|
|
354
|
+
work.
|
|
355
|
+
|
|
356
|
+
ondibahezron@gmail.com
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
311
360
|
## Licence
|
|
312
361
|
|
|
313
362
|
MIT.
|
|
@@ -136,9 +136,11 @@ Two rules the library follows throughout:
|
|
|
136
136
|
| `compare` | Does the margin between two systems survive a paired test? |
|
|
137
137
|
| `audit` | Everything except `pairwise`, as a report ranked by what changes the conclusion. |
|
|
138
138
|
|
|
139
|
-
`audit` is the deliverable. It runs
|
|
140
|
-
finds by what changes the conclusion.
|
|
141
|
-
|
|
139
|
+
`audit` is the deliverable. It runs seven checks drawn from five of these
|
|
140
|
+
modules and orders what it finds by what changes the conclusion. `judge`
|
|
141
|
+
supplies three of the seven, since judge-human agreement, position bias and
|
|
142
|
+
length bias are separate findings. Each of those five modules also stands
|
|
143
|
+
alone when you want a single number instead of a report.
|
|
142
144
|
|
|
143
145
|
`pairwise` runs on its own. A leaderboard is a different question from a
|
|
144
146
|
single eval and arrives as a different frame, one row per comparison rather
|
|
@@ -151,18 +153,10 @@ Scores, compare and power are the foundation those three stand on.
|
|
|
151
153
|
|
|
152
154
|
## Status
|
|
153
155
|
|
|
154
|
-
All seven modules are implemented.
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|---|---|
|
|
159
|
-
| `scores` | Implemented |
|
|
160
|
-
| `compare` | Implemented |
|
|
161
|
-
| `agreement` | Implemented |
|
|
162
|
-
| `judge` | Implemented |
|
|
163
|
-
| `power` | Implemented |
|
|
164
|
-
| `audit` | Implemented |
|
|
165
|
-
| `pairwise` | Implemented |
|
|
156
|
+
All seven modules are implemented. CI runs the suite on Python 3.9, 3.11 and
|
|
157
|
+
3.12, including the checks that pin results against outside implementations.
|
|
158
|
+
The examples below are run there too, so what they print here is what they
|
|
159
|
+
print for you.
|
|
166
160
|
|
|
167
161
|
### What `scores` answers
|
|
168
162
|
|
|
@@ -228,17 +222,32 @@ print(bradley_terry(comparisons, seed=0).summary())
|
|
|
228
222
|
```
|
|
229
223
|
|
|
230
224
|
```
|
|
231
|
-
Bradley-Terry ratings for 6 models from 600 comparisons (ties split).
|
|
232
|
-
15 pairs are separable at 95%, meaning
|
|
233
|
-
|
|
234
|
-
|
|
225
|
+
Bradley-Terry ratings for 6 models from 600 comparisons (ties split). 7 of
|
|
226
|
+
15 pairs are separable at 95%, meaning the interval on the gap between the
|
|
227
|
+
two ratings excludes zero. For the other 8 pairs the interval includes zero,
|
|
228
|
+
so this data does not establish an order for those pairs in either
|
|
229
|
+
direction. [...] Ratings are anchored on m1 at 0. Only differences between
|
|
230
|
+
models mean anything [...]
|
|
235
231
|
```
|
|
236
232
|
|
|
237
|
-
Six models make fifteen pairs. Six hundred comparisons separate
|
|
238
|
-
them
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
233
|
+
Six models make fifteen pairs. Six hundred comparisons separate seven of
|
|
234
|
+
them. Five are the weakest model against each of the others, and the other
|
|
235
|
+
two put m1 and m2 above m5. No pair among the top four separates, and the
|
|
236
|
+
fit even rates m4 above m3, the reverse of the strengths the data was drawn
|
|
237
|
+
from. A published board would still print all six in a line, one through
|
|
238
|
+
six, and readers would take that order seriously.
|
|
239
|
+
|
|
240
|
+
`result.pairs` lists all fifteen pairs with the interval on each gap, so the
|
|
241
|
+
eight that do not separate can be read as well as counted.
|
|
242
|
+
|
|
243
|
+
The bootstrap behind those intervals resamples items, taking every comparison
|
|
244
|
+
made on one prompt together, because judgements of the same prompt move
|
|
245
|
+
together. Versions before 0.3.0 resampled single comparisons. On simulated
|
|
246
|
+
data shaped like MT-Bench, 2,575 comparisons over 80 prompts, that covered
|
|
247
|
+
88% where 95% was claimed once prompts shifted model strength by a spread of
|
|
248
|
+
0.5 on the log-odds scale, and 80% at a spread of 1.0.
|
|
249
|
+
`examples/pairwise_cluster_study.py` has the full table. Pass
|
|
250
|
+
`resample="comparisons"` to reproduce an older result.
|
|
242
251
|
|
|
243
252
|
`to_elo` puts the same fit on the 400 point scale people expect and carries
|
|
244
253
|
the intervals across with it. Leaderboards publish Elo without intervals,
|
|
@@ -254,11 +263,32 @@ and named.
|
|
|
254
263
|
## Coverage
|
|
255
264
|
|
|
256
265
|
A statistics package earns trust by showing its intervals cover at the rate
|
|
257
|
-
they claim.
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
266
|
+
they claim. Generate datasets with a known truth, then confirm the 95%
|
|
267
|
+
interval contains it about 95% of the time. Runs per test range from a
|
|
268
|
+
hundred or so to a thousand, set by what each simulation costs.
|
|
269
|
+
|
|
270
|
+
The package builds fifteen intervals and nine of them are tested that way.
|
|
271
|
+
Those nine are the Wilson and bootstrap intervals on a single score, the
|
|
272
|
+
Tango, bootstrap and Hodges-Lehmann intervals on a paired difference, the
|
|
273
|
+
bootstrap intervals on Krippendorff's alpha and on judge-human alpha, and the
|
|
274
|
+
Bradley-Terry intervals on each rating and on each gap between two ratings.
|
|
275
|
+
The gap interval is tested on data where comparisons made on the same prompt
|
|
276
|
+
move together, which is the case its item bootstrap is for.
|
|
277
|
+
|
|
278
|
+
Five more are pinned against a reference instead, which is the sharper test
|
|
279
|
+
where one exists. The score interval for two independent proportions is swept
|
|
280
|
+
against its own p-value over every table at two group sizes, since that
|
|
281
|
+
interval is the test inverted and the two must never disagree about zero. The
|
|
282
|
+
Wilson intervals in `position_bias` and both logistic intervals in
|
|
283
|
+
`length_bias` are matched against `statsmodels`. The Student-t interval in
|
|
284
|
+
`score_ci` is matched against `scipy`, and Welch's interval in
|
|
285
|
+
`compare_independent` against `statsmodels`.
|
|
286
|
+
|
|
287
|
+
The last one has nothing pinning its bounds, and this is the place to say so
|
|
288
|
+
rather than leave you to find out. It is the two-sample bootstrap in
|
|
289
|
+
`compare_independent`.
|
|
290
|
+
|
|
291
|
+
Those tests run in CI and you can read them in `tests/`.
|
|
262
292
|
|
|
263
293
|
---
|
|
264
294
|
|
|
@@ -281,6 +311,25 @@ Python 3.9+, numpy, scipy, pandas. Nothing else.
|
|
|
281
311
|
|
|
282
312
|
---
|
|
283
313
|
|
|
314
|
+
## Who wrote this
|
|
315
|
+
|
|
316
|
+
I'm Hezron Mokaya, a statistician. I have spent years on the task and
|
|
317
|
+
QA side of expert AI evaluation. I
|
|
318
|
+
graded, and I ran quality control on other people's grading. I did not design
|
|
319
|
+
the benchmarks.
|
|
320
|
+
|
|
321
|
+
This package is the work I do for clients, published in the open. I audit AI
|
|
322
|
+
evaluations for statistical validity: rater agreement, pairwise comparison,
|
|
323
|
+
judge validation, and whether the numbers in a report support the claim being
|
|
324
|
+
made from them.
|
|
325
|
+
|
|
326
|
+
If you have an eval you are about to publish, act on, or defend, I take that
|
|
327
|
+
work.
|
|
328
|
+
|
|
329
|
+
ondibahezron@gmail.com
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
284
333
|
## Licence
|
|
285
334
|
|
|
286
335
|
MIT.
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
"""evalaudit: statistical validity checks for AI evaluations."""
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version as _version
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
__version__ = _version("evalaudit")
|
|
7
|
+
except PackageNotFoundError:
|
|
8
|
+
# Running from a source tree with nothing installed. There is no
|
|
9
|
+
# version to report and there is no literal to fall back on, since a
|
|
10
|
+
# literal here is what put two different releases on the same number.
|
|
11
|
+
__version__ = "unknown"
|
|
4
12
|
|
|
5
13
|
from ._types import (
|
|
6
14
|
AgreementResult,
|