evalsuite-python 0.3.1__tar.gz → 0.4.1__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.
Files changed (92) hide show
  1. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/CHANGELOG.md +57 -0
  2. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/PKG-INFO +65 -22
  3. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/README.md +52 -21
  4. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/pyproject.toml +17 -1
  5. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/__init__.py +5 -1
  6. evalsuite_python-0.4.1/src/evalsuite/_bench_metrics.py +1391 -0
  7. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/benchmarks.py +171 -10
  8. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/cli/main.py +33 -2
  9. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/clinical/metrics.py +7 -4
  10. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/plot.py +146 -0
  11. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/stats/_resolve.py +23 -3
  12. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/stats/compare.py +7 -3
  13. evalsuite_python-0.4.1/src/evalsuite/text/__init__.py +152 -0
  14. evalsuite_python-0.4.1/src/evalsuite/text/_common.py +94 -0
  15. evalsuite_python-0.4.1/src/evalsuite/text/factuality.py +469 -0
  16. evalsuite_python-0.4.1/src/evalsuite/text/generation.py +1127 -0
  17. evalsuite_python-0.4.1/src/evalsuite/text/judge.py +532 -0
  18. evalsuite_python-0.4.1/src/evalsuite/text/qa.py +108 -0
  19. evalsuite_python-0.4.1/src/evalsuite/text/rag.py +235 -0
  20. evalsuite_python-0.4.1/src/evalsuite/text/reasoning.py +215 -0
  21. evalsuite_python-0.4.1/src/evalsuite/text/report.py +158 -0
  22. evalsuite_python-0.4.1/src/evalsuite/text/retrieval.py +238 -0
  23. evalsuite_python-0.4.1/src/evalsuite/text/semantic.py +465 -0
  24. evalsuite_python-0.4.1/src/evalsuite/text/structured.py +789 -0
  25. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/version.py +1 -1
  26. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/integration/test_readme_examples.py +25 -0
  27. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/output/test_benchmarks.py +48 -2
  28. evalsuite_python-0.4.1/tests/text/test_against_references.py +256 -0
  29. evalsuite_python-0.4.1/tests/text/test_text_edges.py +175 -0
  30. evalsuite_python-0.4.1/tests/text/test_v040.py +835 -0
  31. evalsuite_python-0.4.1/tests/vision/__init__.py +0 -0
  32. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/.gitignore +0 -0
  33. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/CONTRIBUTING.md +0 -0
  34. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/LICENSE +0 -0
  35. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/__main__.py +0 -0
  36. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/api.py +0 -0
  37. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/calibration.py +0 -0
  38. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/classification/__init__.py +0 -0
  39. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/classification/_common.py +0 -0
  40. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/classification/metrics.py +0 -0
  41. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/cli/__init__.py +0 -0
  42. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/clinical/__init__.py +0 -0
  43. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/clinical/report.py +0 -0
  44. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/core/__init__.py +0 -0
  45. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/core/context.py +0 -0
  46. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/core/exceptions.py +0 -0
  47. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/core/export.py +0 -0
  48. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/core/registry.py +0 -0
  49. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/core/result.py +0 -0
  50. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/core/types.py +0 -0
  51. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/core/validation.py +0 -0
  52. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/py.typed +0 -0
  53. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/regression/__init__.py +0 -0
  54. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/regression/metrics.py +0 -0
  55. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/reporting.py +0 -0
  56. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/stats/__init__.py +0 -0
  57. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/stats/effect.py +0 -0
  58. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/stats/hypothesis.py +0 -0
  59. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/stats/intervals.py +0 -0
  60. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/stats/paired.py +0 -0
  61. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/stats/results.py +0 -0
  62. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/vision/__init__.py +0 -0
  63. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/vision/detection.py +0 -0
  64. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/src/evalsuite/vision/segmentation.py +0 -0
  65. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/__init__.py +0 -0
  66. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/classification/__init__.py +0 -0
  67. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/classification/test_against_sklearn.py +0 -0
  68. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/clinical/__init__.py +0 -0
  69. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/clinical/test_outputs.py +0 -0
  70. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/clinical/test_v020.py +0 -0
  71. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/conftest.py +0 -0
  72. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/integration/__init__.py +0 -0
  73. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/integration/test_qa.py +0 -0
  74. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/integration/test_repo_hygiene.py +0 -0
  75. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/output/__init__.py +0 -0
  76. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/output/test_cli.py +0 -0
  77. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/output/test_plot.py +0 -0
  78. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/output/test_reporting.py +0 -0
  79. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/regression/__init__.py +0 -0
  80. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/regression/test_against_sklearn.py +0 -0
  81. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/stats/__init__.py +0 -0
  82. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/stats/test_branches.py +0 -0
  83. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/stats/test_compare.py +0 -0
  84. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/stats/test_reference.py +0 -0
  85. {evalsuite_python-0.3.1/tests/unit → evalsuite_python-0.4.1/tests/text}/__init__.py +0 -0
  86. {evalsuite_python-0.3.1/tests/vision → evalsuite_python-0.4.1/tests/unit}/__init__.py +0 -0
  87. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/unit/test_core.py +0 -0
  88. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/unit/test_edges.py +0 -0
  89. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/vision/test_detection.py +0 -0
  90. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/vision/test_edges.py +0 -0
  91. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/vision/test_outputs.py +0 -0
  92. {evalsuite_python-0.3.1 → evalsuite_python-0.4.1}/tests/vision/test_segmentation.py +0 -0
