Skip to main content

driftdep

Your drift monitor is lying to you. If your feature windows are autocorrelated — and they almost always are — standard two-sample tests (KS, CvM, AD, MMD) over-reject by 2–10× at realistic dependencies. A single AR(1) coefficient of ρ=0.7 inflates the KS false-alarm rate from 5% to 35%. Long-memory processes (ARFIMA) push it even higher.

driftdep is a drop-in, dependence-robust replacement that corrects for serial dependence via ESS-adjusted block permutation by default.

# Before — unreliable under serial dependence
from scipy.stats import ks_2samp
stat, p = ks_2samp(x_ref, x_new)   # p-value too small when data is autocorrelated

# After — calibrated by default
from driftdep import ks_2samp
stat, p = ks_2samp(x_ref, x_new)   # same call, same unpacking, correct p-value

Install

pip install driftdep

Requires Python ≥ 3.10, numpy ≥ 1.24, scipy ≥ 1.10 only. Heavy research dependencies (arch, statsmodels, dcor) are optional:

pip install "driftdep[research]"   # for all corrections and download scripts

Quick start

import numpy as np
import driftdep

rng = np.random.default_rng(0)
x_ref = rng.standard_normal(500)
x_new = rng.standard_normal(500)   # same distribution; should not alarm

stat, p = driftdep.ks_2samp(x_ref, x_new)
# p ≈ 0.6 — no false alarm (correct even if the series is autocorrelated)

# Full result with diagnostics
result = driftdep.drift_test(x_ref, x_new, statistic="ks")
print(result.pvalue)        # dependence-corrected p-value
print(result.n_eff)         # effective sample size estimate
print(result.block_length)  # block length used by block permutation

API

driftdep.drift_test(
    x, y, *,
    statistic="ks",           # "ks", "cvm", "ad", "energy", "mmd",
                              # "wasserstein", "psi", "js"
    correction="block_perm",  # default engine; see table below
    block_length=None,        # None → auto (Politis–White 2004)
    ess_adjust=True,          # compute and report indicator-transform ESS
    n_resamples=999,          # permutation resamples
    alpha=0.05,
    rng=None,                 # numpy Generator, int seed, or None
) -> DriftResult

DriftResult unpacks as (statistic, pvalue) for drop-in compatibility and also exposes .pvalue, .n_eff, .block_length, .correction.

Available corrections

correction= Description Extra deps
block_perm Block permutation, Politis–White block length —
ess_adjust ESS-adjusted analytic null (cheapest; KS/CvM/AD) —
naive i.i.d. null — baseline / reference only —
thinning Keep every k-th obs to approximate independence —
dep_wild Dependent wild bootstrap (Shao 2010) —
mbb Moving block bootstrap (Künsch 1989) [research]
cbb Circular block bootstrap [research]
stationary Stationary bootstrap (Politis–Romano 1994) [research]
prewhiten Cautionary only — changes the hypothesis [research]

Method

driftdep benchmarks and operationalizes dependence corrections for two-sample distributional drift tests. The core insight: when observations within a monitoring window are autocorrelated, the i.i.d. null distribution of KS, CvM, and related statistics is stochastically dominated, causing severe over-rejection.

The recommended default — ESS-adjusted block permutation — permutes contiguous blocks of length b (preserving within-block dependence) and selects b automatically via Politis–White (2004). Empirical size recovers to ≈ α across AR(1), ARFIMA, and GARCH dependence structures. Size-adjusted power is within 5–7 percentage points of the uncalibrated naive test at moderate effect sizes.

All corrections already exist in the literature; this package operationalizes them in a unified interface with a validated default.

Reproduce paper results

git clone https://github.com/vivekch2018/driftdep
cd driftdep
pip install -e ".[research]"
make data        # download public datasets (requires internet)
make reproduce   # regenerate all figures and tables from seeds

Citation

@misc{chaudhary2025driftdep,
  author  = {Chaudhary, Vivek},
  title   = {Two-Sample Drift Tests Break Under Serial Dependence:
             A Benchmark and Deployable Correction},
  year    = {2025},
  note    = {Preprint},
  url     = {https://github.com/vivekch2018/driftdep},
}

License

MIT

Metadata

Release files for driftdep 0.1.0

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

Source distribution (sdist)

Source distribution for driftdep 0.1.0
File Size Uploaded
driftdep-0.1.0.tar.gz 204.0 kB Details

Built distribution (wheel)

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

Total release size: 218.2 kB

Release files / driftdep-0.1.0.tar.gz

Download URL driftdep-0.1.0.tar.gz
Size 204.0 kB
Tags Source
SHA-256 checksum
How to use checksums
25ec575476c3bbaf27be499b1d83e71e10b75c54c7a4367f21e1a24903817f46
BLAKE2b-256 checksum
How to use checksums
94e727502de067b50e8c87ab9f9e9c0177d47b9e82100ac1697a0dfc5a1b1a03
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.0

Release files / driftdep-0.1.0-py3-none-any.whl

Download URL driftdep-0.1.0-py3-none-any.whl
Size 14.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0ee975f540d2631d73e0a38a7e0b25273dc9a7f8b4a19333ec3462d7046b2848
BLAKE2b-256 checksum
How to use checksums
757cd3f5fcf02dca561276a14a902bb1e04cacda4730ca4b88379cb6a5395797
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.0

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

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