Skip to main content

fcnd

fcnd is a Python package for full conformal novelty detection with finite-sample false discovery rate (FDR) control. It provides implementations of the full conformal methodology developed in the following paper:

J. Lee, I. Popov, Z. Ren. "Full conformal novelty detection". (arXiv)

Novelty detection is the problem of identifying outliers in a test dataset given a reference dataset of only inliers. The goal is to learn (via ML models) a representation that can distinguish between the outliers in the test dataset and the inliers in the test and reference dataset.

This package is for method development and is designed to fit into workflows that want to apply or build on top of full conformal novelty detection methods. This repository is not a reproduction repository for the above mentioned paper. Reproduction-specific assets such as job scripts and plotting code are not included. Split conformal baselines are included, in case the application of these methods are also of interest.

Features

  • Full conformal novelty detection via FCND
  • Split conformal novelty detection via SCND
  • Model-selection full conformal novelty detection via MSFCND
  • Weighted conformal p-values and e-values for distribution-shifted settings
  • Fast and lightweight conditionally calibrated e-BH boosting via EBHCC
  • Flexible learner interface via BaseLearner, with built-in wrappers for common scikit-learn novelty-detection models
  • Numba-backed numerical kernels enabled by default

Installation

Install the package from PyPI:

pip install fcnd

For notebook examples, install the optional notebook dependencies:

pip install "fcnd[notebook]"

fcnd supports Python 3.10, 3.11, and 3.12. The default dependency set includes numba, numpy, and scikit-learn; scipy is installed transitively by scikit-learn.

Quickstart Example

import numpy as np

from fcnd import FCND, IsoForestLearner
from fcnd.synthetic import generate_wset, gen_data

rng = np.random.default_rng(123)
W = generate_wset(size=16, dims=8, random_state=rng)

X_ref = gen_data(W, 60, a=1.0, random_state=rng)
X_test = np.vstack([
    gen_data(W, 30, a=1.0, random_state=rng),
    gen_data(W, 10, a=3.5, random_state=rng),
])

detector = FCND(
    IsoForestLearner(random_state=1, n_estimators=50),
    use_numba=True,
)
result = detector.detect(X_ref, X_test, alpha=0.2, method="ebh")

print(result.rejections)
print(result.n_rejections)

Expected output:

[ 1 20 31 32 34 37 39]
7

The detect method returns a DetectionResult with conformal p- or e-values, non-conformity scores, the rejection set, and basic metadata.

Example Notebook

The notebook examples/fcnd_quickstart.ipynb demonstrates FCND, weighted FCND, and MSFCND in a single workflow.

Main API

Object Purpose
FCND Full conformal novelty detector for reference and test samples
SCND Split conformal novelty detector with separate train/calibration/test inputs
MSFCND Model-selection full conformal novelty detector over a candidate learner library
EBHCC Streaming conditionally calibrated e-BH booster
IsoForestLearner Isolation Forest wrapper with larger scores meaning more anomalous
OneClassSVMLearner One-class SVM wrapper with larger scores meaning more anomalous
BaseLearner Abstract interface for custom score learners
bh, ebh BH and e-BH multiple-testing procedures

Custom Learners

FCND, SCND, and MSFCND can use any learner that implements BaseLearner. A learner must provide:

  • reset(): return a fresh, unfitted learner state;
  • fit(X, **kwargs): fit on an array of observations and return self;
  • score(X): return a one-dimensional array of nonconformity scores. Larger scores should indicate more anomalous observations.

Example wrapper around a scikit-learn-compatible estimator:

import numpy as np
from sklearn.neighbors import LocalOutlierFactor

from fcnd import BaseLearner, FCND


class LOFLearner(BaseLearner):
    def __init__(self, **kwargs):
        self._params = kwargs
        self.model = None
        self.fitted_ = False

    def reset(self):
        self.model = LocalOutlierFactor(novelty=True, **self._params)
        self.fitted_ = False
        return self

    def fit(self, X, **kwargs):
        if self.model is None:
            self.reset()
        self.model.set_params(**kwargs)
        self.model.fit(X)
        self.fitted_ = True
        return self

    def score(self, X):
        if self.model is None:
            raise RuntimeError("Call fit before score.")
        return -np.asarray(self.model.score_samples(X), dtype=float).reshape(-1)


detector = FCND(LOFLearner(n_neighbors=20), use_numba=True)
result = detector.detect(X_ref, X_test, alpha=0.1, method="ebh")

Score Construction Modes

