| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556 |
- """Data preparation, constrained MAP fitting, prediction, and fit diagnostics."""
- import numpy as np
- from .core import (
- load_xy,
- make_trimmed_dataset,
- sigmoid,
- softplus,
- theta_max,
- unpack,
- dE_full,
- P_with,
- make_priors,
- init_phi,
- neg_post,
- fit_bayes,
- x_at_p,
- slope_at_x,
- )
- def goodness_of_fit(X, y, theta_hat, threshold=0.5):
- """Return conditional Bernoulli fit measures for a fitted CB model."""
- X = np.asarray(X, float).ravel()
- y = np.asarray(y, int).ravel()
- p = np.clip(np.asarray(P_with(theta_hat, X), float), 1e-12, 1.0 - 1e-12)
- pred = (p >= threshold).astype(int)
- log_loss = -float(np.mean(y * np.log(p) + (1 - y) * np.log1p(-p)))
- return {
- "n": int(y.size),
- "events": int(y.sum()),
- "log_loss": log_loss,
- "brier_score": float(np.mean((y - p) ** 2)),
- "accuracy": float(np.mean(pred == y)),
- "sensitivity": float(np.mean(pred[y == 1] == 1)) if np.any(y == 1) else np.nan,
- "specificity": float(np.mean(pred[y == 0] == 0)) if np.any(y == 0) else np.nan,
- }
- def fit_full_trim(percentile=95, **fit_kwargs):
- """Load, trim, and fit the FULL and TRIM constrained Bayesian models."""
- X, y = load_xy(perc=percentile)
- ds = make_trimmed_dataset(X, y)
- result = {"data": ds}
- for key, x_key, y_key in (
- ("FULL", "X_orig", "y_orig"),
- ("TRIM", "X_trim", "y_trim"),
- ):
- theta, optimizer = fit_bayes(ds[x_key], ds[y_key], **fit_kwargs)
- result[key] = {
- "theta": theta,
- "optimizer": optimizer,
- "gof": goodness_of_fit(ds[x_key], ds[y_key], theta),
- }
- return result
|