@@ -6,6 +6,63 @@ All notable changes to this project are documented here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.4.1] - 2026-10-09
10
+
11
+ Benchmarks for every metric. No API changed.
12
+
13
+ ### Added
14
+ - `run_benchmarks(suite="metrics")` and `evalsuite benchmark --suite metrics`: one row for each of the 147
15
+ registered metrics and statistics functions, compared with a reference library (scikit-learn, SciPy,
16
+ statsmodels, pycocotools, sacreBLEU, rouge-score, NLTK, pycocoevalcap, ranx, krippendorff, choix, POT,
17
+ jsonschema) where one exists, otherwise with an independent NumPy / standard-library implementation of
18
+ the textbook formula; learned, judge-dependent and randomised procedures are timed alone. All 128
19
+ comparisons agree to 1e-9. A test keeps the suite in step with the registry.
20
+ - `scripts/bench_metrics_report.py` renders the per-metric table for BENCHMARKS.md and the website.
21
+
22
+ ### Changed
23
+ - `net_benefit` at a single threshold computes in one pass instead of sorting (about 3× faster).
24
+ - `perplexity` and `cross_entropy` validate the pooled tokens once instead of each sequence separately
25
+ (5–9× faster for many short sequences); errors still name the offending sequence.
26
+
27
+ ## [0.4.0] - 2026-10-09
28
+
29
+ LLM evaluation (the v0.4.0 roadmap). No existing API changed.
30
+
31
+ ### Added
32
+ - `es.text` and top-level functions for language-model evaluation; 69 new registered metrics, each checked
33
+ against a reference implementation where one exists:
34
+ - Text generation: BLEU, sentence BLEU, chrF/chrF++, TER (sacreBLEU), ROUGE-1/2/L/Lsum (rouge-score),
35
+ METEOR (NLTK, synonyms pluggable), CIDEr-D (pycocoevalcap), perplexity, cross-entropy, Distinct-n,
36
+ Self-BLEU, MAUVE (mauve-text divergence frontier, NumPy k-means).
37
+ - Semantic: BERTScore, embedding cosine / Euclidean / Manhattan, MoverScore (exact transport, = POT), and
38
+ `model_score` to run COMET, BLEURT, BARTScore, AlignScore or any scorer with intervals and comparison.
39
+ - Factuality: faithfulness, hallucination (unsupported-claim) rate, groundedness, citation precision and
40
+ recall (ALCE), claim-verification accuracy, knowledge consistency, answer correctness and relevance
41
+ (RAGAS), abstention accuracy, exact match and token F1 (SQuAD).
42
+ - LLM-as-a-judge: win rate, Bradley–Terry (= choix), Elo, Krippendorff's alpha (= krippendorff), Fleiss'
43
+ kappa (= statsmodels), judge–human agreement, position consistency, verbosity and self-preference bias,
44
+ rubric scores.
45
+ - Reasoning: pass@k, majority-vote accuracy, answer extraction and benchmark accuracy (GSM8K, MATH,
46
+ multiple choice).
47
+ - RAG: Precision/Recall/Hit rate@k, MRR, MAP, NDCG (= ranx), context precision, recall and relevance,
48
+ latency summary, task success rate, failure attribution.
49
+ - Structured output: JSON validity, JSON Schema compliance (built-in validator, agrees with jsonschema),
50
+ XML validity, required-field accuracy, tool selection / argument accuracy and tool-call F1, API-call
51
+ success, instruction compliance, constraint satisfaction, format compliance, multi-turn retention,
52
+ extra-content rate.
53
+ - `es.text_report` and `evalsuite text` (CLI) for the reference-based text metrics in one report.
54
+ - `bootstrap_ci`, `compare` and the paired tests resample whole items (texts, reference lists, rankings) for
55
+ these metrics, so corpus metrics such as BLEU get proper intervals.
56
+ - Benchmark suite `llm` against sacreBLEU, rouge-score, NLTK, ranx, krippendorff and jsonschema.
57
+ - `llm` extra (`nltk`) for METEOR's default Porter stemmer.
58
+ - Plots: `es.plot.ratings` (Bradley–Terry or Elo leaderboard with bootstrap intervals), `es.plot.win_matrix`
59
+ (pairwise win rates) and `es.plot.text_scores` (per-example score distributions by system).
60
+ - Benchmark overall summary counts cases without their size suffixes.
61
+
62
+ ### Not included
63
+ - SPICE (needs a Java scene-graph parser); BLEURT, COMET, BARTScore and AlignScore run through
64
+ `es.model_score` with your model rather than being bundled.
65
+
9
66
  ## [0.3.1] - 2026-10-09
