bci-mvp / src /bootstrap_ci.py
WilliamK112
feat: add bootstrap confidence-interval evaluation for metric uncertainty
f7e869b
Raw
History Blame Contribute Delete
2.07 kB
"""
Bootstrap confidence intervals for key metrics (accuracy, f1, auc) on test predictions.
"""
from pathlib import Path
import json
import numpy as np
import joblib
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, f1_score, roc_auc_score
from src.preprocess import build_dataset_from_folder
def ci(arr, alpha=0.95):
lo = (1 - alpha) / 2
hi = 1 - lo
return float(np.quantile(arr, lo)), float(np.quantile(arr, hi))
def main(model_path='outputs/model_rf_real.joblib', n_boot=300, seed=42):
X0, y0 = build_dataset_from_folder('data/relaxed', label=0)
X1, y1 = build_dataset_from_folder('data/focused', label=1)
X = np.vstack([X0, X1])
y = np.concatenate([y0, y1])
_, X_test, _, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)
mp = Path(model_path)
if not mp.exists():
raise FileNotFoundError(f'Model not found: {mp}')
clf = joblib.load(mp)
pred = clf.predict(X_test)
proba = clf.predict_proba(X_test)[:, 1]
rng = np.random.default_rng(seed)
n = len(y_test)
accs, f1s, aucs = [], [], []
for _ in range(n_boot):
idx = rng.integers(0, n, size=n)
yt = y_test[idx]
yp = pred[idx]
pp = proba[idx]
accs.append(accuracy_score(yt, yp))
f1s.append(f1_score(yt, yp))
try:
aucs.append(roc_auc_score(yt, pp))
except Exception:
pass
out = {
'n_bootstrap': int(n_boot),
'accuracy_mean': float(np.mean(accs)),
'accuracy_ci95': ci(np.array(accs)),
'f1_mean': float(np.mean(f1s)),
'f1_ci95': ci(np.array(f1s)),
'auc_mean': float(np.mean(aucs)) if aucs else None,
'auc_ci95': ci(np.array(aucs)) if aucs else None,
}
od = Path('outputs'); od.mkdir(exist_ok=True)
fp = od / 'bootstrap_ci_results.json'
fp.write_text(json.dumps(out, indent=2), encoding='utf-8')
print(json.dumps(out, indent=2))
print(f'Saved {fp}')
if __name__ == '__main__':
main()