← Blog/blog/cjsd-overlap-blind-spot

The drift score that knows when it cannot know

Your fraud model starts missing a new batch. Did customer behavior move into a different part of feature space, or did the relationship between features and fraud actually change? The first is covariate shift: P(X) changes. The second is mechanism or concept drift: P(Y | X) changes. They demand different responses, but most drift scores mix them together.

Oda's Conditional Jensen–Shannon Discrepancy (CJSD) asks a crisp question: after the input X is known, how much extra information does the label Y reveal about which dataset the row came from? Two ordinary probabilistic classifiers estimate the answer. The important catch is in the paper's anti-coupling inequality: if X already gives the dataset away, there is almost no information left for Y to add. A tiny CJSD can mean “same mechanism,” or “no overlap, so we cannot tell.”

01

Predict the dataset, not the label

Pool equally many examples from datasets A and B and attach a dataset indicator Z. Train one discriminator T₁ to predict Z from X. Train a second T₂ to predict Z from the pair (X, Y). A discriminator here is just a probabilistic binary classifier; a logistic regression works for simple boundaries, while a tree or boosted model can represent nonlinear ones.

If Y carries no dataset-specific information once X is fixed, T₂ cannot improve on T₁. If the labeling rule changed, the joint classifier should predict the dataset better. With cross-entropy (log loss), the population identity is

CJSD = I(Z; Y | X) = CE(Z | X) − CE(Z | X, Y).

Conditional mutual information I(Z; Y | X) is the information Y adds about Z after X is already known. The subtraction is evaluated on held-out folds, so neither classifier scores points it trained on. The two losses are paired row by row, which also gives a useful variance estimate.

def held_out_cjs(rows, eps=1e-6):
    total = 0.0
    for z, p_x, p_xy in rows:
        p_x = min(1 - eps, max(eps, p_x))
        p_xy = min(1 - eps, max(eps, p_xy))
        loss_x = -log(p_x if z == 0 else 1 - p_x)
        loss_xy = -log(p_xy if z == 0 else 1 - p_xy)
        total += loss_x - loss_xy
    return total / len(rows)

The from-scratch function above is the paper's held-out estimator. On a two-row sanity check where T₁ is uninformative at 0.5 and T₂ assigns 0.8 to the correct dataset, it returns 0.470 nats, exactly ln(1.6). In a real audit, the probabilities must come from cross-fitted models, and the two source samples are balanced so P(Z) = 1/2.

02

The chain rule separates the two axes exactly

The total Jensen–Shannon difference between the two joint datasets is I(Z; X, Y). The mutual information chain rule splits it without a residual:

I(Z; X, Y) = I(Z; X) + I(Z; Y | X).

The first term is a covariate axis: how identifiable the dataset is from inputs alone. The second is CJSD, the functional axis. Under pure covariate shift, the conditional label distributions match at every observable X, so CJSD is exactly zero no matter how far P(X) moves. Unlike exchanging two task-specific predictors, nothing is asked to extrapolate off its training support.

Analytic from-scratch reproduction of the paper's drift-mass law. For deterministic labels and matched input distributions, CJSD / ln 2 equals the fraction of input mass on which the two labeling rules disagree.

That normalization gives CJSD an intuitive ruler. If two deterministic labelers disagree on 25% of an otherwise shared input distribution, the score is 0.25 ln 2, and the highlighted bar reads 25%. This is an identity, not a fit to the paper's empirical datasets.

03

The buried caveat: the axes compete for one bit

Because Z is binary and balanced, all the information about it fits inside ln 2 nats—one bit. Therefore

CJSD ≤ ln 2 − I(Z; X).

The two axes are additive, not independent coordinates. As the input distributions become easy to separate, the maximum observable functional signal collapses. This is not a defect a larger classifier can repair; it is an identifiability boundary.

input axis I(Z; X)functional axis CJSDjoint discrepancy
Seed-free analytic stress test computed by the core module. The two deterministic mechanisms disagree at both X values throughout, but their input supports separate. Joint dataset information stays at ln 2 while CJSD is squeezed to zero because no X value remains jointly observable.
04

The fitted score inherits two model errors

Let ε₁ be T₁'s excess log loss above the best possible X-only discriminator, and ε₂ the corresponding excess for T₂. The fitted population loss gap is CJSD + ε₁ − ε₂. Its bias has no guaranteed sign. The paper's one-sided result is sharper: an inflated alarm is bounded only by ε₁, while an overly reassuring clearance is bounded only by ε₂.

In the main experiments, matched architectures tended to make ε₂ larger and shrink the estimate toward zero. That was an empirical regularity, not a theorem. The appendix constructs a pure scale shift where linear logistic T₁ cannot represent its quadratic target: ε₁ = 0.1492 exceeds ε₂ = 0.1255, creating a false +0.0237 functional signal even though true CJSD is zero. A flexible discriminator removes the artifact.

  • Balance A and B so the ln 2 normalization remains exact.
  • Cross-fit both discriminators; do not score their training rows.
  • Clip probabilities before log loss, and report the clipping threshold.
  • Audit calibration and capacity separately for T₁ and T₂.
  • Read CJSD beside the covariate axis and an overlap diagnostic.
05

What the experiments establish

MeasureConcept vs covariate AUCPure covariate signalMain limitation
CJSD1.00≈ 0Two discriminators
kNN-CMI1.00≈ 0Fails from d = 64
Local-permutation test0.90CCIT-style
Exchange scores0.78–0.82InflatesOff-support error
MMD / sliced W₂0.00RespondsInput-only
Paper-reported results over 202 pairs. The exchange-score row is the reported 0.78–0.82 range across variants; MMD and sliced Wasserstein use input distributions only.

Under a pure support shift, the paper's exchange score rose from 0.001 to 0.346 while estimated CJSD stayed between −0.002 and 0.002. In the dimensionality study, the kNN plug-in dropped to 0.72 AUC at d = 64 and reached chance from d = 256. With 12,000 samples per side, a histogram-gradient-boosting discriminator reached 1.00 across the tested grid through d = 512. That comparison supports a practical claim about the estimator, not a claim that CJSD discovered a different population quantity than conditional mutual information.

06

What to probe next

Before using CJSD as a production gate, sweep discriminator families, folds, probability clipping, and source balance. Plot the score against I(Z; X); challenge every low CJSD with deliberately reduced overlap; and calibrate thresholds on matched null pairs. Also remember what the paper does not claim: CJSD tests no-adaptation reuse, not whether fine-tuning will transfer well. Differences outside shared support are irrelevant to the former and may be decisive for the latter.

References

  1. Kentaro Oda (2026). Separating Covariate Shift from Mechanism Change with Two Discriminators: CJSD, a Conditional Discrepancy with an Exact Covariate-Concept Decomposition. arXiv preprint, cs.LG
  2. Sudipto Mukherjee, Himanshu Asnani, Sreeram Kannan (2020). CCMI: Classifier Based Conditional Mutual Information Estimation. Proceedings of the 35th Conference on Uncertainty in Artificial Intelligence