10
67
 
11
68
  Quality-assurance release: release pipeline, packaging checks, edge-case fixes and an overall benchmark.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: evalsuite-python
3
- Version: 0.3.1
3
+ Version: 0.4.1
4
4
  Summary: A unified Python framework for machine-learning, clinical, statistical, segmentation, object-detection, uncertainty, and model evaluation.
5
5
  Project-URL: Homepage, https://evalsuite-nine.vercel.app
6
6
  Project-URL: Documentation, https://evalsuite-nine.vercel.app/docs
@@ -36,22 +36,34 @@ Requires-Dist: pandas>=1.4
36
36
  Requires-Dist: scipy>=1.8
37
37
  Provides-Extra: all
38
38
  Requires-Dist: matplotlib>=3.5; extra == 'all'
39
+ Requires-Dist: nltk>=3.8; extra == 'all'
39
40
  Requires-Dist: pillow>=9; extra == 'all'
40
41
  Provides-Extra: dev
41
42
  Requires-Dist: build; extra == 'dev'
43
+ Requires-Dist: choix>=0.3; extra == 'dev'
42
44
  Requires-Dist: hypothesis>=6.80; extra == 'dev'
45
+ Requires-Dist: jsonschema>=4.18; extra == 'dev'
46
+ Requires-Dist: krippendorff>=0.6; extra == 'dev'
43
47
  Requires-Dist: matplotlib>=3.5; extra == 'dev'
44
48
  Requires-Dist: mypy>=1.10; extra == 'dev'
49
+ Requires-Dist: nltk>=3.8; extra == 'dev'
45
50
  Requires-Dist: pandas-stubs; extra == 'dev'
46
51
  Requires-Dist: pillow>=9; extra == 'dev'
47
52
  Requires-Dist: pip-audit; extra == 'dev'
53
+ Requires-Dist: pot>=0.9; (python_version < '3.14') and extra == 'dev'
54
+ Requires-Dist: pycocoevalcap>=1.2; extra == 'dev'
48
55
  Requires-Dist: pycocotools>=2.0.7; extra == 'dev'
49
56
  Requires-Dist: pytest-cov>=4; extra == 'dev'
50
57
  Requires-Dist: pytest>=7; extra == 'dev'
58
+ Requires-Dist: ranx>=0.3.19; (python_version < '3.14') and extra == 'dev'
59
+ Requires-Dist: rouge-score>=0.1.2; extra == 'dev'
51
60
  Requires-Dist: ruff>=0.6; extra == 'dev'
61
+ Requires-Dist: sacrebleu>=2.4; extra == 'dev'
52
62
  Requires-Dist: scikit-learn>=1.4; extra == 'dev'
53
63
  Requires-Dist: statsmodels>=0.13; extra == 'dev'
54
64
  Requires-Dist: twine; extra == 'dev'
65
+ Provides-Extra: llm
66
+ Requires-Dist: nltk>=3.8; extra == 'llm'
55
67
  Provides-Extra: plot
56
68
  Requires-Dist: matplotlib>=3.5; extra == 'plot'
