Data drift detection — PSI, KS
এই পাঠে যা শিখবেন
- PSI computation + thresholds
- KS test — when, how
- Chi-square for categorical
- False positive control — window size, seasonality
১ · Drift types
- Covariate drift / data drift: $P(X)$ changes; $P(y|X)$ same.
- Concept drift: $P(y|X)$ changes (Lesson 26).
- Label drift / prior shift: $P(y)$ changes.
২ · PSI — Population Stability Index
$$ \text{PSI} = \sum_i (a_i - b_i) \ln\left(\frac{a_i}{b_i}\right) $$
যেখানে $a_i$ = baseline-এ bin $i$ এর fraction, $b_i$ = current-এ bin $i$।
Thresholds:
- PSI < 0.1 — no significant change.
- 0.1 ≤ PSI < 0.25 — moderate, watch.
- PSI ≥ 0.25 — significant, alert.
৩ · PSI Python implementation
import numpy as np
import pandas as pd
def psi(baseline: np.ndarray, current: np.ndarray, n_bins: int = 10) -> float:
"""Compute Population Stability Index."""
# Bin edges from baseline (quantile-based)
breaks = np.unique(np.quantile(baseline, np.linspace(0, 1, n_bins + 1)))
if len(breaks) < 2:
return 0.0
base_counts = np.histogram(baseline, bins=breaks)[0].astype(float)
curr_counts = np.histogram(current, bins=breaks)[0].astype(float)
# Add small epsilon — avoid log(0)
eps = 1e-6
base_pct = (base_counts + eps) / (base_counts.sum() + eps * len(base_counts))
curr_pct = (curr_counts + eps) / (curr_counts.sum() + eps * len(curr_counts))
return float(((curr_pct - base_pct) * np.log(curr_pct / base_pct)).sum())
# Usage
baseline_age = np.random.normal(35, 10, 10_000) # training data
current_age = np.random.normal(38, 12, 5_000) # last 7 days production
p = psi(baseline_age, current_age)
print(f"PSI: {p:.3f}")
if p > 0.25:
print("⚠️ Significant drift")
elif p > 0.1:
print("👀 Moderate drift, watch")
else:
print("✓ Stable")
৪ · KS test — Kolmogorov-Smirnov
Continuous distribution-এর CDF-difference.
$$ D = \sup_x |F_1(x) - F_2(x)| $$
- scipy
ks_2samp— direct. - p-value < 0.05 — significantly different.
- Sensitivity to large samples — even small drift "significant" statistically.
৫ · Chi-square — categorical
Categorical feature distribution compare.
- $\chi^2 = \sum (O - E)^2 / E$।
- Each unique category — observed vs expected.
- scipy
chi2_contingency.
৬ · False positive control
- Window size: too small → noisy; too large → slow detection. Typical: 7-day window.
- Seasonality: Friday vs Monday traffic ভিন্ন। Compare same-day-of-week.
- Multiple comparisons: 50 features × daily check = ~2.5 false alarm/day at p=0.05. Bonferroni correction.
- Practical: PSI threshold prefer over p-value (less sample-size sensitive).
৭ · Drift types — covariate vs label
Covariate drift sole-এ accuracy decay না হতে পারে — যদি conditional $P(y|X)$ same থাকে। Concept drift এর সাথে কম্বাইনেশনে damaging.
- Important features-এ drift — high-impact.
- Low-importance features-এ drift — sometimes ignorable.
- Feature importance ranking — multi-feature drift prioritization.
ভাবনার প্রশ্ন
প্র ০১"Seasonality vs drift — distinguish কীভাবে?"
Seasonal pattern drift মতো দেখায় but recurring.
Examples:
- Daraz Eid sale — purchase distribution massive shift, expected.
- Friday Jumma — Pathao demand spike আসে।
- Monsoon — food delivery surge.
Strategies:
- Compare year-over-year: Eid 2025 vs Eid 2024 — drift if বদল।
- Compare same-day-of-week: Friday vs last Friday.
- Detrending: remove seasonal component; check residual drift.
- Multiple baselines: per-season baseline maintain.
- Calendar-aware threshold: Eid week relax PSI threshold.
BD calendar-specific:
- Eid (2× yearly), Pohela Boishakh, Victory Day, Independence Day, Durga Puja, Christmas.
- Each has distinct distribution. Calendar-aware monitoring built-in.
মূল উপলব্ধি: Naive drift detection seasonal-tag confused. Calendar-context essential. BD-specific events care.
প্র ০২"Window size choice — 1 day, 7 day, 30 day?"
Window size = sensitivity vs noise trade-off.
1 day:
- Pros: fast detection.
- Cons: noisy, weekly variation captured.
- Use: very sensitive features (fraud signal).
7 day:
- Pros: weekly cycle averaged, less noise.
- Cons: 1-week lag.
- Use: most production cases — sweet spot.
30 day:
- Pros: very stable.
- Cons: slow detection.
- Use: long-term trend trackingে।
Multiple windows:
- 1-day for quick alert.
- 7-day for confirmed trend.
- 30-day for trend dashboard.
Sliding vs tumbling:
- Sliding: rolling 7 days, daily compute.
- Tumbling: discrete weeks Sat-Fri.
- Sliding more common, smoother.
মূল উপলব্ধি: Default 7-day sliding. Sensitive add 1-day. Strategic add 30-day. Single window не покрывает all need.
প্র ০৩"Covariate drift detected, কিন্তু accuracy ঠিক — retrain করব?"
Common confusion.
Scenario:
- Feature distribution shifted.
- Ground truth available — accuracy stable.
- Should retrain?
Considerations:
Don't retrain:
- Accuracy stable — model robust to shift.
- Drift may revert (seasonal).
- Retraining cost > benefit.
Do retrain:
- Drift in important feature consistently.
- Accuracy stable but borderline.
- "Future-proofing" — drift growing.
- New data improves model fundamentally.
Better question:
- "Is drift growing or stabilizing?"
- "Has subgroup performance shifted?" (overall stable can hide).
- "Concept drift might follow covariate drift."
Cost analysis:
- Retraining cost (compute + engineer).
- Risk of new model regression.
- "Don't fix what works".
Bangladesh fintech reality:
- Quarterly scheduled retrain — drift handled by routine.
- Mid-quarter drift alert — investigate, retrain only if pattern persists.
মূল উপলব্ধি: Drift alert ≠ automatic retrain trigger. Investigate first. Retraining-this is risk-reward decision. Routine schedule + emergency retrain hybrid.
প্র ০৪"50 feature daily PSI = noisy — practical multi-feature alerting?"
Multiple comparisons issue.
Problem:
- 50 features × daily check = many alerts.
- Some "drift" naturally; alert fatigue.
Strategies:
(১) Feature importance weight:
- Top-10 features only alert; rest digest.
- SHAP-based importance from training.
(২) Aggregate metric:
- "Number of features in drift" daily count.
- Sudden spike alert.
(৩) Bonferroni correction:
- α = 0.05 / 50 = 0.001 effective.
- Stricter threshold; fewer false positives.
(৪) Hierarchical alert:
- Single critical feature drift → page.
- 3+ feature drift → Slack.
- Less critical → daily digest report.
(৫) Concept-drift-only alert:
- Covariate drift digest only.
- Concept drift (accuracy drop) → escalate.
BD context:
- Mid-size fintech 30-50 features common.
- Top-10 + aggregate strategy practical.
মূল উপলব্ধি: Feature drift = pruning + prioritization problem. All-feature alert noise; top-feature + aggregate signal-to-noise ভাল।
অনুশীলন
- Compute: উপরের PSI function নিজের sample data-তে চালান। Drift inject করুন, threshold trigger.
Baseline mean=35; current mean=45 — PSI ~0.3-0.5. Threshold trigger.
- KS test: scipy.stats.ks_2samp ব্যবহার করুন; PSI-এর সাথে compare.
from scipy.stats import ks_2samp; stat, p = ks_2samp(baseline, current). Same drift PSI ও KS দু'টোতেই ধরা পড়ে। - চিন্তা: Pathao surge model — top 5 features কী হবে; PSI threshold কী set করবেন?
- Driver count in zone (last hour) — PSI > 0.2 alert (sensitive).
- Avg ride duration — PSI > 0.25 alert.
- Time of day (categorical) — Chi-square seasonal aware.
- Weather — PSI > 0.3 (high seasonality natural).
- Day of week — exclude (seasonality dominant).