nestkit 0.1.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.
- nestkit-0.1.0/LICENSE +21 -0
- nestkit-0.1.0/PKG-INFO +207 -0
- nestkit-0.1.0/README.md +160 -0
- nestkit-0.1.0/pyproject.toml +80 -0
- nestkit-0.1.0/requirements.txt +5 -0
- nestkit-0.1.0/setup.cfg +4 -0
- nestkit-0.1.0/src/nestkit/__init__.py +49 -0
- nestkit-0.1.0/src/nestkit/_base.py +398 -0
- nestkit-0.1.0/src/nestkit/_validation.py +113 -0
- nestkit-0.1.0/src/nestkit/calibration/__init__.py +12 -0
- nestkit-0.1.0/src/nestkit/calibration/calibrators.py +162 -0
- nestkit-0.1.0/src/nestkit/calibration/diagnostics.py +513 -0
- nestkit-0.1.0/src/nestkit/callbacks.py +235 -0
- nestkit-0.1.0/src/nestkit/classifier.py +559 -0
- nestkit-0.1.0/src/nestkit/comparison/__init__.py +10 -0
- nestkit-0.1.0/src/nestkit/comparison/comparator.py +391 -0
- nestkit-0.1.0/src/nestkit/comparison/statistical_tests.py +327 -0
- nestkit-0.1.0/src/nestkit/diagnostics/__init__.py +9 -0
- nestkit-0.1.0/src/nestkit/diagnostics/stability.py +201 -0
- nestkit-0.1.0/src/nestkit/importance/__init__.py +11 -0
- nestkit-0.1.0/src/nestkit/importance/aggregator.py +319 -0
- nestkit-0.1.0/src/nestkit/importance/extractors.py +180 -0
- nestkit-0.1.0/src/nestkit/importance/stability.py +106 -0
- nestkit-0.1.0/src/nestkit/inner/__init__.py +9 -0
- nestkit-0.1.0/src/nestkit/inner/search.py +151 -0
- nestkit-0.1.0/src/nestkit/inner/tuning_report.py +209 -0
- nestkit-0.1.0/src/nestkit/plotting/__init__.py +66 -0
- nestkit-0.1.0/src/nestkit/plotting/_style.py +38 -0
- nestkit-0.1.0/src/nestkit/plotting/calibration.py +220 -0
- nestkit-0.1.0/src/nestkit/plotting/comparison.py +302 -0
- nestkit-0.1.0/src/nestkit/plotting/folds.py +199 -0
- nestkit-0.1.0/src/nestkit/plotting/importance.py +242 -0
- nestkit-0.1.0/src/nestkit/plotting/summary.py +479 -0
- nestkit-0.1.0/src/nestkit/plotting/threshold.py +186 -0
- nestkit-0.1.0/src/nestkit/plotting/tuning.py +121 -0
- nestkit-0.1.0/src/nestkit/regressor.py +251 -0
- nestkit-0.1.0/src/nestkit/results/__init__.py +19 -0
- nestkit-0.1.0/src/nestkit/results/_base.py +283 -0
- nestkit-0.1.0/src/nestkit/results/classifier_results.py +279 -0
- nestkit-0.1.0/src/nestkit/results/regressor_results.py +146 -0
- nestkit-0.1.0/src/nestkit/thresholding/__init__.py +28 -0
- nestkit-0.1.0/src/nestkit/thresholding/criteria.py +288 -0
- nestkit-0.1.0/src/nestkit/thresholding/results.py +73 -0
- nestkit-0.1.0/src/nestkit/thresholding/strategies.py +300 -0
- nestkit-0.1.0/src/nestkit.egg-info/PKG-INFO +207 -0
- nestkit-0.1.0/src/nestkit.egg-info/SOURCES.txt +47 -0
- nestkit-0.1.0/src/nestkit.egg-info/dependency_links.txt +1 -0
- nestkit-0.1.0/src/nestkit.egg-info/requires.txt +31 -0
- nestkit-0.1.0/src/nestkit.egg-info/top_level.txt +1 -0
nestkit-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ettore Rocchi
|
|
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.
|
nestkit-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nestkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Nested cross-validation toolkit with optional probability calibration, threshold optimization, and comprehensive diagnostics
|
|
5
|
+
Author: Ettore Rocchi
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Intended Audience :: Science/Research
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: scikit-learn>=1.2
|
|
20
|
+
Requires-Dist: numpy>=1.22
|
|
21
|
+
Requires-Dist: pandas>=1.4
|
|
22
|
+
Requires-Dist: joblib>=1.2
|
|
23
|
+
Requires-Dist: scipy>=1.9
|
|
24
|
+
Provides-Extra: plotting
|
|
25
|
+
Requires-Dist: matplotlib>=3.5; extra == "plotting"
|
|
26
|
+
Requires-Dist: seaborn>=0.12; extra == "plotting"
|
|
27
|
+
Provides-Extra: full
|
|
28
|
+
Requires-Dist: matplotlib>=3.5; extra == "full"
|
|
29
|
+
Requires-Dist: seaborn>=0.12; extra == "full"
|
|
30
|
+
Requires-Dist: shap>=0.42; extra == "full"
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
34
|
+
Requires-Dist: hypothesis>=6.0; extra == "dev"
|
|
35
|
+
Requires-Dist: ruff; extra == "dev"
|
|
36
|
+
Requires-Dist: pre-commit; extra == "dev"
|
|
37
|
+
Provides-Extra: docs
|
|
38
|
+
Requires-Dist: sphinx>=7.0; extra == "docs"
|
|
39
|
+
Requires-Dist: pydata-sphinx-theme>=0.14; extra == "docs"
|
|
40
|
+
Requires-Dist: sphinx-copybutton; extra == "docs"
|
|
41
|
+
Requires-Dist: myst-parser>=2.0; extra == "docs"
|
|
42
|
+
Requires-Dist: numpydoc; extra == "docs"
|
|
43
|
+
Requires-Dist: nbsphinx; extra == "docs"
|
|
44
|
+
Requires-Dist: ipykernel; extra == "docs"
|
|
45
|
+
Requires-Dist: sphinx-design; extra == "docs"
|
|
46
|
+
Dynamic: license-file
|
|
47
|
+
|
|
48
|
+
<p align="center">
|
|
49
|
+
<img src="docs/_static/nestkit_logo.png" alt="nestkit" width="300">
|
|
50
|
+
</p>
|
|
51
|
+
|
|
52
|
+
<p align="center">
|
|
53
|
+
<em>A nested cross-validation toolkit for scikit-learn</em>
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
<p align="center">
|
|
57
|
+
<a href="https://pypi.org/project/nestkit/"><img src="https://img.shields.io/pypi/v/nestkit" alt="PyPI"></a>
|
|
58
|
+
<a href="https://pypi.org/project/nestkit/"><img src="https://img.shields.io/pypi/pyversions/nestkit" alt="Python"></a>
|
|
59
|
+
<a href="https://github.com/ettorerocchi/nestkit/blob/main/LICENSE"><img src="https://img.shields.io/github/license/ettorerocchi/nestkit" alt="License"></a>
|
|
60
|
+
</p>
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Motivation
|
|
65
|
+
|
|
66
|
+
Standard cross-validation conflates model selection with performance estimation, producing optimistically biased scores. When the same data that guides hyperparameter tuning is also used to report performance, the resulting estimates no longer reflect true generalization ability - a subtle but pervasive form of data leakage.
|
|
67
|
+
|
|
68
|
+
**Nested cross-validation** (nested CV) addresses this by separating the two concerns into an inner loop for hyperparameter search and an outer loop for unbiased evaluation. While conceptually simple, implementing nested CV correctly - with proper calibration, threshold optimization, and statistical comparison - requires careful engineering that is tedious and error-prone to write from scratch.
|
|
69
|
+
|
|
70
|
+
**nestkit** provides a scikit-learn-compatible implementation that handles the full pipeline: nested CV with integrated probability calibration, decision-threshold optimization, statistical model comparison, hyperparameter stability diagnostics, feature importance aggregation, and visualizations - all through a familiar `fit`/`predict` API.
|
|
71
|
+
|
|
72
|
+
## Key Features
|
|
73
|
+
|
|
74
|
+
- **Nested cross-validation** for classification and regression with full scikit-learn API compatibility
|
|
75
|
+
- **Post-hoc probability calibration** - Platt scaling, isotonic regression, beta calibration, and Venn-ABERS prediction
|
|
76
|
+
- **Threshold optimization** - Youden's J, F-beta, cost-sensitive, balanced accuracy, and precision-at-recall criteria with pooled or fold-specific strategies
|
|
77
|
+
- **Statistical model comparison** - Nadeau-Bengio corrected t-test, Bayesian correlated t-test with ROPE, and Holm-Bonferroni multi-model correction
|
|
78
|
+
- **Hyperparameter stability diagnostics** - selection frequency analysis, pairwise Jaccard similarity
|
|
79
|
+
- **Feature importance aggregation** - cross-fold importance with Nogueira stability index and consensus feature selection
|
|
80
|
+
- **Callback system** - progress tracking, logging, checkpointing, and custom hooks
|
|
81
|
+
- **25+ plotting functions** - ROC curves, confusion matrices, calibration diagrams, threshold sensitivity, critical difference diagrams, and more
|
|
82
|
+
- **Residual-based prediction intervals** for regression tasks
|
|
83
|
+
|
|
84
|
+
## Installation
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
pip install nestkit
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Optional dependency groups:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
pip install nestkit[plotting] # matplotlib + seaborn
|
|
94
|
+
pip install nestkit[full] # plotting + SHAP
|
|
95
|
+
pip install nestkit[dev] # testing + linting
|
|
96
|
+
pip install nestkit[docs] # Sphinx documentation
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Quick Start
|
|
100
|
+
|
|
101
|
+
### Classification
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from sklearn.datasets import load_breast_cancer
|
|
105
|
+
from sklearn.ensemble import RandomForestClassifier
|
|
106
|
+
from nestkit import NestedCVClassifier
|
|
107
|
+
|
|
108
|
+
X, y = load_breast_cancer(return_X_y=True)
|
|
109
|
+
|
|
110
|
+
ncv = NestedCVClassifier(
|
|
111
|
+
estimator=RandomForestClassifier(random_state=42),
|
|
112
|
+
param_grid={"n_estimators": [50, 100], "max_depth": [3, 5, 10]},
|
|
113
|
+
outer_cv=5,
|
|
114
|
+
inner_cv=3,
|
|
115
|
+
scoring="accuracy",
|
|
116
|
+
random_state=42,
|
|
117
|
+
)
|
|
118
|
+
ncv.fit(X, y)
|
|
119
|
+
|
|
120
|
+
results = ncv.results_
|
|
121
|
+
print(results.summary_default_)
|
|
122
|
+
print(results.best_params_per_fold_)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
With calibration and threshold optimization:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
ncv = NestedCVClassifier(
|
|
129
|
+
estimator=RandomForestClassifier(random_state=42),
|
|
130
|
+
param_grid={"n_estimators": [50, 100], "max_depth": [3, 5]},
|
|
131
|
+
outer_cv=5,
|
|
132
|
+
inner_cv=3,
|
|
133
|
+
calibration_method="isotonic",
|
|
134
|
+
threshold_strategy="pooled",
|
|
135
|
+
threshold_criterion="youden",
|
|
136
|
+
random_state=42,
|
|
137
|
+
)
|
|
138
|
+
ncv.fit(X, y)
|
|
139
|
+
print(ncv.results_.threshold_comparison())
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Regression
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from sklearn.datasets import load_diabetes
|
|
146
|
+
from sklearn.linear_model import Ridge
|
|
147
|
+
from nestkit import NestedCVRegressor
|
|
148
|
+
|
|
149
|
+
X, y = load_diabetes(return_X_y=True)
|
|
150
|
+
|
|
151
|
+
ncv = NestedCVRegressor(
|
|
152
|
+
estimator=Ridge(),
|
|
153
|
+
param_grid={"alpha": [0.01, 0.1, 1.0, 10.0]},
|
|
154
|
+
outer_cv=5,
|
|
155
|
+
inner_cv=3,
|
|
156
|
+
prediction_intervals=True,
|
|
157
|
+
random_state=42,
|
|
158
|
+
)
|
|
159
|
+
ncv.fit(X, y)
|
|
160
|
+
|
|
161
|
+
results = ncv.results_
|
|
162
|
+
print(results.summary_default_)
|
|
163
|
+
print(f"PI coverage: {results.prediction_interval_coverage_['mean']:.3f}")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Architecture
|
|
167
|
+
|
|
168
|
+
nestkit's nested CV procedure executes four phases per outer fold:
|
|
169
|
+
|
|
170
|
+
1. **Inner CV search** - hyperparameter tuning via `GridSearchCV` or `RandomizedSearchCV` on the outer training set
|
|
171
|
+
2. **Post-inner processing** - probability calibration (classification) or residual collection for prediction intervals (regression)
|
|
172
|
+
3. **Refit** - the best hyperparameters are used to refit the estimator on the full outer training set
|
|
173
|
+
4. **Outer evaluation** - the refitted model is scored on the held-out outer test fold
|
|
174
|
+
|
|
175
|
+
**Class hierarchy:**
|
|
176
|
+
|
|
177
|
+
| Class | Purpose |
|
|
178
|
+
|-------|---------|
|
|
179
|
+
| `NestedCVClassifier` | Classification with calibration + thresholding |
|
|
180
|
+
| `NestedCVRegressor` | Regression with prediction intervals |
|
|
181
|
+
| `ClassifierResults` / `RegressorResults` | Rich result containers |
|
|
182
|
+
| `NestedCVComparator` | Statistical model comparison |
|
|
183
|
+
| `FeatureImportanceAggregator` | Cross-fold importance analysis |
|
|
184
|
+
| `HyperparameterStability` | Selection consistency diagnostics |
|
|
185
|
+
| `PostHocCalibrator` | Standalone probability calibration |
|
|
186
|
+
| `InnerCVReport` | Inner CV analysis and reporting |
|
|
187
|
+
|
|
188
|
+
## Documentation
|
|
189
|
+
|
|
190
|
+
Full documentation is available at the [nestkit documentation site](https://nestkit.readthedocs.io/).
|
|
191
|
+
|
|
192
|
+
## Citation
|
|
193
|
+
|
|
194
|
+
If you use nestkit in your research, please cite:
|
|
195
|
+
|
|
196
|
+
```bibtex
|
|
197
|
+
@software{rocchi2026nestkit,
|
|
198
|
+
author = {Rocchi, Ettore},
|
|
199
|
+
title = {nestkit: A Nested Cross-Validation Toolkit for Scikit-Learn},
|
|
200
|
+
year = {2026},
|
|
201
|
+
url = {https://github.com/ettorerocchi/nestkit},
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## License
|
|
206
|
+
|
|
207
|
+
MIT - see [LICENSE](LICENSE) for details.
|
nestkit-0.1.0/README.md
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/_static/nestkit_logo.png" alt="nestkit" width="300">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<em>A nested cross-validation toolkit for scikit-learn</em>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://pypi.org/project/nestkit/"><img src="https://img.shields.io/pypi/v/nestkit" alt="PyPI"></a>
|
|
11
|
+
<a href="https://pypi.org/project/nestkit/"><img src="https://img.shields.io/pypi/pyversions/nestkit" alt="Python"></a>
|
|
12
|
+
<a href="https://github.com/ettorerocchi/nestkit/blob/main/LICENSE"><img src="https://img.shields.io/github/license/ettorerocchi/nestkit" alt="License"></a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Motivation
|
|
18
|
+
|
|
19
|
+
Standard cross-validation conflates model selection with performance estimation, producing optimistically biased scores. When the same data that guides hyperparameter tuning is also used to report performance, the resulting estimates no longer reflect true generalization ability - a subtle but pervasive form of data leakage.
|
|
20
|
+
|
|
21
|
+
**Nested cross-validation** (nested CV) addresses this by separating the two concerns into an inner loop for hyperparameter search and an outer loop for unbiased evaluation. While conceptually simple, implementing nested CV correctly - with proper calibration, threshold optimization, and statistical comparison - requires careful engineering that is tedious and error-prone to write from scratch.
|
|
22
|
+
|
|
23
|
+
**nestkit** provides a scikit-learn-compatible implementation that handles the full pipeline: nested CV with integrated probability calibration, decision-threshold optimization, statistical model comparison, hyperparameter stability diagnostics, feature importance aggregation, and visualizations - all through a familiar `fit`/`predict` API.
|
|
24
|
+
|
|
25
|
+
## Key Features
|
|
26
|
+
|
|
27
|
+
- **Nested cross-validation** for classification and regression with full scikit-learn API compatibility
|
|
28
|
+
- **Post-hoc probability calibration** - Platt scaling, isotonic regression, beta calibration, and Venn-ABERS prediction
|
|
29
|
+
- **Threshold optimization** - Youden's J, F-beta, cost-sensitive, balanced accuracy, and precision-at-recall criteria with pooled or fold-specific strategies
|
|
30
|
+
- **Statistical model comparison** - Nadeau-Bengio corrected t-test, Bayesian correlated t-test with ROPE, and Holm-Bonferroni multi-model correction
|
|
31
|
+
- **Hyperparameter stability diagnostics** - selection frequency analysis, pairwise Jaccard similarity
|
|
32
|
+
- **Feature importance aggregation** - cross-fold importance with Nogueira stability index and consensus feature selection
|
|
33
|
+
- **Callback system** - progress tracking, logging, checkpointing, and custom hooks
|
|
34
|
+
- **25+ plotting functions** - ROC curves, confusion matrices, calibration diagrams, threshold sensitivity, critical difference diagrams, and more
|
|
35
|
+
- **Residual-based prediction intervals** for regression tasks
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install nestkit
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Optional dependency groups:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install nestkit[plotting] # matplotlib + seaborn
|
|
47
|
+
pip install nestkit[full] # plotting + SHAP
|
|
48
|
+
pip install nestkit[dev] # testing + linting
|
|
49
|
+
pip install nestkit[docs] # Sphinx documentation
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
### Classification
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from sklearn.datasets import load_breast_cancer
|
|
58
|
+
from sklearn.ensemble import RandomForestClassifier
|
|
59
|
+
from nestkit import NestedCVClassifier
|
|
60
|
+
|
|
61
|
+
X, y = load_breast_cancer(return_X_y=True)
|
|
62
|
+
|
|
63
|
+
ncv = NestedCVClassifier(
|
|
64
|
+
estimator=RandomForestClassifier(random_state=42),
|
|
65
|
+
param_grid={"n_estimators": [50, 100], "max_depth": [3, 5, 10]},
|
|
66
|
+
outer_cv=5,
|
|
67
|
+
inner_cv=3,
|
|
68
|
+
scoring="accuracy",
|
|
69
|
+
random_state=42,
|
|
70
|
+
)
|
|
71
|
+
ncv.fit(X, y)
|
|
72
|
+
|
|
73
|
+
results = ncv.results_
|
|
74
|
+
print(results.summary_default_)
|
|
75
|
+
print(results.best_params_per_fold_)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
With calibration and threshold optimization:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
ncv = NestedCVClassifier(
|
|
82
|
+
estimator=RandomForestClassifier(random_state=42),
|
|
83
|
+
param_grid={"n_estimators": [50, 100], "max_depth": [3, 5]},
|
|
84
|
+
outer_cv=5,
|
|
85
|
+
inner_cv=3,
|
|
86
|
+
calibration_method="isotonic",
|
|
87
|
+
threshold_strategy="pooled",
|
|
88
|
+
threshold_criterion="youden",
|
|
89
|
+
random_state=42,
|
|
90
|
+
)
|
|
91
|
+
ncv.fit(X, y)
|
|
92
|
+
print(ncv.results_.threshold_comparison())
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Regression
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from sklearn.datasets import load_diabetes
|
|
99
|
+
from sklearn.linear_model import Ridge
|
|
100
|
+
from nestkit import NestedCVRegressor
|
|
101
|
+
|
|
102
|
+
X, y = load_diabetes(return_X_y=True)
|
|
103
|
+
|
|
104
|
+
ncv = NestedCVRegressor(
|
|
105
|
+
estimator=Ridge(),
|
|
106
|
+
param_grid={"alpha": [0.01, 0.1, 1.0, 10.0]},
|
|
107
|
+
outer_cv=5,
|
|
108
|
+
inner_cv=3,
|
|
109
|
+
prediction_intervals=True,
|
|
110
|
+
random_state=42,
|
|
111
|
+
)
|
|
112
|
+
ncv.fit(X, y)
|
|
113
|
+
|
|
114
|
+
results = ncv.results_
|
|
115
|
+
print(results.summary_default_)
|
|
116
|
+
print(f"PI coverage: {results.prediction_interval_coverage_['mean']:.3f}")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Architecture
|
|
120
|
+
|
|
121
|
+
nestkit's nested CV procedure executes four phases per outer fold:
|
|
122
|
+
|
|
123
|
+
1. **Inner CV search** - hyperparameter tuning via `GridSearchCV` or `RandomizedSearchCV` on the outer training set
|
|
124
|
+
2. **Post-inner processing** - probability calibration (classification) or residual collection for prediction intervals (regression)
|
|
125
|
+
3. **Refit** - the best hyperparameters are used to refit the estimator on the full outer training set
|
|
126
|
+
4. **Outer evaluation** - the refitted model is scored on the held-out outer test fold
|
|
127
|
+
|
|
128
|
+
**Class hierarchy:**
|
|
129
|
+
|
|
130
|
+
| Class | Purpose |
|
|
131
|
+
|-------|---------|
|
|
132
|
+
| `NestedCVClassifier` | Classification with calibration + thresholding |
|
|
133
|
+
| `NestedCVRegressor` | Regression with prediction intervals |
|
|
134
|
+
| `ClassifierResults` / `RegressorResults` | Rich result containers |
|
|
135
|
+
| `NestedCVComparator` | Statistical model comparison |
|
|
136
|
+
| `FeatureImportanceAggregator` | Cross-fold importance analysis |
|
|
137
|
+
| `HyperparameterStability` | Selection consistency diagnostics |
|
|
138
|
+
| `PostHocCalibrator` | Standalone probability calibration |
|
|
139
|
+
| `InnerCVReport` | Inner CV analysis and reporting |
|
|
140
|
+
|
|
141
|
+
## Documentation
|
|
142
|
+
|
|
143
|
+
Full documentation is available at the [nestkit documentation site](https://nestkit.readthedocs.io/).
|
|
144
|
+
|
|
145
|
+
## Citation
|
|
146
|
+
|
|
147
|
+
If you use nestkit in your research, please cite:
|
|
148
|
+
|
|
149
|
+
```bibtex
|
|
150
|
+
@software{rocchi2026nestkit,
|
|
151
|
+
author = {Rocchi, Ettore},
|
|
152
|
+
title = {nestkit: A Nested Cross-Validation Toolkit for Scikit-Learn},
|
|
153
|
+
year = {2026},
|
|
154
|
+
url = {https://github.com/ettorerocchi/nestkit},
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## License
|
|
159
|
+
|
|
160
|
+
MIT - see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "nestkit"
|
|
7
|
+
description = "Nested cross-validation toolkit with optional probability calibration, threshold optimization, and comprehensive diagnostics"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
license = {text = "MIT"}
|
|
10
|
+
authors = [{name = "Ettore Rocchi"}]
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
dynamic = ["version", "dependencies"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Science/Research",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.optional-dependencies]
|
|
26
|
+
plotting = ["matplotlib>=3.5", "seaborn>=0.12"]
|
|
27
|
+
full = ["matplotlib>=3.5", "seaborn>=0.12", "shap>=0.42"]
|
|
28
|
+
dev = [
|
|
29
|
+
"pytest>=7",
|
|
30
|
+
"pytest-cov",
|
|
31
|
+
"hypothesis>=6.0",
|
|
32
|
+
"ruff",
|
|
33
|
+
"pre-commit",
|
|
34
|
+
]
|
|
35
|
+
docs = [
|
|
36
|
+
"sphinx>=7.0",
|
|
37
|
+
"pydata-sphinx-theme>=0.14",
|
|
38
|
+
"sphinx-copybutton",
|
|
39
|
+
"myst-parser>=2.0",
|
|
40
|
+
"numpydoc",
|
|
41
|
+
"nbsphinx",
|
|
42
|
+
"ipykernel",
|
|
43
|
+
"sphinx-design",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[tool.setuptools.dynamic]
|
|
47
|
+
version = {attr = "nestkit.__version__"}
|
|
48
|
+
dependencies = {file = "requirements.txt"}
|
|
49
|
+
|
|
50
|
+
[tool.setuptools.packages.find]
|
|
51
|
+
where = ["src"]
|
|
52
|
+
|
|
53
|
+
[tool.ruff]
|
|
54
|
+
target-version = "py310"
|
|
55
|
+
line-length = 99
|
|
56
|
+
src = ["src", "tests"]
|
|
57
|
+
|
|
58
|
+
[tool.ruff.lint]
|
|
59
|
+
select = [
|
|
60
|
+
"E", # pycodestyle errors
|
|
61
|
+
"W", # pycodestyle warnings
|
|
62
|
+
"F", # pyflakes
|
|
63
|
+
"I", # isort
|
|
64
|
+
"UP", # pyupgrade
|
|
65
|
+
"B", # flake8-bugbear
|
|
66
|
+
"SIM", # flake8-simplify
|
|
67
|
+
"RUF", # ruff-specific
|
|
68
|
+
]
|
|
69
|
+
ignore = [
|
|
70
|
+
"E501", # line too long (handled by formatter)
|
|
71
|
+
"B905", # zip strict
|
|
72
|
+
"SIM108", # ternary operator
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
[tool.ruff.lint.isort]
|
|
76
|
+
known-first-party = ["nestkit"]
|
|
77
|
+
|
|
78
|
+
[tool.pytest.ini_options]
|
|
79
|
+
testpaths = ["tests"]
|
|
80
|
+
addopts = "-ra -q"
|
nestkit-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""nestkit - A rigorous nested cross-validation toolkit for scikit-learn.
|
|
2
|
+
|
|
3
|
+
Core estimators
|
|
4
|
+
---------------
|
|
5
|
+
- :class:`NestedCVClassifier` - Classification with optional calibration
|
|
6
|
+
and threshold optimization.
|
|
7
|
+
- :class:`NestedCVRegressor` - Regression with optional residual-based
|
|
8
|
+
prediction intervals.
|
|
9
|
+
|
|
10
|
+
Results
|
|
11
|
+
-------
|
|
12
|
+
- :class:`ClassifierResults` / :class:`RegressorResults` - Rich result
|
|
13
|
+
containers with summary statistics, export methods, and plots.
|
|
14
|
+
|
|
15
|
+
Submodules
|
|
16
|
+
----------
|
|
17
|
+
- :mod:`nestkit.calibration` - Post-hoc probability calibration and
|
|
18
|
+
calibration diagnostics.
|
|
19
|
+
- :mod:`nestkit.callbacks` - Fold-level monitoring (progress, logging,
|
|
20
|
+
checkpointing).
|
|
21
|
+
- :mod:`nestkit.comparison` - Statistical model comparison.
|
|
22
|
+
- :mod:`nestkit.diagnostics` - Hyperparameter stability analysis.
|
|
23
|
+
- :mod:`nestkit.importance` - Cross-fold feature importance aggregation.
|
|
24
|
+
- :mod:`nestkit.inner` - Inner CV tuning reports.
|
|
25
|
+
- :mod:`nestkit.plotting` - 25+ plotting functions for nested CV results.
|
|
26
|
+
- :mod:`nestkit.thresholding` - Decision-threshold optimization criteria.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
from __future__ import annotations
|
|
30
|
+
|
|
31
|
+
import logging
|
|
32
|
+
|
|
33
|
+
from nestkit.classifier import NestedCVClassifier
|
|
34
|
+
from nestkit.regressor import NestedCVRegressor
|
|
35
|
+
from nestkit.results.classifier_results import ClassifierResults
|
|
36
|
+
from nestkit.results.regressor_results import RegressorResults
|
|
37
|
+
|
|
38
|
+
__version__ = "0.1.0"
|
|
39
|
+
|
|
40
|
+
logger = logging.getLogger("nestkit")
|
|
41
|
+
logger.addHandler(logging.NullHandler())
|
|
42
|
+
|
|
43
|
+
__all__ = [
|
|
44
|
+
"ClassifierResults",
|
|
45
|
+
"NestedCVClassifier",
|
|
46
|
+
"NestedCVRegressor",
|
|
47
|
+
"RegressorResults",
|
|
48
|
+
"__version__",
|
|
49
|
+
]
|