fast-ivap 1.0.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.
@@ -0,0 +1,18 @@
1
+ # Build artefacts
2
+ build/
3
+ dist/
4
+ wheelhouse/
5
+ *.so
6
+ *.pyd
7
+
8
+ # Python
9
+ __pycache__/
10
+ *.egg-info/
11
+ .venv/
12
+ .pytest_cache/
13
+ .ruff_cache/
14
+
15
+ # Editors / notebooks
16
+ .vscode/
17
+ .idea/
18
+ .ipynb_checkpoints/
@@ -0,0 +1,35 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 - 2026-10-27
4
+
5
+ Complete rewrite, published under the name `fast-ivap` (import `fast_ivap`).
6
+
7
+ ### Fixed
8
+ - `p0` and `p1` were wrong for a test score equal to one of the calibration
9
+ scores.
10
+ - `p1` was wrong for a test score above all calibration scores (it must be 1).
11
+ - The pure-Python implementation failed on NumPy 2 (`np.cross` on 2-D vectors).
12
+ - Removed the module-level global state, so separate predictors no longer
13
+ interfere with each other.
14
+
15
+ ### Changed
16
+ - New API: `fast_ivap.IVAP` (`fit`, `predict_p0_p1`, `predict_proba`) and
17
+ `fast_ivap.sklearn.VennAbersCalibrator`, whose `predict_proba` now returns
18
+ an `(n, 2)` array as scikit-learn expects. `ScoresToMultiProbs` is kept as a
19
+ deprecated shim.
20
+ - The C++ code is now a dependency-free header-only library, with nanobind
21
+ bindings (zero-copy NumPy input, GIL released) built by scikit-build-core.
22
+ - Portable wheels for Linux, macOS and Windows via cibuildwheel.
23
+
24
+ ### Added
25
+ - `merge_log_minimax` (IVAP and CVAP) and `merge_brier`.
26
+ - pytest suite checking both backends against IVAP computed from its
27
+ definition; C++ tests via CTest; CI on Linux, macOS and Windows.
28
+
29
+ ## 0.2 - 2020-07
30
+ - Fixed bug affecting the `p0` calculation; added a test notebook.
31
+ - (2024, branches `cpp_version` / `pip_package`) C++ port with pybind11 and a
32
+ scikit-learn style wrapper.
33
+
34
+ ## 0.1
35
+ - Initial pure-Python implementation.
@@ -0,0 +1,48 @@
1
+ cmake_minimum_required(VERSION 3.18...3.31)
2
+ project(fast_ivap LANGUAGES CXX)
3
+
4
+ # Header-only C++ library: fast_ivap::fast_ivap
5
+ add_library(fast_ivap INTERFACE)
6
+ add_library(fast_ivap::fast_ivap ALIAS fast_ivap)
7
+ target_include_directories(
8
+ fast_ivap INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
9
+ $<INSTALL_INTERFACE:include>)
10
+ target_compile_features(fast_ivap INTERFACE cxx_std_20)
11
+
12
+ if(SKBUILD)
13
+ # Python extension module fast_ivap._core, built by scikit-build-core.
14
+ find_package(Python 3.11 REQUIRED
15
+ COMPONENTS Interpreter Development.Module ${SKBUILD_SABI_COMPONENT})
16
+ find_package(nanobind CONFIG REQUIRED)
17
+ nanobind_add_module(_core STABLE_ABI NB_STATIC src/bindings/core.cpp)
18
+ target_link_libraries(_core PRIVATE fast_ivap)
19
+ install(TARGETS _core LIBRARY DESTINATION fast_ivap)
20
+ return()
21
+ endif()
22
+
23
+ # Standalone C++ build: tests, example and install rules for find_package().
24
+ option(FAST_IVAP_BUILD_TESTS "Build the C++ tests" ${PROJECT_IS_TOP_LEVEL})
25
+ option(FAST_IVAP_BUILD_EXAMPLES "Build the C++ example" ${PROJECT_IS_TOP_LEVEL})
26
+
27
+ if(FAST_IVAP_BUILD_TESTS)
28
+ enable_testing()
29
+ add_executable(test_ivap tests/cpp/test_ivap.cpp)
30
+ target_link_libraries(test_ivap PRIVATE fast_ivap)
31
+ add_test(NAME test_ivap COMMAND test_ivap)
32
+ endif()
33
+
34
+ if(FAST_IVAP_BUILD_EXAMPLES)
35
+ add_executable(ivap_example examples/cpp/example.cpp)
36
+ target_link_libraries(ivap_example PRIVATE fast_ivap)
37
+ endif()
38
+
39
+ include(GNUInstallDirs)
40
+ include(CMakePackageConfigHelpers)
41
+ install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
42
+ install(TARGETS fast_ivap EXPORT fast_ivapTargets)
43
+ install(EXPORT fast_ivapTargets NAMESPACE fast_ivap::
44
+ DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/fast_ivap)
45
+ file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/fast_ivapConfig.cmake
46
+ "include(\"\${CMAKE_CURRENT_LIST_DIR}/fast_ivapTargets.cmake\")\n")
47
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fast_ivapConfig.cmake
48
+ DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/fast_ivap)
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Paolo Toccaceli, Royal Holloway, Univ. of London
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,188 @@
1
+ Metadata-Version: 2.4
2
+ Name: fast-ivap
3
+ Version: 1.0.0
4
+ Summary: Fast inductive Venn-ABERS predictors: distribution-free calibration of classifier scores
5
+ Keywords: calibration,conformal prediction,venn-abers,isotonic regression,probability
6
+ Author: Paolo Toccaceli
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Programming Language :: C++
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
14
+ Classifier: Typing :: Typed
15
+ Project-URL: Homepage, https://github.com/ptocca/VennABERS
16
+ Project-URL: Paper, https://arxiv.org/abs/1511.00213
17
+ Requires-Python: >=3.11
18
+ Requires-Dist: numpy>=1.25
19
+ Provides-Extra: sklearn
20
+ Requires-Dist: scikit-learn>=1.6; extra == "sklearn"
21
+ Description-Content-Type: text/markdown
22
+
23
+ # fast-ivap: fast inductive Venn-ABERS predictors
24
+
25
+ [![CI](https://github.com/ptocca/VennABERS/actions/workflows/ci.yml/badge.svg)](https://github.com/ptocca/VennABERS/actions/workflows/ci.yml)
26
+
27
+ `fast-ivap` turns the scores of any binary classifier into **well-calibrated
28
+ probabilities**, with no assumption beyond the calibration and test data being
29
+ i.i.d. It implements the inductive Venn-ABERS predictor (IVAP) with the
30
+ O(k log k) algorithm of
31
+
32
+ > V. Vovk, I. Petej, V. Fedorova. *Large-scale probabilistic predictors with
33
+ > and without guarantees of validity.* NeurIPS 2015.
34
+ > [arXiv:1511.00213](https://arxiv.org/abs/1511.00213)
35
+
36
+ The core is a small header-only C++20 library with Python bindings
37
+ ([nanobind](https://github.com/wjakob/nanobind)), plus a pure-Python
38
+ reference implementation. A gentle introduction to Venn-ABERS predictors is in
39
+ this [tutorial](https://cml.rhul.ac.uk/people/ptocca/HomePage/Toccaceli_CP___Venn_Tutorial.pdf).
40
+
41
+ ## What it computes
42
+
43
+ Given calibration scores and labels, and the score `s` of a test object, an
44
+ IVAP outputs two probabilities that the label is 1:
45
+
46
+ - `p0`: the isotonic-regression fit at `s` after adding `(s, 0)` to the
47
+ calibration set,
48
+ - `p1`: the same after adding `(s, 1)`.
49
+
50
+ `p0 <= p1` always holds, and one of the two (which one depends on the unknown
51
+ true label) is perfectly calibrated. The gap `p1 - p0` is typically small and
52
+ shrinks as the calibration set grows. A single probability can be
53
+ obtained with the log-loss minimax merge
54
+
55
+ $$p = \frac{p_1}{1 - p_0 + p_1}.$$
56
+
57
+ Fitting takes O(k log k) for k calibration examples; each prediction takes
58
+ O(log k).
59
+
60
+ ## Installation
61
+
62
+ ```bash
63
+ pip install fast-ivap # NumPy API
64
+ pip install "fast-ivap[sklearn]" # plus the scikit-learn estimator
65
+ ```
66
+
67
+ Until the package is on PyPI, install from GitHub (this builds from source, so
68
+ it needs a C++20 compiler; CMake is fetched automatically if missing):
69
+
70
+ ```bash
71
+ pip install git+https://github.com/ptocca/VennABERS
72
+ ```
73
+
74
+ Prebuilt wheels are produced for Linux (x86-64, aarch64; glibc and musl),
75
+ macOS (Intel and Apple silicon) and Windows (x86-64, ARM64), for CPython 3.11
76
+ and a single stable-ABI wheel for CPython 3.12 and later.
77
+
78
+ ## Usage
79
+
80
+ ### NumPy
81
+
82
+ ```python
83
+ from fast_ivap import IVAP
84
+
85
+ ivap = IVAP().fit(cal_scores, cal_labels) # labels are 0/1 or booleans
86
+ p0, p1 = ivap.predict_p0_p1(test_scores) # Venn-ABERS pair
87
+ p = ivap.predict_proba(test_scores) # merged probability of label 1
88
+ ```
89
+
90
+ See [`examples/quickstart.py`](examples/quickstart.py) for a complete example
91
+ with a scikit-learn classifier.
92
+
93
+ For a cross Venn-ABERS predictor (CVAP), fit one IVAP per fold, stack the
94
+ outputs and merge them with geometric means:
95
+
96
+ ```python
97
+ from fast_ivap import merge_log_minimax
98
+
99
+ p = merge_log_minimax(p0_folds, p1_folds, axis=0) # arrays of shape (K, n)
100
+ ```
101
+
102
+ `merge_brier` gives the Brier-loss minimax merge instead.
103
+
104
+ ### scikit-learn
105
+
106
+ `VennAbersCalibrator` takes one score per example and follows the
107
+ scikit-learn classifier API (`predict_proba` returns `[1 - p, p]`):
108
+
109
+ ```python
110
+ from fast_ivap.sklearn import VennAbersCalibrator
111
+
112
+ cal = VennAbersCalibrator().fit(clf.decision_function(X_cal), y_cal)
113
+ proba = cal.predict_proba(clf.decision_function(X_test))
114
+ p0, p1 = cal.predict_p0_p1(clf.decision_function(X_test))
115
+ ```
116
+
117
+ ### C++
118
+
119
+ The C++ library is the single header
120
+ [`include/fast_ivap/ivap.hpp`](include/fast_ivap/ivap.hpp) with no
121
+ dependencies. Copy it into your project, or install it and use CMake:
122
+
123
+ ```bash
124
+ cmake -S . -B build && cmake --install build --prefix /your/prefix
125
+ ```
126
+
127
+ ```cmake
128
+ find_package(fast_ivap REQUIRED)
129
+ target_link_libraries(my_app PRIVATE fast_ivap::fast_ivap)
130
+ ```
131
+
132
+ ```cpp
133
+ #include <fast_ivap/ivap.hpp>
134
+
135
+ auto cal = fast_ivap::fit(scores, labels); // any contiguous range of doubles
136
+ auto [p0, p1] = fast_ivap::predict(cal, test_scores);
137
+ ```
138
+
139
+ ## Implementation notes
140
+
141
+ - The C++ backend is used when available. `IVAP(backend="python")` or the
142
+ environment variable `FAST_IVAP_BACKEND=python` select the pure-Python
143
+ implementation in [`_reference.py`](src/fast_ivap/_reference.py), which
144
+ follows the paper step by step. Both are tested against each other and
145
+ against a brute-force IVAP computed from its definition.
146
+ - `p1` is computed with Algorithms 1 and 2 of the paper. Instead of the
147
+ mirror-image Algorithms 3 and 4, `p0` is obtained from the same code by the
148
+ symmetry noted in the paper: negate the scores, flip the labels, and take
149
+ `1 - p1`.
150
+ - The paper defines the extra CSD point for Algorithms 3–4 as
151
+ `P[k'+1] = P[k'] + (1, 1)`; it should be `P[k'] + (1, 0)`, because that
152
+ segment represents the test object with label 0. The original
153
+ implementation already used `(1, 0)`.
154
+ - A test score equal to a calibration score, and a test score outside the
155
+ range of the calibration scores, are handled exactly as in the definition
156
+ (two bugs in versions up to 0.2 affected these cases).
157
+ - A NaN test score yields NaN probabilities. Calibration scores must be finite.
158
+
159
+ ## Development
160
+
161
+ ```bash
162
+ uv sync --group dev # build the extension and install dev tools
163
+ uv run pytest # Python tests (both backends)
164
+ uv run ruff check . && uv run ruff format --check .
165
+
166
+ cmake -S . -B build && cmake --build build && ctest --test-dir build # C++ tests
167
+ ```
168
+
169
+ The GitHub Actions workflows run the tests on Linux, macOS and Windows, and
170
+ build wheels with [cibuildwheel](https://cibuildwheel.pypa.io/). Publishing a
171
+ GitHub release uploads the wheels and sdist to PyPI (trusted publishing).
172
+
173
+ ## Version history
174
+
175
+ See [CHANGELOG.md](CHANGELOG.md).
176
+
177
+ ## Acknowledgements
178
+
179
+ - The algorithm was invented by Prof. Vladimir Vovk et al. at the
180
+ [Centre for Reliable Machine Learning, Royal Holloway, University of London](https://cml.rhul.ac.uk/).
181
+ - This work was supported in part by funding from the European Union's Horizon
182
+ 2020 Research and Innovation programme under Grant Agreement no. 671555
183
+ (ExCAPE).
184
+ - We are grateful to the Ministry of Education, Youth and Sports (Czech
185
+ Republic) that supports the Large Infrastructures for Research, Experimental
186
+ Development and Innovations project "IT4Innovations National Supercomputing
187
+ Center - LM2015070" for providing access to the Solomon supercomputing
188
+ cluster.
@@ -0,0 +1,166 @@
1
+ # fast-ivap: fast inductive Venn-ABERS predictors
2
+
3
+ [![CI](https://github.com/ptocca/VennABERS/actions/workflows/ci.yml/badge.svg)](https://github.com/ptocca/VennABERS/actions/workflows/ci.yml)
4
+
5
+ `fast-ivap` turns the scores of any binary classifier into **well-calibrated
6
+ probabilities**, with no assumption beyond the calibration and test data being
7
+ i.i.d. It implements the inductive Venn-ABERS predictor (IVAP) with the
8
+ O(k log k) algorithm of
9
+
10
+ > V. Vovk, I. Petej, V. Fedorova. *Large-scale probabilistic predictors with
11
+ > and without guarantees of validity.* NeurIPS 2015.
12
+ > [arXiv:1511.00213](https://arxiv.org/abs/1511.00213)
13
+
14
+ The core is a small header-only C++20 library with Python bindings
15
+ ([nanobind](https://github.com/wjakob/nanobind)), plus a pure-Python
16
+ reference implementation. A gentle introduction to Venn-ABERS predictors is in
17
+ this [tutorial](https://cml.rhul.ac.uk/people/ptocca/HomePage/Toccaceli_CP___Venn_Tutorial.pdf).
18
+
19
+ ## What it computes
20
+
21
+ Given calibration scores and labels, and the score `s` of a test object, an
22
+ IVAP outputs two probabilities that the label is 1:
23
+
24
+ - `p0`: the isotonic-regression fit at `s` after adding `(s, 0)` to the
25
+ calibration set,
26
+ - `p1`: the same after adding `(s, 1)`.
27
+
28
+ `p0 <= p1` always holds, and one of the two (which one depends on the unknown
29
+ true label) is perfectly calibrated. The gap `p1 - p0` is typically small and
30
+ shrinks as the calibration set grows. A single probability can be
31
+ obtained with the log-loss minimax merge
32
+
33
+ $$p = \frac{p_1}{1 - p_0 + p_1}.$$
34
+
35
+ Fitting takes O(k log k) for k calibration examples; each prediction takes
36
+ O(log k).
37
+
38
+ ## Installation
39
+
40
+ ```bash
41
+ pip install fast-ivap # NumPy API
42
+ pip install "fast-ivap[sklearn]" # plus the scikit-learn estimator
43
+ ```
44
+
45
+ Until the package is on PyPI, install from GitHub (this builds from source, so
46
+ it needs a C++20 compiler; CMake is fetched automatically if missing):
47
+
48
+ ```bash
49
+ pip install git+https://github.com/ptocca/VennABERS
50
+ ```
51
+
52
+ Prebuilt wheels are produced for Linux (x86-64, aarch64; glibc and musl),
53
+ macOS (Intel and Apple silicon) and Windows (x86-64, ARM64), for CPython 3.11
54
+ and a single stable-ABI wheel for CPython 3.12 and later.
55
+
56
+ ## Usage
57
+
58
+ ### NumPy
59
+
60
+ ```python
61
+ from fast_ivap import IVAP
62
+
63
+ ivap = IVAP().fit(cal_scores, cal_labels) # labels are 0/1 or booleans
64
+ p0, p1 = ivap.predict_p0_p1(test_scores) # Venn-ABERS pair
65
+ p = ivap.predict_proba(test_scores) # merged probability of label 1
66
+ ```
67
+
68
+ See [`examples/quickstart.py`](examples/quickstart.py) for a complete example
69
+ with a scikit-learn classifier.
70
+
71
+ For a cross Venn-ABERS predictor (CVAP), fit one IVAP per fold, stack the
72
+ outputs and merge them with geometric means:
73
+
74
+ ```python
75
+ from fast_ivap import merge_log_minimax
76
+
77
+ p = merge_log_minimax(p0_folds, p1_folds, axis=0) # arrays of shape (K, n)
78
+ ```
79
+
80
+ `merge_brier` gives the Brier-loss minimax merge instead.
81
+
82
+ ### scikit-learn
83
+
84
+ `VennAbersCalibrator` takes one score per example and follows the
85
+ scikit-learn classifier API (`predict_proba` returns `[1 - p, p]`):
86
+
87
+ ```python
88
+ from fast_ivap.sklearn import VennAbersCalibrator
89
+
90
+ cal = VennAbersCalibrator().fit(clf.decision_function(X_cal), y_cal)
91
+ proba = cal.predict_proba(clf.decision_function(X_test))
92
+ p0, p1 = cal.predict_p0_p1(clf.decision_function(X_test))
93
+ ```
94
+
95
+ ### C++
96
+
97
+ The C++ library is the single header
98
+ [`include/fast_ivap/ivap.hpp`](include/fast_ivap/ivap.hpp) with no
99
+ dependencies. Copy it into your project, or install it and use CMake:
100
+
101
+ ```bash
102
+ cmake -S . -B build && cmake --install build --prefix /your/prefix
103
+ ```
104
+
105
+ ```cmake
106
+ find_package(fast_ivap REQUIRED)
107
+ target_link_libraries(my_app PRIVATE fast_ivap::fast_ivap)
108
+ ```
109
+
110
+ ```cpp
111
+ #include <fast_ivap/ivap.hpp>
112
+
113
+ auto cal = fast_ivap::fit(scores, labels); // any contiguous range of doubles
114
+ auto [p0, p1] = fast_ivap::predict(cal, test_scores);
115
+ ```
116
+
117
+ ## Implementation notes
118
+
119
+ - The C++ backend is used when available. `IVAP(backend="python")` or the
120
+ environment variable `FAST_IVAP_BACKEND=python` select the pure-Python
121
+ implementation in [`_reference.py`](src/fast_ivap/_reference.py), which
122
+ follows the paper step by step. Both are tested against each other and
123
+ against a brute-force IVAP computed from its definition.
124
+ - `p1` is computed with Algorithms 1 and 2 of the paper. Instead of the
125
+ mirror-image Algorithms 3 and 4, `p0` is obtained from the same code by the
126
+ symmetry noted in the paper: negate the scores, flip the labels, and take
127
+ `1 - p1`.
128
+ - The paper defines the extra CSD point for Algorithms 3–4 as
129
+ `P[k'+1] = P[k'] + (1, 1)`; it should be `P[k'] + (1, 0)`, because that
130
+ segment represents the test object with label 0. The original
131
+ implementation already used `(1, 0)`.
132
+ - A test score equal to a calibration score, and a test score outside the
133
+ range of the calibration scores, are handled exactly as in the definition
134
+ (two bugs in versions up to 0.2 affected these cases).
135
+ - A NaN test score yields NaN probabilities. Calibration scores must be finite.
136
+
137
+ ## Development
138
+
139
+ ```bash
140
+ uv sync --group dev # build the extension and install dev tools
141
+ uv run pytest # Python tests (both backends)
142
+ uv run ruff check . && uv run ruff format --check .
143
+
144
+ cmake -S . -B build && cmake --build build && ctest --test-dir build # C++ tests
145
+ ```
146
+
147
+ The GitHub Actions workflows run the tests on Linux, macOS and Windows, and
148
+ build wheels with [cibuildwheel](https://cibuildwheel.pypa.io/). Publishing a
149
+ GitHub release uploads the wheels and sdist to PyPI (trusted publishing).
150
+
151
+ ## Version history
152
+
153
+ See [CHANGELOG.md](CHANGELOG.md).
154
+
155
+ ## Acknowledgements
156
+
157
+ - The algorithm was invented by Prof. Vladimir Vovk et al. at the
158
+ [Centre for Reliable Machine Learning, Royal Holloway, University of London](https://cml.rhul.ac.uk/).
159
+ - This work was supported in part by funding from the European Union's Horizon
160
+ 2020 Research and Innovation programme under Grant Agreement no. 671555
161
+ (ExCAPE).
162
+ - We are grateful to the Ministry of Education, Youth and Sports (Czech
163
+ Republic) that supports the Large Infrastructures for Research, Experimental
164
+ Development and Innovations project "IT4Innovations National Supercomputing
165
+ Center - LM2015070" for providing access to the Solomon supercomputing
166
+ cluster.
@@ -0,0 +1,21 @@
1
+ // Minimal example of using the header-only C++ library.
2
+ //
3
+ // cmake -B build && cmake --build build && ./build/ivap_example
4
+
5
+ #include <fast_ivap/ivap.hpp>
6
+
7
+ #include <cstdio>
8
+ #include <vector>
9
+
10
+ int main() {
11
+ const std::vector<double> scores{2.0, 3.0, 4.0, 5.0, 7.0, 8.0};
12
+ const std::vector<double> labels{0.0, 1.0, 0.0, 0.0, 1.0, 1.0};
13
+ const std::vector<double> test{1.0, 2.5, 7.2};
14
+
15
+ const fast_ivap::Calibrator cal = fast_ivap::fit(scores, labels);
16
+ const auto [p0, p1] = fast_ivap::predict(cal, test);
17
+
18
+ for (std::size_t i = 0; i < test.size(); ++i) {
19
+ std::printf("score %4.1f -> p0 = %.3f, p1 = %.3f\n", test[i], p0[i], p1[i]);
20
+ }
21
+ }
@@ -0,0 +1,34 @@
1
+ """Calibrate a classifier's scores with an inductive Venn-ABERS predictor.
2
+
3
+ Run with: python examples/quickstart.py (needs scikit-learn)
4
+ """
5
+
6
+ import numpy as np
7
+ from sklearn.datasets import make_classification
8
+ from sklearn.model_selection import train_test_split
9
+ from sklearn.svm import LinearSVC
10
+
11
+ from fast_ivap import IVAP
12
+
13
+ X, y = make_classification(n_samples=20_000, n_features=20, flip_y=0.1, random_state=0)
14
+ X_train, X_rest, y_train, y_rest = train_test_split(X, y, train_size=0.5, random_state=0)
15
+ X_cal, X_test, y_cal, y_test = train_test_split(X_rest, y_rest, train_size=0.5, random_state=0)
16
+
17
+ # 1. Train any scoring classifier on the proper training set.
18
+ clf = LinearSVC().fit(X_train, y_train)
19
+
20
+ # 2. Fit the IVAP on the classifier's scores for a held-out calibration set.
21
+ ivap = IVAP().fit(clf.decision_function(X_cal), y_cal)
22
+
23
+ # 3. Predict: a pair (p0, p1) per test example, or a single merged probability.
24
+ test_scores = clf.decision_function(X_test)
25
+ p0, p1 = ivap.predict_p0_p1(test_scores)
26
+ p = ivap.predict_proba(test_scores)
27
+
28
+ print("first five test examples:")
29
+ for s, a, b, q, label in zip(test_scores[:5], p0, p1, p, y_test, strict=False):
30
+ print(f" score {s:+.2f} p0 {a:.3f} p1 {b:.3f} p {q:.3f} true label {label}")
31
+
32
+ print(f"\nmean width p1 - p0: {np.mean(p1 - p0):.4f}")
33
+ print(f"Brier score: {np.mean((p - y_test) ** 2):.4f}")
34
+ print(f"mean predicted prob.: {p.mean():.4f} observed frequency: {y_test.mean():.4f}")