API Reference¶
Complete API documentation for all nonconform modules and classes.
Start Here¶
If you are looking for task-oriented call sequences, start with Common Workflows.
For the v1 public compatibility contract, see API Stability.
Detector¶
nonconform.detector ¶
Core conformal anomaly detector implementation.
This module provides the main ConformalDetector class that wraps any anomaly detector with conformal inference for valid p-values and FDR control.
Classes:
| Name | Description |
|---|---|
BaseConformalDetector |
Abstract base class for conformal detectors. |
ConformalDetector |
Main conformal anomaly detector with optional weighting. |
BaseConformalDetector ¶
Bases: ABC
Abstract base class for all conformal anomaly detectors.
Defines the core interface that all conformal anomaly detection implementations must provide. Conformal detectors support either an integrated or detached calibration workflow:
- Integrated calibration:
fit()trains detector(s) and computes calibration scores - Detached calibration: train detector externally, then call
calibrate()on a separate calibration dataset - Inference Phase:
compute_p_values()converts new data scores to valid p-values, orselect()for the combined p-value + FDR-control workflow
Subclasses must implement both abstract methods.
Note
This is an abstract class and cannot be instantiated directly.
Use ConformalDetector for the main implementation.
fit
abstractmethod
¶
fit(
x: DataFrame | ndarray,
y: ndarray | None = None,
*,
n_jobs: int | None = None,
) -> Self
Fit the detector model(s) and compute calibration scores.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | ndarray
|
The dataset used for fitting the model(s) and determining calibration scores. |
required |
y
|
ndarray | None
|
Ignored. Present for sklearn API compatibility. |
None
|
n_jobs
|
int | None
|
Optional strategy-specific parallelism hint.
Currently used by strategies that expose an |
None
|
Returns:
| Type | Description |
|---|---|
Self
|
The fitted detector instance. |
Source code in nonconform/detector.py
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | |
calibrate ¶
calibrate(
x: DataFrame | ndarray, y: ndarray | None = None
) -> Self
Calibrate a pre-fitted detector on separate calibration data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | ndarray
|
Dataset used only to compute calibration scores. |
required |
y
|
ndarray | None
|
Ignored. Present for sklearn API compatibility. |
None
|
Returns:
| Type | Description |
|---|---|
Self
|
The calibrated detector instance. |
Source code in nonconform/detector.py
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | |
compute_p_values
abstractmethod
¶
compute_p_values(
x: DataFrame | Series | ndarray,
*,
refit_weights: bool = True,
) -> np.ndarray | pd.Series
Return conformal p-values for new data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | Series | ndarray
|
New data instances for anomaly estimation. |
required |
refit_weights
|
bool
|
Whether to refit the weight estimator for this batch in weighted mode. Ignored in standard mode. |
True
|
Returns:
| Type | Description |
|---|---|
ndarray | Series
|
P-values as ndarray for numpy input, or pandas Series for pandas input. |
Source code in nonconform/detector.py
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | |
score_samples
abstractmethod
¶
score_samples(
x: DataFrame | Series | ndarray,
*,
refit_weights: bool = True,
) -> np.ndarray | pd.Series
Return aggregated raw anomaly scores for new data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | Series | ndarray
|
New data instances for anomaly estimation. |
required |
refit_weights
|
bool
|
Whether to refit the weight estimator for this batch in weighted mode. Ignored in standard mode. |
True
|
Returns:
| Type | Description |
|---|---|
ndarray | Series
|
Raw scores as ndarray for numpy input, or pandas Series for pandas input. |
Source code in nonconform/detector.py
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | |
ConformalDetector ¶
ConformalDetector(
detector: Any,
strategy: BaseStrategy,
estimation: BaseEstimation | None = None,
weight_estimator: BaseWeightEstimator | None = None,
aggregation: str = "median",
score_polarity: ScorePolarity
| Literal[
"auto", "higher_is_anomalous", "higher_is_normal"
]
| None = None,
seed: int | None = None,
verbose: bool = False,
verify_prepared_batch_content: bool = True,
)
Bases: BaseConformalDetector
Unified conformal anomaly detector with optional covariate shift handling.
Provides distribution-free anomaly detection with valid p-values and False Discovery Rate (FDR) control by wrapping any anomaly detector with conformal inference. Supports PyOD detectors, sklearn-compatible detectors, and custom detectors implementing the AnomalyDetector protocol.
When no weight estimator is provided (standard conformal prediction): - Uses classical conformal inference for exchangeable data - Provides optimal performance and memory usage - Suitable when training and test data come from the same distribution
When a weight estimator is provided (weighted conformal prediction): - Handles distribution shift between calibration and test data - Estimates importance weights to maintain statistical validity - Slightly higher computational cost but robust to covariate shift
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
detector
|
Any
|
Anomaly detector (PyOD, sklearn-compatible, or custom). |
required |
strategy
|
BaseStrategy
|
The conformal strategy for fitting and calibration. |
required |
estimation
|
BaseEstimation | None
|
P-value estimation strategy. Defaults to Empirical(). |
None
|
weight_estimator
|
BaseWeightEstimator | None
|
Weight estimator for covariate shift. Defaults to None. |
None
|
aggregation
|
str
|
Method for aggregating scores from multiple models. Defaults to "median". |
'median'
|
score_polarity
|
ScorePolarity | Literal['auto', 'higher_is_anomalous', 'higher_is_normal'] | None
|
Score direction convention. Use |
None
|
seed
|
int | None
|
Random seed for reproducibility. Defaults to None. |
None
|
verbose
|
bool
|
If True, displays progress bars during prediction. Defaults to False. |
False
|
verify_prepared_batch_content
|
bool
|
If True (default), weighted reuse mode
( |
True
|
Attributes:
| Name | Type | Description |
|---|---|---|
detector |
The underlying anomaly detection model. |
|
strategy |
The calibration strategy for computing p-values. |
|
weight_estimator |
Optional weight estimator for handling covariate shift. |
|
aggregation |
Method for combining scores from multiple models. |
|
score_polarity |
ScorePolarity
|
Resolved score polarity used internally. |
seed |
ScorePolarity
|
Random seed for reproducible results. |
verbose |
ScorePolarity
|
Whether to display progress bars. |
_detector_set |
ScorePolarity
|
List of trained detector models (populated after fit). |
_calibration_set |
ScorePolarity
|
Calibration scores (populated after fit). |
Examples:
Standard conformal prediction — FDR-controlled selection in one call:
from pyod.models.iforest import IForest
from nonconform import ConformalDetector, Split
detector = ConformalDetector(
detector=IForest(), strategy=Split(n_calib=0.2), seed=42
)
detector.fit(X_train)
mask = detector.select(X_test, alpha=0.05)
Access raw p-values when needed:
detector.fit(X_train)
p_values = detector.compute_p_values(X_test)
Weighted conformal prediction:
from nonconform import logistic_weight_estimator
detector = ConformalDetector(
detector=IForest(),
strategy=Split(n_calib=0.2),
weight_estimator=logistic_weight_estimator(),
seed=42,
)
detector.fit(X_train)
mask = detector.select(X_test, alpha=0.05)
Detached calibration with a pre-trained model (Split strategy):
base_detector.fit(X_fit)
detector = ConformalDetector(
detector=base_detector, strategy=Split(n_calib=0.2)
)
detector.calibrate(X_calib)
p_values = detector.compute_p_values(X_test)
Note
Strict inductive conformal/FDR workflows require a fixed training-only score map at inference time. PyOD detectors known to violate this are: CD, COF, COPOD, ECOD, LMDD, LOCI, RGraph, SOD, SOS.
Source code in nonconform/detector.py
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | |
detector_set
property
¶
detector_set: list[AnomalyDetector]
Returns a copy of the list of trained detector models.
calibration_samples
property
¶
calibration_samples: ndarray
Returns a copy of the calibration samples (weighted mode only).
last_result
property
¶
last_result: ConformalResult | None
Return the most recent conformal result snapshot.
score_polarity
property
¶
score_polarity: ScorePolarity
Returns the resolved score polarity convention.
get_params ¶
get_params(deep: bool = True) -> dict[str, Any]
Return estimator parameters following sklearn conventions.
Notes
deep=Falsereturns constructor-facing parameters used for sklearn clone compatibility.deep=Truealso includes nestedcomponent__paramentries read from the current runtime components (effective/internal state), which may differ from originally passed constructor objects after adaptation/normalization.
Source code in nonconform/detector.py
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | |
set_params ¶
set_params(**params: Any) -> Self
Set estimator parameters following sklearn conventions.
Source code in nonconform/detector.py
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | |
fit ¶
fit(
x: DataFrame | ndarray,
y: ndarray | None = None,
*,
n_jobs: int | None = None,
) -> Self
Fit detector model(s) and compute calibration scores.
Uses the specified strategy to train the base detector(s) and calculate non-conformity scores on the calibration set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | ndarray
|
The dataset used for fitting and calibration. |
required |
y
|
ndarray | None
|
Ignored. Present for sklearn API compatibility. |
None
|
n_jobs
|
int | None
|
Optional strategy-specific parallelism hint. Supported by
strategies whose |
None
|
Returns:
| Type | Description |
|---|---|
Self
|
The fitted detector instance (for method chaining). |
Source code in nonconform/detector.py
502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 | |
calibrate ¶
calibrate(
x: DataFrame | ndarray, y: ndarray | None = None
) -> Self
Calibrate a pre-fitted detector on separate calibration data.
This detached workflow is currently supported only for Split strategy,
where a single pre-fitted model is calibrated on a dedicated dataset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | ndarray
|
Calibration dataset used to compute calibration scores. |
required |
y
|
ndarray | None
|
Ignored. Present for sklearn API compatibility. |
None
|
Returns:
| Type | Description |
|---|---|
Self
|
The calibrated detector instance (for method chaining). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If strategy is not |
NotFittedError
|
If the base detector appears unfitted. |
Source code in nonconform/detector.py
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 | |
select ¶
select(
x: DataFrame | Series | ndarray,
*,
alpha: float = 0.05,
pruning: Pruning = Pruning.DETERMINISTIC,
seed: int | None = None,
refit_weights: bool = True,
) -> np.ndarray | pd.Series
Compute p-values and apply FDR-controlled selection in one step.
This is the recommended single-call workflow for most use cases. It
combines compute_p_values() and the appropriate selection procedure
(BH-style FDR selection for standard mode, weighted conformalized
selection for weighted mode) into one method, eliminating the need to
access last_result manually.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | Series | ndarray
|
New data instances for anomaly estimation. |
required |
alpha
|
float
|
Target FDR level in |
0.05
|
pruning
|
Pruning
|
Pruning strategy for weighted FDR control. Ignored in
standard (unweighted) mode. Defaults to
|
DETERMINISTIC
|
seed
|
int | None
|
Optional random seed for weighted randomized pruning modes.
When |
None
|
refit_weights
|
bool
|
Whether to refit the weight estimator for this batch in weighted mode. Ignored in standard mode. Defaults to True. |
True
|
Returns:
| Type | Description |
|---|---|
ndarray | Series
|
Boolean selection mask of shape |
ndarray | Series
|
the FDR-controlled anomaly discoveries. Returns a pandas Series when |
ndarray | Series
|
the input is a DataFrame or Series. |
Examples:
Standard workflow (no weight estimator):
detector.fit(X_train)
mask = detector.select(X_test, alpha=0.05)
print(f"Discoveries: {mask.sum()}")
Weighted workflow:
detector = ConformalDetector(
detector=IForest(),
strategy=Split(n_calib=0.2),
weight_estimator=logistic_weight_estimator(),
)
detector.fit(X_train)
mask = detector.select(
X_test,
alpha=0.1,
pruning=Pruning.HETEROGENEOUS,
seed=42,
)
Source code in nonconform/detector.py
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 | |
prepare_weights_for ¶
prepare_weights_for(x: DataFrame | ndarray) -> Self
Prepare weighted conformal state for a specific test batch.
In weighted mode, this fits the weight estimator for the supplied batch without producing predictions. Use this for explicit state transitions in exploratory workflows.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | ndarray
|
Test batch for which weights should be prepared. |
required |
Returns:
| Type | Description |
|---|---|
Self
|
The fitted detector instance (for method chaining). |
Raises:
| Type | Description |
|---|---|
NotFittedError
|
If fit() has not been called. |
RuntimeError
|
If weighted mode is disabled. |
Source code in nonconform/detector.py
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 | |
score_samples ¶
score_samples(
x: DataFrame | Series | ndarray,
*,
refit_weights: bool = True,
) -> np.ndarray | pd.Series
Return aggregated raw anomaly scores for new data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | Series | ndarray
|
New data instances for anomaly estimation. |
required |
refit_weights
|
bool
|
Whether to refit the weight estimator for this batch in weighted mode. Defaults to True. |
True
|
Returns:
| Type | Description |
|---|---|
ndarray | Series
|
Aggregated raw anomaly scores. |
Source code in nonconform/detector.py
803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 | |
compute_p_values ¶
compute_p_values(
x: DataFrame | Series | ndarray,
*,
refit_weights: bool = True,
) -> np.ndarray | pd.Series
Return conformal p-values for new data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | Series | ndarray
|
New data instances for anomaly estimation. |
required |
refit_weights
|
bool
|
Whether to refit the weight estimator for this batch in weighted mode. Defaults to True. |
True
|
Returns:
| Type | Description |
|---|---|
ndarray | Series
|
Conformal p-values. |
Source code in nonconform/detector.py
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 | |
Resampling Strategies¶
nonconform.resampling ¶
Calibration strategies for conformal anomaly detection.
This module provides various calibration strategies that define how to split data for training and calibration in conformal prediction.
Classes:
| Name | Description |
|---|---|
BaseStrategy |
Abstract base class for calibration strategies. |
Split |
Simple train-test split strategy. |
CrossValidation |
K-fold cross-validation strategy (includes Jackknife factory). |
JackknifeBootstrap |
Jackknife+-after-Bootstrap (JaB+) strategy. |
BaseStrategy ¶
BaseStrategy(mode: ConformalModeInput = 'plus')
Bases: ABC
Abstract base class for anomaly detection calibration strategies.
This class provides a common interface for various calibration strategies applied to anomaly detectors. Subclasses must implement the core calibration logic and define how calibration data is identified and used.
Attributes:
| Name | Type | Description |
|---|---|---|
_mode |
ConformalMode
|
Model retention mode controlling calibration/inference behavior. |
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mode
|
ConformalModeInput
|
Model retention mode ( |
'plus'
|
Source code in nonconform/resampling.py
70 71 72 73 74 75 76 77 78 | |
calibration_ids
abstractmethod
property
¶
calibration_ids: list[int] | None
Indices of data points used for calibration.
fit_calibrate
abstractmethod
¶
fit_calibrate(
x: DataFrame | ndarray,
detector: AnomalyDetector,
seed: int | None = None,
weighted: bool = False,
) -> tuple[list[AnomalyDetector], np.ndarray]
Fits the detector and performs calibration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | ndarray
|
The input data for fitting and calibration. |
required |
detector
|
AnomalyDetector
|
The anomaly detection model to be fitted and calibrated. |
required |
seed
|
int | None
|
Random seed for reproducibility. Defaults to None. |
None
|
weighted
|
bool
|
Whether to use weighted approach. Defaults to False. |
False
|
Returns:
| Type | Description |
|---|---|
tuple[list[AnomalyDetector], ndarray]
|
Tuple of (list of trained detectors, calibration scores array). |
Source code in nonconform/resampling.py
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | |
Split ¶
Split(n_calib: float | int = 0.1)
Bases: BaseStrategy
Split conformal strategy for fast anomaly detection.
Implements the classical split conformal approach by dividing training data into separate fitting and calibration sets.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_calib
|
float | int
|
Size or proportion of data used for calibration. If float, must be between 0.0 and 1.0 (proportion). If int, the absolute number of samples. Defaults to 0.1. |
0.1
|
Examples:
# Use 20% of data for calibration
strategy = Split(n_calib=0.2)
# Use exactly 1000 samples for calibration
strategy = Split(n_calib=1000)
Source code in nonconform/resampling.py
131 132 133 134 | |
calibration_ids
property
¶
calibration_ids: list[int] | None
Indices of calibration samples (None if weighted=False).
fit_calibrate ¶
fit_calibrate(
x: DataFrame | ndarray,
detector: AnomalyDetector,
weighted: bool = False,
seed: int | None = None,
) -> tuple[list[AnomalyDetector], np.ndarray]
Fits detector and generates calibration scores using a data split.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | ndarray
|
The input data. |
required |
detector
|
AnomalyDetector
|
The detector instance to train. |
required |
weighted
|
bool
|
If True, stores calibration sample indices. Defaults to False. |
False
|
seed
|
int | None
|
Random seed for reproducibility. Defaults to None. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[list[AnomalyDetector], ndarray]
|
Tuple of (list with trained detector, calibration scores array). |
Source code in nonconform/resampling.py
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | |
CrossValidation ¶
CrossValidation(
k: int | None = 5,
mode: ConformalModeInput = "plus",
shuffle: bool = True,
)
Bases: BaseStrategy
K-fold cross-validation strategy for conformal anomaly detection.
Splits data into k folds and uses each fold as a calibration set while training on the remaining folds.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
k
|
int | None
|
Number of folds. If None, uses leave-one-out (k=n at fit time). |
5
|
mode
|
ConformalModeInput
|
Model retention mode ( |
'plus'
|
shuffle
|
bool
|
Whether to shuffle data before splitting. Defaults to True. Set to False for deterministic leave-one-out (Jackknife). |
True
|
Examples:
# 5-fold cross-validation
strategy = CrossValidation(k=5)
# Leave-one-out (Jackknife) via factory
strategy = CrossValidation.jackknife()
Source code in nonconform/resampling.py
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | |
jackknife
classmethod
¶
jackknife(
mode: ConformalModeInput = "plus",
) -> CrossValidation
Create Leave-One-Out cross-validation (deterministic, no shuffle).
This factory method creates a Jackknife strategy, which is a special case of k-fold CV where k equals n (the dataset size). Each sample is left out exactly once for calibration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mode
|
ConformalModeInput
|
Model retention mode ( |
'plus'
|
Returns:
| Type | Description |
|---|---|
CrossValidation
|
CrossValidation configured for leave-one-out. |
Examples:
strategy = CrossValidation.jackknife()
detector_list, calib_scores = strategy.fit_calibrate(X, detector)
Source code in nonconform/resampling.py
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | |
fit_calibrate ¶
fit_calibrate(
x: DataFrame | ndarray,
detector: AnomalyDetector,
seed: int | None = None,
weighted: bool = False,
) -> tuple[list[AnomalyDetector], np.ndarray]
Fit and calibrate using k-fold cross-validation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | ndarray
|
Input data matrix. |
required |
detector
|
AnomalyDetector
|
The base anomaly detector. |
required |
seed
|
int | None
|
Random seed for reproducibility. Defaults to None. |
None
|
weighted
|
bool
|
Whether to use weighted calibration. Defaults to False. |
False
|
Returns:
| Type | Description |
|---|---|
tuple[list[AnomalyDetector], ndarray]
|
Tuple of (list of trained detectors, calibration scores array). |
Raises:
| Type | Description |
|---|---|
ValueError
|
If k < 2 or not enough samples for specified k. |
Source code in nonconform/resampling.py
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | |
JackknifeBootstrap ¶
JackknifeBootstrap(
n_bootstraps: int = 100,
aggregation_method: BootstrapAggregationMethod = "mean",
mode: ConformalModeInput = "plus",
)
Bases: BaseStrategy
Jackknife+-after-Bootstrap (JaB+) conformal anomaly detection.
Implements the JaB+ method which provides predictive inference for ensemble models trained on bootstrap samples. Uses out-of-bag samples for calibration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_bootstraps
|
int
|
Number of bootstrap iterations. Defaults to 100. |
100
|
aggregation_method
|
BootstrapAggregationMethod
|
How to aggregate OOB predictions ("mean" or "median"). Defaults to "mean". |
'mean'
|
mode
|
ConformalModeInput
|
Model retention mode ( |
'plus'
|
References
Jin, Ying, and Emmanuel J. Candès. "Selection by Prediction with Conformal p-values." Journal of Machine Learning Research 24.244 (2023): 1-41.
Source code in nonconform/resampling.py
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | |
calibration_ids
property
¶
calibration_ids: list[int]
Indices used for calibration (all samples in JaB+).
aggregation_method
property
¶
aggregation_method: BootstrapAggregationMethod
Aggregation method for OOB predictions.
fit_calibrate ¶
fit_calibrate(
x: DataFrame | ndarray,
detector: AnomalyDetector,
seed: int | None = None,
weighted: bool = False,
n_jobs: int | None = None,
) -> tuple[list[AnomalyDetector], np.ndarray]
Fit and calibrate using JaB+ method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
DataFrame | ndarray
|
Input data matrix. |
required |
detector
|
AnomalyDetector
|
The base anomaly detector. |
required |
seed
|
int | None
|
Random seed for reproducibility. Defaults to None. |
None
|
weighted
|
bool
|
Not used in JaB+. Defaults to False. |
False
|
n_jobs
|
int | None
|
Number of parallel jobs. Use -1 for all available cores. Defaults to None (sequential). |
None
|
Returns:
| Type | Description |
|---|---|
tuple[list[AnomalyDetector], ndarray]
|
Tuple of (list of trained detectors, calibration scores array). |
Source code in nonconform/resampling.py
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 | |
P-Value Estimation¶
nonconform.scoring ¶
P-value estimation strategies for conformal prediction.
This module provides strategies for computing p-values from calibration scores.
Classes:
| Name | Description |
|---|---|
BaseEstimation |
Abstract base class for p-value estimation. |
Empirical |
Classical empirical p-value estimation using discrete CDF. |
ConditionalEmpirical |
Conditionally calibrated empirical p-values. |
Probabilistic |
KDE-based probabilistic p-value estimation. |
Kernel ¶
Bases: Enum
Kernel functions for KDE-based p-value computation.
Attributes:
| Name | Type | Description |
|---|---|---|
GAUSSIAN |
Gaussian (normal) kernel. |
|
EXPONENTIAL |
Exponential kernel. |
|
BOX |
Box (uniform) kernel. |
|
TRIANGULAR |
Triangular kernel. |
|
EPANECHNIKOV |
Epanechnikov kernel. |
|
BIWEIGHT |
Biweight (quartic) kernel. |
|
TRIWEIGHT |
Triweight kernel. |
|
TRICUBE |
Tricube kernel. |
|
COSINE |
Cosine kernel. |
BaseEstimation ¶
Bases: ABC
Abstract base for p-value estimation strategies.
compute_p_values
abstractmethod
¶
compute_p_values(
scores: ndarray,
calibration_set: ndarray,
weights: tuple[ndarray, ndarray] | None = None,
) -> np.ndarray
Compute p-values for test scores.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scores
|
ndarray
|
Test instance anomaly scores (1D array). |
required |
calibration_set
|
ndarray
|
Calibration anomaly scores (1D array). |
required |
weights
|
tuple[ndarray, ndarray] | None
|
Optional (w_calib, w_test) tuple for weighted conformal. |
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Array of p-values for each test instance. |
Source code in nonconform/scoring.py
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | |
get_metadata ¶
get_metadata() -> dict[str, Any]
Optional auxiliary data exposed after compute_p_values.
Source code in nonconform/scoring.py
82 83 84 | |
set_seed ¶
set_seed(seed: int | None) -> None
Set random seed for reproducibility.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seed
|
int | None
|
Random seed value or None. |
required |
Source code in nonconform/scoring.py
86 87 88 89 90 91 92 93 | |
Empirical ¶
Empirical(tie_break: TieBreakModeInput = 'classical')
Bases: BaseEstimation
Classical empirical p-value estimation using discrete CDF.
Computes p-values using deterministic tie handling by default. Optionally supports randomized smoothing to eliminate the resolution floor caused by discrete ties (Jin & Candes 2023).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tie_break
|
TieBreakModeInput
|
Tie-breaking strategy ( |
'classical'
|
Examples:
estimation = Empirical() # tie_break="classical" by default
p_values = estimation.compute_p_values(test_scores, calib_scores)
# For randomized smoothing:
estimation = Empirical(tie_break="randomized")
Source code in nonconform/scoring.py
117 118 119 | |
set_seed ¶
set_seed(seed: int | None) -> None
Set random seed for reproducibility.
Source code in nonconform/scoring.py
121 122 123 | |
compute_p_values ¶
compute_p_values(
scores: ndarray,
calibration_set: ndarray,
weights: tuple[ndarray, ndarray] | None = None,
) -> np.ndarray
Compute empirical p-values from calibration set.
Source code in nonconform/scoring.py
125 126 127 128 129 130 131 132 133 134 135 136 | |
ConditionalEmpirical ¶
ConditionalEmpirical(
*,
delta: float = 0.05,
method: str | ConditionalCalibrationMethod = "mc",
tie_break: TieBreakModeInput = "classical",
simes_kden: int = 2,
mc_num_simulations: int = 10000,
)
Bases: Empirical
Conditionally calibrated empirical conformal p-values (CCCPV).
This estimator first computes classical empirical conformal p-values and then applies a finite-sample calibration map:
.. math:: p_j = \frac{1 + \sum_{i=1}^{n_{\text{cal}}}\mathbf{1}[s_i \ge s_j]} {n_{\text{cal}} + 1}, \qquad \tilde p_j = C_{n_{\text{cal}},\delta}(p_j).
Supported calibration maps are "mc", "simes", "dkwm", and
"asymptotic".
References
Bates et al. (2023), Testing for outliers with conformal p-values. Reference implementation: https://github.com/msesia/conditional-conformal-pvalues
Note
Weighted conformal p-values are intentionally not supported in this
first release of ConditionalEmpirical.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
delta
|
float
|
Confidence level used by the conditional calibration map.
Must be in |
0.05
|
method
|
str | ConditionalCalibrationMethod
|
Conditional calibration method. One of
|
'mc'
|
tie_break
|
TieBreakModeInput
|
Tie-breaking strategy used for base empirical p-values
( |
'classical'
|
simes_kden
|
int
|
Denominator used to derive |
2
|
mc_num_simulations
|
int
|
Monte Carlo sample size used to estimate the
finite-sample correction for |
10000
|
Source code in nonconform/scoring.py
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | |
set_seed ¶
set_seed(seed: int | None) -> None
Set random seed for reproducibility.
Source code in nonconform/scoring.py
241 242 243 244 245 | |
compute_p_values ¶
compute_p_values(
scores: ndarray,
calibration_set: ndarray,
weights: tuple[ndarray, ndarray] | None = None,
) -> np.ndarray
Compute conditionally calibrated conformal p-values.
Source code in nonconform/scoring.py
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | |
Probabilistic ¶
Probabilistic(
kernel: Kernel | Sequence[Kernel] = Kernel.GAUSSIAN,
n_trials: int = 100,
cv_folds: int = -1,
)
Bases: BaseEstimation
KDE-based probabilistic p-value estimation with continuous values.
Provides smooth p-values in [0,1] via kernel density estimation. Supports automatic hyperparameter tuning and weighted conformal prediction. In weighted mode, only calibration weights are applied to the KDE; test weights are intentionally not injected into the survival calculation so p-values can reach 0. This avoids the lower bound w_test / (sum_calib_weight + w_test) that the discrete weighted formula would impose.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kernel
|
Kernel | Sequence[Kernel]
|
Kernel function or list (list triggers kernel tuning). Bandwidth is always auto-tuned. Defaults to Kernel.GAUSSIAN. |
GAUSSIAN
|
n_trials
|
int
|
Number of Optuna trials for tuning. Defaults to 100. |
100
|
cv_folds
|
int
|
CV folds for tuning (-1 for leave-one-out). Defaults to -1. |
-1
|
Examples:
# Basic usage
estimation = Probabilistic()
p_values = estimation.compute_p_values(test_scores, calib_scores)
# With custom kernel
estimation = Probabilistic(kernel=Kernel.EPANECHNIKOV)
Source code in nonconform/scoring.py
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 | |
compute_p_values ¶
compute_p_values(
scores: ndarray,
calibration_set: ndarray,
weights: tuple[ndarray, ndarray] | None = None,
) -> np.ndarray
Compute continuous p-values using KDE.
Lazy fitting: tunes and fits KDE on first call or when calibration changes. Note: When weights are provided, this estimator uses only calibration weights to shape the KDE. Test weights are accepted for API parity but do not set a positive lower bound on p-values.
Source code in nonconform/scoring.py
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | |
get_metadata ¶
get_metadata() -> dict[str, Any]
Return KDE metadata after p-value computation.
Source code in nonconform/scoring.py
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 | |
calculate_p_val ¶
calculate_p_val(
scores: ndarray,
calibration_set: ndarray,
tie_break: TieBreakModeInput = "classical",
rng: Generator | None = None,
) -> np.ndarray
Calculate empirical p-values (standalone function).
Uses classical deterministic tie handling by default. Optionally supports randomized smoothing to eliminate the resolution floor caused by discrete ties (Jin & Candes 2023).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scores
|
ndarray
|
Test instance anomaly scores (1D array). |
required |
calibration_set
|
ndarray
|
Calibration anomaly scores (1D array). |
required |
tie_break
|
TieBreakModeInput
|
Tie-breaking strategy for equal scores ( |
'classical'
|
rng
|
Generator | None
|
Optional random number generator for reproducibility. |
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Array of p-values for each test instance. |
Source code in nonconform/scoring.py
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | |
calculate_weighted_p_val ¶
calculate_weighted_p_val(
scores: ndarray,
calibration_set: ndarray,
test_weights: ndarray,
calib_weights: ndarray,
tie_break: TieBreakModeInput = "classical",
rng: Generator | None = None,
) -> np.ndarray
Calculate weighted empirical p-values (standalone function).
Uses classical deterministic tie handling by default. Optionally supports randomized smoothing to eliminate the resolution floor caused by discrete ties (Jin & Candes 2023).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scores
|
ndarray
|
Test instance anomaly scores (1D array). |
required |
calibration_set
|
ndarray
|
Calibration anomaly scores (1D array). |
required |
test_weights
|
ndarray
|
Test instance weights (1D array). |
required |
calib_weights
|
ndarray
|
Calibration weights (1D array). |
required |
tie_break
|
TieBreakModeInput
|
Tie-breaking strategy for equal scores ( |
'classical'
|
rng
|
Generator | None
|
Optional random number generator for reproducibility. |
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Array of weighted p-values for each test instance. |
Note
Including test_weights in the numerator/denominator implies a positive lower bound of test_weights / (sum(calib_weights) + test_weights) when there is no calibration mass above the test score.
Source code in nonconform/scoring.py
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 | |
Weight Estimation¶
nonconform.weighting ¶
Weight estimation for covariate shift correction in weighted conformal prediction.
This module provides weight estimators that compute importance weights to correct for covariate shift between calibration and test distributions. They estimate density ratios w(x) = p_test(x) / p_calib(x) which are used to reweight conformal scores for better coverage guarantees under distribution shift.
Classes:
| Name | Description |
|---|---|
BaseWeightEstimator |
Abstract base class for weight estimators. |
IdentityWeightEstimator |
Returns uniform weights (no covariate shift). |
SklearnWeightEstimator |
Universal wrapper for sklearn probabilistic classifiers. |
BootstrapBaggedWeightEstimator |
Bootstrap-bagged wrapper for robust estimation. |
Factory functions
logistic_weight_estimator: Create estimator using Logistic Regression. forest_weight_estimator: Create estimator using Random Forest.
ProbabilisticClassifier ¶
Bases: Protocol
Protocol for classifiers that support probability estimation.
This protocol defines the interface for sklearn-compatible classifiers that can produce probability estimates for weight computation.
fit ¶
fit(X: ndarray, y: ndarray) -> ProbabilisticClassifier
Fit the classifier on training data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
Feature matrix of shape (n_samples, n_features). |
required |
y
|
ndarray
|
Target labels of shape (n_samples,). |
required |
Returns:
| Type | Description |
|---|---|
ProbabilisticClassifier
|
The fitted classifier instance. |
Source code in nonconform/weighting.py
49 50 51 52 53 54 55 56 57 58 59 | |
predict_proba ¶
predict_proba(X: ndarray) -> np.ndarray
Return probability estimates for samples.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
Feature matrix of shape (n_samples, n_features). |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Probability estimates of shape (n_samples, n_classes). |
Source code in nonconform/weighting.py
61 62 63 64 65 66 67 68 69 70 | |
BaseWeightEstimator ¶
Bases: ABC
Abstract base class for weight estimators in weighted conformal prediction.
Weight estimators compute importance weights to correct for covariate shift between calibration and test distributions. They estimate density ratios w(x) = p_test(x) / p_calib(x) which are used to reweight conformal scores for better coverage guarantees under distribution shift.
Subclasses must implement fit(), _get_stored_weights(), and _score_new_data() to provide specific weight estimation strategies.
fit
abstractmethod
¶
fit(
calibration_samples: ndarray, test_samples: ndarray
) -> None
Estimate density ratio weights.
Source code in nonconform/weighting.py
87 88 89 90 | |
get_weights ¶
get_weights(
calibration_samples: ndarray | None = None,
test_samples: ndarray | None = None,
) -> tuple[np.ndarray, np.ndarray]
Return density ratio weights for calibration and test data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
calibration_samples
|
ndarray | None
|
Optional calibration data to score. If provided, computes weights for this data using the fitted model. If None, returns stored weights from fit(). Must provide both or neither. |
None
|
test_samples
|
ndarray | None
|
Optional test data to score. If provided, computes weights for this data using the fitted model. If None, returns stored weights from fit(). Must provide both or neither. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[ndarray, ndarray]
|
Tuple of (calibration_weights, test_weights) as numpy arrays. |
Raises:
| Type | Description |
|---|---|
NotFittedError
|
If fit() has not been called. |
ValueError
|
If only one of calibration_samples/test_samples is provided. |
Source code in nonconform/weighting.py
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | |
set_seed ¶
set_seed(seed: int | None) -> None
Set random seed for reproducibility.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seed
|
int | None
|
Random seed value or None. |
required |
Source code in nonconform/weighting.py
140 141 142 143 144 145 146 | |
IdentityWeightEstimator ¶
IdentityWeightEstimator()
Bases: BaseWeightEstimator
Identity weight estimator that returns uniform weights.
This estimator assumes no covariate shift and returns weights of 1.0 for all samples. Useful as a baseline or when covariate shift is known to be minimal.
This effectively makes weighted conformal prediction equivalent to standard conformal prediction.
Source code in nonconform/weighting.py
241 242 243 244 | |
fit ¶
fit(
calibration_samples: ndarray, test_samples: ndarray
) -> None
Fit the identity weight estimator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
calibration_samples
|
ndarray
|
Array of calibration data samples. |
required |
test_samples
|
ndarray
|
Array of test data samples. |
required |
Source code in nonconform/weighting.py
246 247 248 249 250 251 252 253 254 255 | |
SklearnWeightEstimator ¶
SklearnWeightEstimator(
base_estimator: ProbabilisticClassifier
| BaseEstimator
| None = None,
clip_quantile: float | None = 0.05,
)
Bases: BaseWeightEstimator
Universal wrapper for any sklearn-compatible probabilistic classifier.
Adheres to the standard sklearn 'Meta-Estimator' pattern. Accepts a configured estimator instance and clones it for cross-validation safety.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_estimator
|
ProbabilisticClassifier | BaseEstimator | None
|
Configured sklearn classifier instance with predict_proba support. Defaults to LogisticRegression. |
None
|
clip_quantile
|
float | None
|
Quantile for weight clipping (e.g., 0.05 clips to 5th-95th percentile). Use None to disable clipping. Defaults to 0.05. |
0.05
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If base_estimator does not implement predict_proba. |
Examples:
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
# Default (LogisticRegression)
estimator = SklearnWeightEstimator()
# Custom with pipeline
estimator = SklearnWeightEstimator(
base_estimator=make_pipeline(
StandardScaler(), LogisticRegression(C=1.0, class_weight="balanced")
)
)
# Random Forest
estimator = SklearnWeightEstimator(
base_estimator=RandomForestClassifier(n_estimators=100, max_depth=5)
)
Source code in nonconform/weighting.py
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 | |
fit ¶
fit(
calibration_samples: ndarray, test_samples: ndarray
) -> None
Fit the weight estimator on calibration and test samples.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
calibration_samples
|
ndarray
|
Array of calibration data samples. |
required |
test_samples
|
ndarray
|
Array of test data samples. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If calibration_samples is empty. |
Source code in nonconform/weighting.py
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | |
BootstrapBaggedWeightEstimator ¶
BootstrapBaggedWeightEstimator(
base_estimator: BaseWeightEstimator,
n_bootstraps: int = 100,
clip_quantile: float | None = 0.05,
scoring_mode: Literal["frozen"] = "frozen",
)
Bases: BaseWeightEstimator
Bootstrap-bagged wrapper for weight estimators with instance-wise aggregation.
This estimator wraps any base weight estimator and applies bootstrap bagging to create more stable, robust weight estimates. It's most relevant when the calibration set is much larger than the test batch (or vice versa), where standalone weights can become spiky and unstable.
The algorithm: 1. For each bootstrap iteration: - Resample BOTH sets to balanced sample size (min of calibration and test sizes) - Fit the base estimator on the balanced bootstrap sample - Score ALL original instances using the fitted model (perfect coverage) - Store log(weights) for each instance 2. After all iterations: - Aggregate instance-wise weights using geometric mean (average in log-space) - Apply clipping to maintain boundedness for theoretical guarantees
Seed inheritance
This class uses the _seed attribute pattern for automatic seed
inheritance from ConformalDetector.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_estimator
|
BaseWeightEstimator
|
Any BaseWeightEstimator instance. |
required |
n_bootstraps
|
int
|
Number of bootstrap iterations. Defaults to 100. |
100
|
clip_quantile
|
float | None
|
Quantile for adaptive clipping. Use None to disable clipping. Defaults to 0.05. |
0.05
|
scoring_mode
|
Literal['frozen']
|
Weight scoring behavior after fit. Currently only
|
'frozen'
|
References
Jin, Ying, and Emmanuel J. Candès. "Selection by Prediction with Conformal p-values." Journal of Machine Learning Research 24.244 (2023): 1-41.
Source code in nonconform/weighting.py
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 | |
supports_rescoring
property
¶
supports_rescoring: bool
Whether this estimator can score arbitrary new batches after fit().
weight_counts
property
¶
weight_counts: str
Return diagnostic info about instance-wise weight coverage.
fit ¶
fit(
calibration_samples: ndarray, test_samples: ndarray
) -> None
Fit the bagged weight estimator with perfect instance coverage.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
calibration_samples
|
ndarray
|
Array of calibration data samples. |
required |
test_samples
|
ndarray
|
Array of test data samples. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If calibration_samples is empty. |
Source code in nonconform/weighting.py
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 | |
logistic_weight_estimator ¶
logistic_weight_estimator(
regularization: str | float = "auto",
clip_quantile: float = 0.05,
class_weight: str | dict = "balanced",
max_iter: int = 1000,
) -> SklearnWeightEstimator
Create weight estimator using Logistic Regression.
This factory function provides behavioral equivalence with the old LogisticWeightEstimator class.
Note
When used with ConformalDetector, the detector's seed is automatically propagated to the weight estimator for reproducibility.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
regularization
|
str | float
|
Regularization parameter. If 'auto', uses C=1.0. If float, uses as C parameter. |
'auto'
|
clip_quantile
|
float
|
Quantile for weight clipping. Defaults to 0.05. |
0.05
|
class_weight
|
str | dict
|
Class weights for LogisticRegression. Defaults to 'balanced'. |
'balanced'
|
max_iter
|
int
|
Maximum iterations for solver convergence. Defaults to 1000. |
1000
|
Returns:
| Type | Description |
|---|---|
SklearnWeightEstimator
|
Configured SklearnWeightEstimator instance. |
Examples:
estimator = logistic_weight_estimator(regularization=0.5)
estimator.fit(calib_samples, test_samples)
w_calib, w_test = estimator.get_weights()
Source code in nonconform/weighting.py
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 | |
forest_weight_estimator ¶
forest_weight_estimator(
n_estimators: int = 100,
max_depth: int | None = 5,
min_samples_leaf: int = 10,
clip_quantile: float = 0.05,
) -> SklearnWeightEstimator
Create weight estimator using Random Forest.
This factory function provides behavioral equivalence with the old ForestWeightEstimator class.
Note
When used with ConformalDetector, the detector's seed is automatically propagated to the weight estimator for reproducibility.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_estimators
|
int
|
Number of trees in the forest. Defaults to 100. |
100
|
max_depth
|
int | None
|
Maximum depth of trees. Defaults to 5. |
5
|
min_samples_leaf
|
int
|
Minimum samples at leaf node. Defaults to 10. |
10
|
clip_quantile
|
float
|
Quantile for weight clipping. Defaults to 0.05. |
0.05
|
Returns:
| Type | Description |
|---|---|
SklearnWeightEstimator
|
Configured SklearnWeightEstimator instance. |
Examples:
estimator = forest_weight_estimator(n_estimators=200)
estimator.fit(calib_samples, test_samples)
w_calib, w_test = estimator.get_weights()
Source code in nonconform/weighting.py
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 | |
FDR Control¶
Includes weighted low-level expert APIs (weighted_false_discovery_control).
For standard workflows, prefer ConformalDetector.select(...).
nonconform.fdr ¶
False Discovery Rate control utilities for conformal prediction.
This module provides explicit entry points for:
- Weighted Conformalized Selection (WCS) under covariate shift.
Pruning ¶
Bases: Enum
Pruning strategies for weighted FDR control.
Attributes:
| Name | Type | Description |
|---|---|---|
HETEROGENEOUS |
Remove elements based on independent random checks per item. |
|
HOMOGENEOUS |
Apply one shared random decision to all items. |
|
DETERMINISTIC |
Remove items using a fixed rule with no randomness. |
weighted_false_discovery_control ¶
weighted_false_discovery_control(
result: ConformalResult | None,
*,
alpha: float = 0.05,
pruning: Pruning = Pruning.DETERMINISTIC,
seed: int | None = None,
) -> np.ndarray
Perform WCS from a strict ConformalResult bundle.
Source code in nonconform/fdr.py
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | |
weighted_false_discovery_control_from_arrays ¶
weighted_false_discovery_control_from_arrays(
*,
p_values: ndarray,
test_scores: ndarray,
calib_scores: ndarray,
test_weights: ndarray,
calib_weights: ndarray,
alpha: float = 0.05,
pruning: Pruning = Pruning.DETERMINISTIC,
seed: int | None = None,
) -> np.ndarray
Perform WCS from explicit weighted arrays and precomputed p-values.
Source code in nonconform/fdr.py
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 | |
Martingales¶
nonconform.martingales ¶
Exchangeability martingales for sequential conformal evidence.
This module implements p-value-based martingales and alarm statistics for streaming or temporal monitoring workflows. In practice, you feed one conformal p-value at a time and read a running evidence state after each update.
Implemented martingales
- PowerMartingale
- SimpleMixtureMartingale
- SimpleJumperMartingale
All classes consume conformal p-values in [0, 1]. Alarm statistics are
computed from martingale ratio increments and exposed together with the current
martingale value in :class:MartingaleState.
AlarmConfig
dataclass
¶
AlarmConfig(
ville_threshold: float | None = None,
restarted_ville_threshold: float | None = None,
cusum_threshold: float | None = None,
shiryaev_roberts_threshold: float | None = None,
)
Optional alarm thresholds for martingale evidence statistics.
Thresholds are disabled when set to None. Each threshold compares
against a running statistic in :class:MartingaleState.
ville_threshold and restarted_ville_threshold are Ville thresholds
for e-processes. cusum_threshold and shiryaev_roberts_threshold are
change-evidence thresholds and should not be interpreted as
probability-of-ever-crossing Ville thresholds without a separate theorem for
the exact statistic.
MartingaleState
dataclass
¶
MartingaleState(
step: int,
p_value: float,
log_martingale: float,
martingale: float,
log_restarted_martingale: float,
restarted_martingale: float,
log_cusum: float,
cusum: float,
log_shiryaev_roberts: float,
shiryaev_roberts: float,
triggered_alarms: tuple[str, ...],
)
Snapshot of martingale and alarm statistics after one update.
BaseMartingale ¶
BaseMartingale(alarm_config: AlarmConfig | None = None)
Bases: ABC
Abstract base class for p-value-driven exchangeability martingales.
Source code in nonconform/martingales.py
170 171 172 | |
reset ¶
reset() -> None
Reset martingale and alarm statistics to initial values.
Source code in nonconform/martingales.py
179 180 181 182 183 184 185 186 187 188 189 | |
update_many ¶
update_many(
p_values: Sequence[float] | ndarray,
) -> list[MartingaleState]
Update state for each p-value in order and return all snapshots.
Source code in nonconform/martingales.py
191 192 193 194 195 | |
update ¶
update(p_value: float) -> MartingaleState
Ingest one p-value in [0, 1] and return the updated state.
Source code in nonconform/martingales.py
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 | |
PowerMartingale ¶
PowerMartingale(
epsilon: float = 0.5,
alarm_config: AlarmConfig | None = None,
)
Bases: BaseMartingale
Power martingale with fixed epsilon in (0, 1].
Source code in nonconform/martingales.py
280 281 282 283 284 285 286 287 288 | |
SimpleMixtureMartingale ¶
SimpleMixtureMartingale(
epsilons: Sequence[float] | ndarray | None = None,
*,
n_grid: int = 100,
min_epsilon: float = 0.01,
alarm_config: AlarmConfig | None = None,
)
Bases: BaseMartingale
Simple mixture martingale over a fixed epsilon grid.
Source code in nonconform/martingales.py
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | |
SimpleJumperMartingale ¶
SimpleJumperMartingale(
jump: float = 0.01,
alarm_config: AlarmConfig | None = None,
)
Bases: BaseMartingale
Simple Jumper martingale (Algorithm 1 in Vovk et al.).
This method mixes three betting components and redistributes mass each
step through jump.
Source code in nonconform/martingales.py
358 359 360 361 362 363 364 365 366 367 | |
Data Structures¶
nonconform.structures ¶
Core data structures and protocols for nonconform.
This module provides the fundamental types used throughout the package:
Classes:
| Name | Description |
|---|---|
AnomalyDetector |
Protocol defining the detector interface. |
ConformalResult |
Container for conformal prediction outputs. |
AnomalyDetector ¶
Bases: Protocol
Protocol defining the interface for anomaly detectors.
Any detector (PyOD, sklearn-compatible, or custom) can be used with nonconform by implementing this protocol.
Required methods
fit: Train the detector on data decision_function: Compute anomaly scores get_params: Retrieve detector parameters set_params: Configure detector parameters
The detector must be copyable (support copy.copy and copy.deepcopy).
Examples:
# Most PyOD detectors work automatically (blocked strict-inductive
# exceptions are documented in the detector compatibility guide)
from pyod.models.iforest import IForest
detector: AnomalyDetector = IForest()
# Custom detector implementing the protocol
class MyDetector:
def fit(self, X, y=None): ...
def decision_function(self, X): ...
def get_params(self, deep=True): ...
def set_params(self, **params): ...
detector: AnomalyDetector = MyDetector()
fit ¶
fit(X: ndarray, y: ndarray | None = None) -> Self
Train the anomaly detector.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
Training data of shape (n_samples, n_features). |
required |
y
|
ndarray | None
|
Ignored. Present for API consistency. |
None
|
Returns:
| Type | Description |
|---|---|
Self
|
The fitted detector instance. |
Source code in nonconform/structures.py
62 63 64 65 66 67 68 69 70 71 72 | |
decision_function ¶
decision_function(X: ndarray) -> np.ndarray
Compute anomaly scores for samples.
Higher scores indicate more anomalous samples.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
X
|
ndarray
|
Data of shape (n_samples, n_features). |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
Anomaly scores of shape (n_samples,). |
Source code in nonconform/structures.py
74 75 76 77 78 79 80 81 82 83 84 85 | |
get_params ¶
get_params(deep: bool = True) -> dict[str, Any]
Get parameters for this detector.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
deep
|
bool
|
If True, return parameters for sub-objects. |
True
|
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
Parameter names mapped to their values. |
Source code in nonconform/structures.py
87 88 89 90 91 92 93 94 95 96 | |
set_params ¶
set_params(**params: Any) -> Self
Set parameters for this detector.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**params
|
Any
|
Detector parameters. |
{}
|
Returns:
| Type | Description |
|---|---|
Self
|
The detector instance. |
Source code in nonconform/structures.py
98 99 100 101 102 103 104 105 106 107 | |
ConformalResult
dataclass
¶
ConformalResult(
p_values: ndarray | None = None,
test_scores: ndarray | None = None,
calib_scores: ndarray | None = None,
test_weights: ndarray | None = None,
calib_weights: ndarray | None = None,
metadata: dict[str, Any] = dict(),
)
Snapshot of detector outputs for downstream procedures.
This dataclass holds all outputs from a conformal prediction, including p-values, raw scores, and optional weights for weighted conformal.
Attributes:
| Name | Type | Description |
|---|---|---|
p_values |
ndarray | None
|
Conformal p-values for test instances (None when unavailable). |
test_scores |
ndarray | None
|
Non-conformity scores for the test instances (raw predictions). |
calib_scores |
ndarray | None
|
Non-conformity scores for the calibration set. |
test_weights |
ndarray | None
|
Importance weights for test instances (weighted mode only). |
calib_weights |
ndarray | None
|
Importance weights for calibration instances. |
metadata |
dict[str, Any]
|
Optional dictionary with extra data (debug info, timings, etc.). |
Examples:
p_values = detector.compute_p_values(X_test)
result = detector.last_result
print(result.p_values) # Access p-values
print(result.metadata) # Access optional metadata
copy ¶
copy() -> ConformalResult
Return a copy with arrays and metadata fully duplicated.
Returns:
| Type | Description |
|---|---|
ConformalResult
|
A new ConformalResult with copied arrays and deep-copied metadata. |
Source code in nonconform/structures.py
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | |
Adapters¶
nonconform.adapters ¶
External detector adapters for nonconform.
ScorePolarityAdapter ¶
ScorePolarityAdapter(
detector: AnomalyDetector, score_polarity: ScorePolarity
)
Adapter that normalizes detector score direction conventions.
Source code in nonconform/adapters.py
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | |
fit ¶
fit(X: ndarray, y: ndarray | None = None) -> Self
Fit wrapped detector.
Source code in nonconform/adapters.py
233 234 235 236 | |
decision_function ¶
decision_function(X: ndarray) -> np.ndarray
Return scores transformed to anomalous-higher convention.
Source code in nonconform/adapters.py
238 239 240 241 | |
get_params ¶
get_params(deep: bool = True) -> dict[str, Any]
Delegate parameter retrieval to wrapped detector.
Source code in nonconform/adapters.py
243 244 245 | |
set_params ¶
set_params(**params: Any) -> Self
Delegate parameter updates to wrapped detector.
Source code in nonconform/adapters.py
247 248 249 250 | |
PyODAdapter ¶
PyODAdapter(detector: Any)
Adapter wrapping PyOD detectors to ensure protocol compliance.
Source code in nonconform/adapters.py
284 285 286 287 288 | |
fit ¶
fit(X: ndarray, y: ndarray | None = None) -> Self
Fit wrapped detector.
Source code in nonconform/adapters.py
290 291 292 293 | |
decision_function ¶
decision_function(X: ndarray) -> np.ndarray
Return anomaly scores from wrapped detector.
Source code in nonconform/adapters.py
295 296 297 | |
get_params ¶
get_params(deep: bool = True) -> dict[str, Any]
Delegate parameter retrieval to wrapped detector.
Source code in nonconform/adapters.py
299 300 301 | |
set_params ¶
set_params(**params: Any) -> Self
Delegate parameter updates to wrapped detector.
Source code in nonconform/adapters.py
303 304 305 306 | |
adapt ¶
adapt(detector: Any) -> AnomalyDetector
Adapt a detector to the AnomalyDetector protocol.
Source code in nonconform/adapters.py
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | |
parse_score_polarity ¶
parse_score_polarity(
score_polarity: ScorePolarityInput,
) -> ScorePolarity
Parse score polarity input to canonical enum representation.
Source code in nonconform/adapters.py
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | |
resolve_implicit_score_polarity ¶
resolve_implicit_score_polarity(
detector: Any,
) -> ScorePolarity
Resolve score polarity when users omit score_polarity.
The default favors low-friction custom detector onboarding while preserving safe behavior for known detector families: - Known sklearn normality detectors -> HIGHER_IS_NORMAL - PyOD detectors -> HIGHER_IS_ANOMALOUS - Unknown custom detectors -> HIGHER_IS_ANOMALOUS
Source code in nonconform/adapters.py
145 146 147 148 149 150 151 152 153 154 155 156 157 158 | |
resolve_score_polarity ¶
resolve_score_polarity(
detector: Any, score_polarity: ScorePolarityInput
) -> ScorePolarity
Resolve requested score polarity in strict AUTO mode.
Unlike resolve_implicit_score_polarity, this function is intentionally
strict for explicit score_polarity="auto" and raises for unknown
detectors.
Source code in nonconform/adapters.py
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
apply_score_polarity ¶
apply_score_polarity(
detector: AnomalyDetector,
score_polarity: ScorePolarityInput,
) -> AnomalyDetector
Return detector that follows requested score polarity convention.
Source code in nonconform/adapters.py
191 192 193 194 195 196 197 198 199 200 201 202 203 | |