57
69
  Provides-Extra: vision
@@ -65,12 +77,14 @@ Description-Content-Type: text/markdown
65
77
  [![Python](https://img.shields.io/pypi/pyversions/evalsuite-python)](https://pypi.org/project/evalsuite-python/)
66
78
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
67
79
 
68
- **Unified, reproducible evaluation for machine learning and research.**
80
+ **Unified, reproducible evaluation for machine learning, LLM and research.**
69
81
 
70
82
  EvalSuite brings classification, regression, clinical, statistical, segmentation and object-detection
71
83
  evaluation into one consistent, validated, documented framework.
72
84
 
73
- > **Status: stable (0.3.1).** Every item on the 0.1.0, 0.2.0 and 0.3.0 roadmaps is implemented and verified.
85
+ > **Status: stable (0.4.1).** Every item on the 0.1.0, 0.2.0, 0.3.0 and 0.4.0 roadmaps is implemented and verified
86
+ > (except SPICE, which needs a Java scene-graph parser).
87
+ > **LLM evaluation is available from 0.4.0**; LLM systems, safety and operations are planned for 0.5.0.
74
88
 
75
89
  ## Installation
76
90
 
@@ -226,6 +240,22 @@ Models can be compared over the same images with intervals and paired tests, as
226
240
  `es.compare(y_true, {"unet": masks_a, "deeplab": masks_b})` resamples images; for detection it compares
227
241
  mAP.
228
242
 
243
+ ## LLM evaluation
244
+
245
+ ```python
246
+ es.bleu(references, predictions) # sacreBLEU-identical; also chrf, ter, rouge_l, meteor, cider
247
+ es.text_report(references, predictions) # BLEU, chrF(++), TER, ROUGE, METEOR, EM, token F1 at once
248
+ es.bertscore(ref_token_embs, pred_token_embs) # from your encoder's embeddings; also mauve, moverscore
249
+ es.model_score(refs, preds, scorer=comet_fn) # any learned metric or judge, with intervals and compare
250
+ es.faithfulness(claim_verdicts) # also hallucination_rate, citation_recall, answer_correctness
251
+ es.bradley_terry(comparisons, scale="elo") # also win_rate, elo_ratings, krippendorff_alpha
252
+ es.ndcg_at_k(relevant, retrieved, k=10) # also mrr, context_precision, context_recall
253
+ es.json_schema_compliance(outputs, schema) # also tool_call_f1, instruction_compliance_rate
254
+ es.pass_at_k(n_samples, n_correct, k=10) # also benchmark_accuracy(..., style="gsm8k")
255
+ es.compare(references, {"a": preds_a, "b": preds_b}, metrics=["bleu", "rouge_l"]) # paired over examples
256
+ es.plot.ratings(comparisons) # Bradley–Terry leaderboard with intervals; also win_matrix, text_scores
257
+ ```
258
+
229
259
  ## Classification report
230
260
 
231
261
  ```python
@@ -283,28 +313,41 @@ Input files can be CSV, TSV, Parquet or JSON. Output format follows `--format` o
283
313
  ## Performance
284
314
 
285
315
  Benchmarked against reference implementations on the same data (fastest of 5 runs; Python 3.12, NumPy 2.5,
286
- Linux x86_64). **Overall: 45 of 45 rows agree with the reference** (largest
287
- difference 2.8e-14), 32 are faster, and the geometric-mean speed-up across all
288
- 15 cases and three sizes is **2.22×**. At 1,000,000 samples (pixels for
289
- segmentation; 1,000 images for detection and 50 for Hausdorff), in alphabetical order:
316
+ Linux x86_64). **Overall: 63 of 63 rows agree with the reference** (largest
317
+ difference 1.8e-14), 42 are faster, and the geometric-mean speed-up across all
318
+ 21 cases and three sizes is **2.12×**. At 1,000,000 samples (pixels for
319
+ segmentation; 1,000 images for detection and 50 for Hausdorff; 10,000 examples for the LLM cases), in
320
+ alphabetical order:
290
321
 
291
322
  | Case | Reference | EvalSuite (ms) | Reference (ms) | Speed-up |
292
323
  | --- | --- | ---: | ---: | ---: |
293
- | 10 classes: macro F1 | scikit-learn | 29.3 | 130.8 | **4.5×** |
294
- | binary: 8 label metrics via evaluate() | scikit-learn | 39.5 | 1084.1 | **27.4×** |
295
- | binary: ROC AUC | scikit-learn | 195.0 | 348.3 | **1.8×** |
296
- | calibration: slope and intercept | statsmodels | 193.0 | 1068.0 | **5.5×** |
297
- | clinical: diagnostic report (7 CIs) | statsmodels | 23.5 | 4.7 | 0.20× |
298
- | clinical: sensitivity, specificity, LR+, LR− | scikit-learn | 69.1 | 414.0 | **6.0×** |
299
- | decision curve: 99 thresholds | NumPy loop | 156.3 | 181.6 | **1.2×** |
300
- | detection: COCO evaluation (1000 images) | pycocotools | 817.3 | 983.7 | **1.2×** |
301
- | multiple testing: Hochberg (n p-values) | statsmodels | 82.0 | 108.0 | **1.3×** |
302
- | regression: MAE, MSE, RMSE, R² via evaluate() | scikit-learn | 23.1 | 10.8 | 0.47× |
303
- | segmentation: Dice and IoU per class (n = pixels) | scikit-learn | 43.0 | 290.0 | **6.8×** |
304
- | segmentation: Hausdorff distance (50 images) | SciPy | 27.0 | 20.2 | 0.75× |
305
- | statistics: Cramér's V (5×5 table) | SciPy | 0.5 | 0.4 | 0.88× |
306
- | statistics: Mann–Whitney U | SciPy | 349.7 | 350.2 | **1.0×** |
307
- | statistics: Welch t-test | SciPy | 14.5 | 7.2 | 0.49× |
324
+ | 10 classes: macro F1 | scikit-learn | 23.8 | 135.5 | **5.7×** |
325
+ | agreement: Krippendorff's alpha, interval (4 raters × 10000 items) | krippendorff | 3.5 | 3.4 | 0.96× |
326
+ | binary: 8 label metrics via evaluate() | scikit-learn | 28.5 | 1023.8 | **36.0×** |
327
+ | binary: ROC AUC | scikit-learn | 187.4 | 327.3 | **1.7×** |
328
+ | calibration: slope and intercept | statsmodels | 205.7 | 1173.7 | **5.7×** |
329
+ | clinical: diagnostic report (7 CIs) | statsmodels | 19.6 | 4.9 | 0.25× |
330
+ | clinical: sensitivity, specificity, LR+, LR− | scikit-learn | 75.2 | 411.5 | **5.5×** |
331
+ | decision curve: 99 thresholds | NumPy loop | 165.0 | 201.9 | **1.2×** |
332
+ | detection: COCO evaluation (1000 images) | pycocotools | 838.7 | 848.6 | **1.0×** |
333
+ | multiple testing: Hochberg (n p-values) | statsmodels | 72.1 | 79.0 | **1.1×** |
334
+ | regression: MAE, MSE, RMSE, R² via evaluate() | scikit-learn | 22.9 | 10.6 | 0.47× |
335
+ | retrieval: MRR, MAP@20, NDCG@10 (10000 queries) | ranx | 170.4 | 861.0 | **5.1×** |
336
+ | segmentation: Dice and IoU per class (n = pixels) | scikit-learn | 34.3 | 256.0 | **7.5×** |
337
+ | segmentation: Hausdorff distance (50 images) | SciPy | 24.2 | 19.8 | 0.82× |
338
+ | statistics: Cramér's V (5×5 table) | SciPy | 0.2 | 0.2 | **1.0×** |
339
+ | statistics: Mann–Whitney U | SciPy | 353.5 | 340.6 | 0.96× |
340
+ | statistics: Welch t-test | SciPy | 16.1 | 8.3 | 0.52× |
341
+ | structured: JSON Schema compliance (10000 documents) | jsonschema | 144.6 | 330.5 | **2.3×** |
342
+ | text: corpus BLEU and chrF (10000 sentences) | sacreBLEU | 2789.8 | 3051.8 | **1.1×** |
343
+ | text: METEOR, exact and stem matches (10000 sentences) | NLTK | 488.1 | 626.7 | **1.3×** |
344
+ | text: ROUGE-1, ROUGE-2, ROUGE-L (10000 sentences) | rouge-score | 1290.1 | 1095.6 | 0.85× |
345
+
346
+ **Every metric is benchmarked too** (`evalsuite benchmark --suite metrics`): all 147 registered metrics and
347
+ statistics functions at 10,000 and 100,000 samples. 79 are compared with a reference library, 49 with an
348
+ independent textbook formula and 19 (learned, judge-dependent or randomised) are timed alone; **all 128
349
+ comparisons agree**, and against the libraries the geometric-mean speed-up is **2.76×** (123 of 158
350
+ measurements faster). Per-metric table in BENCHMARKS.md.
308
351
 
309
352
  `evaluate()` validates inputs once and builds the confusion matrix once for all metrics, which is where most
310
353
  of the speed-up comes from. Hypothesis tests use SciPy underneath, so they match its speed at best; rows
@@ -5,12 +5,14 @@
5
5
  [![Python](https://img.shields.io/pypi/pyversions/evalsuite-python)](https://pypi.org/project/evalsuite-python/)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
7
 
8
- **Unified, reproducible evaluation for machine learning and research.**
8
+ **Unified, reproducible evaluation for machine learning, LLM and research.**
9
9
 
10
10
  EvalSuite brings classification, regression, clinical, statistical, segmentation and object-detection
11
11
  evaluation into one consistent, validated, documented framework.
12
12
 
13
- > **Status: stable (0.3.1).** Every item on the 0.1.0, 0.2.0 and 0.3.0 roadmaps is implemented and verified.
13
+ > **Status: stable (0.4.1).** Every item on the 0.1.0, 0.2.0, 0.3.0 and 0.4.0 roadmaps is implemented and verified
14
+ > (except SPICE, which needs a Java scene-graph parser).
15
+ > **LLM evaluation is available from 0.4.0**; LLM systems, safety and operations are planned for 0.5.0.
14
16
 
15
17
  ## Installation
16
18
 
@@ -166,6 +168,22 @@ Models can be compared over the same images with intervals and paired tests, as
166
168
  `es.compare(y_true, {"unet": masks_a, "deeplab": masks_b})` resamples images; for detection it compares
167
169
  mAP.
168
170
 
171
+ ## LLM evaluation
172
+
173
+ ```python
174
+ es.bleu(references, predictions) # sacreBLEU-identical; also chrf, ter, rouge_l, meteor, cider
175
+ es.text_report(references, predictions) # BLEU, chrF(++), TER, ROUGE, METEOR, EM, token F1 at once
176
+ es.bertscore(ref_token_embs, pred_token_embs) # from your encoder's embeddings; also mauve, moverscore
177
+ es.model_score(refs, preds, scorer=comet_fn) # any learned metric or judge, with intervals and compare
178
+ es.faithfulness(claim_verdicts) # also hallucination_rate, citation_recall, answer_correctness
179
+ es.bradley_terry(comparisons, scale="elo") # also win_rate, elo_ratings, krippendorff_alpha
180
+ es.ndcg_at_k(relevant, retrieved, k=10) # also mrr, context_precision, context_recall
181
+ es.json_schema_compliance(outputs, schema) # also tool_call_f1, instruction_compliance_rate
182
+ es.pass_at_k(n_samples, n_correct, k=10) # also benchmark_accuracy(..., style="gsm8k")
183
+ es.compare(references, {"a": preds_a, "b": preds_b}, metrics=["bleu", "rouge_l"]) # paired over examples
184
+ es.plot.ratings(comparisons) # Bradley–Terry leaderboard with intervals; also win_matrix, text_scores
185
+ ```
186
+
169
187
  ## Classification report
170
188
 
171
189
  ```python
@@ -223,28 +241,41 @@ Input files can be CSV, TSV, Parquet or JSON. Output format follows `--format` o
223
241
  ## Performance
224
242
 
225
243
  Benchmarked against reference implementations on the same data (fastest of 5 runs; Python 3.12, NumPy 2.5,
226
- Linux x86_64). **Overall: 45 of 45 rows agree with the reference** (largest
227
- difference 2.8e-14), 32 are faster, and the geometric-mean speed-up across all
228
- 15 cases and three sizes is **2.22×**. At 1,000,000 samples (pixels for
229
- segmentation; 1,000 images for detection and 50 for Hausdorff), in alphabetical order:
244
+ Linux x86_64). **Overall: 63 of 63 rows agree with the reference** (largest
245
+ difference 1.8e-14), 42 are faster, and the geometric-mean speed-up across all
246
+ 21 cases and three sizes is **2.12×**. At 1,000,000 samples (pixels for
247
+ segmentation; 1,000 images for detection and 50 for Hausdorff; 10,000 examples for the LLM cases), in
248
+ alphabetical order:
230
249
 
231
250
  | Case | Reference | EvalSuite (ms) | Reference (ms) | Speed-up |
232
251
  | --- | --- | ---: | ---: | ---: |
233
- | 10 classes: macro F1 | scikit-learn | 29.3 | 130.8 | **4.5×** |
234
- | binary: 8 label metrics via evaluate() | scikit-learn | 39.5 | 1084.1 | **27.4×** |
235
- | binary: ROC AUC | scikit-learn | 195.0 | 348.3 | **1.8×** |
236
- | calibration: slope and intercept | statsmodels | 193.0 | 1068.0 | **5.5×** |
237
- | clinical: diagnostic report (7 CIs) | statsmodels | 23.5 | 4.7 | 0.20× |
238
- | clinical: sensitivity, specificity, LR+, LR− | scikit-learn | 69.1 | 414.0 | **6.0×** |
239
- | decision curve: 99 thresholds | NumPy loop | 156.3 | 181.6 | **1.2×** |
240
- | detection: COCO evaluation (1000 images) | pycocotools | 817.3 | 983.7 | **1.2×** |
241
- | multiple testing: Hochberg (n p-values) | statsmodels | 82.0 | 108.0 | **1.3×** |
242
- | regression: MAE, MSE, RMSE, R² via evaluate() | scikit-learn | 23.1 | 10.8 | 0.47× |
243
- | segmentation: Dice and IoU per class (n = pixels) | scikit-learn | 43.0 | 290.0 | **6.8×** |
244
- | segmentation: Hausdorff distance (50 images) | SciPy | 27.0 | 20.2 | 0.75× |
245
- | statistics: Cramér's V (5×5 table) | SciPy | 0.5 | 0.4 | 0.88× |
246
- | statistics: Mann–Whitney U | SciPy | 349.7 | 350.2 | **1.0×** |
247
- | statistics: Welch t-test | SciPy | 14.5 | 7.2 | 0.49× |
252
+ | 10 classes: macro F1 | scikit-learn | 23.8 | 135.5 | **5.7×** |
253
+ | agreement: Krippendorff's alpha, interval (4 raters × 10000 items) | krippendorff | 3.5 | 3.4 | 0.96× |
254
+ | binary: 8 label metrics via evaluate() | scikit-learn | 28.5 | 1023.8 | **36.0×** |
255
+ | binary: ROC AUC | scikit-learn | 187.4 | 327.3 | **1.7×** |
256
+ | calibration: slope and intercept | statsmodels | 205.7 | 1173.7 | **5.7×** |
257
+ | clinical: diagnostic report (7 CIs) | statsmodels | 19.6 | 4.9 | 0.25× |
258
+ | clinical: sensitivity, specificity, LR+, LR− | scikit-learn | 75.2 | 411.5 | **5.5×** |
259
+ | decision curve: 99 thresholds | NumPy loop | 165.0 | 201.9 | **1.2×** |
260
+ | detection: COCO evaluation (1000 images) | pycocotools | 838.7 | 848.6 | **1.0×** |
261
+ | multiple testing: Hochberg (n p-values) | statsmodels | 72.1 | 79.0 | **1.1×** |
262
+ | regression: MAE, MSE, RMSE, R² via evaluate() | scikit-learn | 22.9 | 10.6 | 0.47× |
263
+ | retrieval: MRR, MAP@20, NDCG@10 (10000 queries) | ranx | 170.4 | 861.0 | **5.1×** |
264
+ | segmentation: Dice and IoU per class (n = pixels) | scikit-learn | 34.3 | 256.0 | **7.5×** |
265
+ | segmentation: Hausdorff distance (50 images) | SciPy | 24.2 | 19.8 | 0.82× |
266
+ | statistics: Cramér's V (5×5 table) | SciPy | 0.2 | 0.2 | **1.0×** |
267
+ | statistics: Mann–Whitney U | SciPy | 353.5 | 340.6 | 0.96× |
268
+ | statistics: Welch t-test | SciPy | 16.1 | 8.3 | 0.52× |
269
+ | structured: JSON Schema compliance (10000 documents) | jsonschema | 144.6 | 330.5 | **2.3×** |
270
+ | text: corpus BLEU and chrF (10000 sentences) | sacreBLEU | 2789.8 | 3051.8 | **1.1×** |
271
+ | text: METEOR, exact and stem matches (10000 sentences) | NLTK | 488.1 | 626.7 | **1.3×** |
272
+ | text: ROUGE-1, ROUGE-2, ROUGE-L (10000 sentences) | rouge-score | 1290.1 | 1095.6 | 0.85× |
273
+
274
+ **Every metric is benchmarked too** (`evalsuite benchmark --suite metrics`): all 147 registered metrics and
275
+ statistics functions at 10,000 and 100,000 samples. 79 are compared with a reference library, 49 with an
276
+ independent textbook formula and 19 (learned, judge-dependent or randomised) are timed alone; **all 128
277
+ comparisons agree**, and against the libraries the geometric-mean speed-up is **2.76×** (123 of 158
278
+ measurements faster). Per-metric table in BENCHMARKS.md.
248
279
 
249
280
  `evaluate()` validates inputs once and builds the confusion matrix once for all metrics, which is where most
250
281
  of the speed-up comes from. Hypothesis tests use SciPy underneath, so they match its speed at best; rows
@@ -38,7 +38,8 @@ dependencies = ["numpy>=1.22", "scipy>=1.8", "pandas>=1.4"]
38
38
  [project.optional-dependencies]
39
39
  plot = ["matplotlib>=3.5"]
40
40
  vision = ["pillow>=9"]
41
- all = ["matplotlib>=3.5", "pillow>=9"]
41
+ llm = ["nltk>=3.8"]
42
+ all = ["matplotlib>=3.5", "pillow>=9", "nltk>=3.8"]
42
43
  dev = [
43
44
  "pytest>=7",
44
45
  "pytest-cov>=4",
@@ -48,6 +49,15 @@ dev = [
48
49
  "matplotlib>=3.5",
49
50
  "pillow>=9",
50
51
  "pycocotools>=2.0.7",
52
+ "nltk>=3.8",
53
+ "sacrebleu>=2.4",
54
+ "rouge-score>=0.1.2",
55
+ "pycocoevalcap>=1.2",
56
+ "jsonschema>=4.18",
57
+ "choix>=0.3",
58
+ "krippendorff>=0.6",
59
+ "pot>=0.9; python_version < '3.14'",
60
+ "ranx>=0.3.19; python_version < '3.14'",
51
61
  "ruff>=0.6",
52
62
  "mypy>=1.10",
53
63
  "pandas-stubs",
@@ -99,6 +109,12 @@ files = ["src/evalsuite"]
99
109
  module = ["scipy.*", "matplotlib.*"]
100
110
  ignore_missing_imports = true
101
111
 
112
+ [[tool.mypy.overrides]]
113
+ # optional reference libraries used only by the benchmarks and METEOR's default stemmer
114
+ module = ["sacrebleu.*", "rouge_score.*", "nltk.*", "ranx.*", "krippendorff.*", "jsonschema.*", "pycocotools.*"]
115
+ ignore_missing_imports = true
116
+ follow_untyped_imports = false
117
+
102
118
  [tool.pytest.ini_options]
103
119
  testpaths = ["tests"]
104
120
  addopts = "-q --strict-markers"
@@ -5,7 +5,7 @@
5
5
  >>> print(result.summary()) # doctest: +SKIP
6
6
  """
7
7
 
8
- from . import calibration, classification, clinical, plot, regression, stats, vision
8
+ from . import calibration, classification, clinical, plot, regression, stats, text, vision
9
9
  from .api import evaluate
10
10
  from .calibration import (
11
11
  CalibrationReport,
@@ -110,6 +110,8 @@ from .stats import (
110
110
  t_test,
111
111
  wilcoxon_test,
112
112
  )
113
+ from .text import * # noqa: F403 (every LLM-evaluation function, listed in text.__all__)
114
+ from .text import __all__ as _text_all
113
115
  from .version import __version__
114
116
  from .vision import (
115
117
  DetectionReport,
@@ -134,6 +136,7 @@ from .vision import (
134
136
  )
135
137
 
136
138
  __all__ = [
139
+ "text",
137
140
  "SegmentationReport",
138
141
  "segmentation_report",
139
142
  "detection_pr_curve",
@@ -258,3 +261,4 @@ __all__ = [
258
261
  "specificity",
259
262
  "top_k_accuracy",
260
263
  ]
264
+ __all__ += list(_text_all)