Skip to main content

Dependence-robust two-sample drift tests for serially correlated feature streams

Project description

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

driftdep-0.1.0.tar.gz (204.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

driftdep-0.1.0-py3-none-any.whl (14.2 kB view details)

Uploaded Python 3

File details

Details for the file driftdep-0.1.0.tar.gz.

File metadata

  • Download URL: driftdep-0.1.0.tar.gz
  • Upload date:
  • Size: 204.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for driftdep-0.1.0.tar.gz
Algorithm Hash digest
SHA256 25ec575476c3bbaf27be499b1d83e71e10b75c54c7a4367f21e1a24903817f46
MD5 7cc2490ce2c07421b9c4eadcd29be5d6
BLAKE2b-256 94e727502de067b50e8c87ab9f9e9c0177d47b9e82100ac1697a0dfc5a1b1a03

See more details on using hashes here.

File details

Details for the file driftdep-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: driftdep-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 14.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.0

File hashes

Hashes for driftdep-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 0ee975f540d2631d73e0a38a7e0b25273dc9a7f8b4a19333ec3462d7046b2848
MD5 5354f6e53155111c88227a80de2b470c
BLAKE2b-256 757cd3f5fcf02dca561276a14a902bb1e04cacda4730ca4b88379cb6a5395797

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page