Full conformal methods can construct scores in two main ways:

  • In-sample (IS) scoring fits the learner once on the combined reference and test data and scores all observations with that fitted learner.
  • Leave-one-out (LOO) scoring refits the learner after removing each observation and then scores the held-out observation.

For a single learner, use FCND(..., leave_one_out=True) to enable LOO scoring. By default, FCND uses IS scoring.

Model Selection

MSFCND accepts a dictionary or sequence of learner objects and performs block-wise model selection before forming conformal values:

from fcnd import MSFCND, IsoForestLearner, OneClassSVMLearner

learners = {
    "if100": IsoForestLearner(random_state=0, n_estimators=100),
    "svm_auto": OneClassSVMLearner(nu=0.05, kernel="rbf", gamma="auto"),
}
training_modes = {"if100": "is", "svm_auto": "loo"}

ms = MSFCND(
    learners,
    alpha=0.1,
    K=10,
    training_modes=training_modes,
    use_numba=True,
)
result = ms.detect(X_ref, X_test, method="ebh")

As seen above, MSFCND controls the score construction mode through training_modes: pass "is", "loo", "both", or a dictionary assigning modes for each learner.

Weighted FCND

Weighted conformal calibration is available through load_weights or the high-level detect interface:

result = detector.detect(
    X_ref,
    X_test,
    alpha=0.1,
    method="ebh",
    weights_ref=w_ref,
    weights_test=w_test,
)

The weights should encode the relevant density-ratio information for the weighted-exchangeability setting. For further details, see Section 4 of the paper.

Conditional Calibration

As the full conformal method uses e-values, we use the e-BH procedure for the multiple testing algorithm. However, e-BH can be further improved through leveraging an informative conditional distribution with regard to a sufficient statistic (see here).

EBHCC implements this ``boosted'' e-BH method, called e-BH-CC (e-BH with Conditional Calibration). It is a fast and lightweight implementation that is suited for conformal novelty detection, reducing memory use and computation time by no longer depending on resampling and Monte Carlo estimation.

The optimized shortcuts in EBHCC are deliberately restricted to the compatible built-in design choices used by the package:

  • built-in p-value auxiliary statistics for the prune=True skipping shortcut;
  • the built-in hybrid hatR denominator for the guarantee=True uniform-improvement shortcut.

For custom conditional-calibration statistics/denominators, use guarantee=False and prune=False unless the corresponding validity argument has been verified for that statistic/denominator pair. For further details, see Section 3.4 of the paper.

Citation

If you use fcnd in your research or workflow, please consider citing our accompanying paper!

@misc{lee2026fullconformal,
  title = {Full-conformal novelty detection},
  author = {Lee, Junu and Popov, Ilia and Ren, Zhimei},
  year = {2026},
  eprint = {2501.02703v2},
  archivePrefix = {arXiv},
  primaryClass = {stat.ME},
  doi = {10.48550/arXiv.2501.02703},
  url = {https://arxiv.org/abs/2501.02703v2}
}

A machine-readable citation is also available in CITATION.cff.

License

fcnd is released under the MIT License. See LICENSE for details.

Metadata

Release files for fcnd 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fcnd 0.1.2
File Size Uploaded Provenance Actions
fcnd-0.1.2.tar.gz 28.8 kB With provenance Details for fcnd-0.1.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for fcnd 0.1.2
File Interpreter ABI Platform Actions
fcnd-0.1.2-py3-none-any.whl Python 3 none any Details for fcnd-0.1.2-py3-none-any.whl

Total release size: 63.8 kB

Release files / fcnd-0.1.2.tar.gz

Download URL fcnd-0.1.2.tar.gz
Size 28.8 kB
Tags Source
SHA-256 checksum
How to use checksums
4fef6af263ec6b3b4a9ae9c5f939992f9c170b5e681f2e04157d7025fea0a5f9
BLAKE2b-256 checksum
How to use checksums
0b2c333bc6b76c69837a723050c9a0be28180d02db42e04d18449f911a3afcec
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 26, 2026.

Transparency log

Release files / fcnd-0.1.2-py3-none-any.whl

Download URL fcnd-0.1.2-py3-none-any.whl
Size 35.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ea0d7dc91b245d16df42edfbd1ccf1815f9e24d0c58542747fa92711c4e9ed1b
BLAKE2b-256 checksum
How to use checksums
6920335a962c4022788bb9ac401c74e03e964f1102a851a5caeb8f868192a345
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 26, 2026.

Transparency log

Security for fcnd 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for fcnd-0.1.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 26, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page