Skip to content
Back to Blog
1 min read

AI Drift Detection: Monitoring Model Performance Over Time

I wrote “AI Drift Detection: Monitoring Model Performance Over Time” to share practical, production-minded guidance on this topic.

Drift Detection Implementation

from dataclasses import dataclass
from typing import Dict, List
import numpy as np
from scipy import stats

@dataclass
class DriftAlert:
    drift_type: str
    severity: str
    metric: str
    baseline_value: float
    current_value: float
    p_value: float

class DriftDetector:
    def __init__(self, baseline_window_days: int = 30, detection_window_days: int = 1):
        self.baseline_window = baseline_window_days
        self.detection_window = detection_window_days
        self.baselines = {}

    def establish_baseline(self, metric_name: str, values: List[float]):
        """Establish baseline distribution for metric."""
        self.baselines[metric_name] = {
            "mean": np.mean(values),
            "std": np.std(values),
            "distribution": values,
            "percentiles": {
                "p5": np.percentile(values, 5),
                "p25": np.percentile(values, 25),
                "p50": np.percentile(values, 50),
                "p75": np.percentile(values, 75),
                "p95": np.percentile(values, 95)
            }
        }

    def detect_drift(self, metric_name: str, current_values: List[float]) -> DriftAlert:
        """Detect drift from baseline."""
        if metric_name not in self.baselines:
            return None

        baseline = self.baselines[metric_name]

        # Statistical tests
        # 1. Kolmogorov-Smirnov test for distribution shift
        ks_stat, ks_pvalue = stats.ks_2samp(baseline["distribution"], current_values)

        # 2. T-test for mean shift
        t_stat, t_pvalue = stats.ttest_ind(baseline["distribution"], current_values)

        # 3. Levene's test for variance change
        lev_stat, lev_pvalue = stats.levene(baseline["distribution"], current_values)

        # Determine drift type and severity
        drift_detected = False
        drift_type = None
        severity = None

        if ks_pvalue < 0.01:
            drift_detected = True
            drift_type = "distribution_shift"
            severity = "high" if ks_stat > 0.3 else "medium"

        elif t_pvalue < 0.05:
            drift_detected = True
            drift_type = "mean_shift"
            current_mean = np.mean(current_values)
            if abs(current_mean - baseline["mean"]) > 2 * baseline["std"]:
                severity = "high"
            else:
                severity = "medium"

        elif lev_pvalue < 0.05:
            drift_detected = True
            drift_type = "variance_change"
            severity = "low"

        if drift_detected:
            return DriftAlert(
                drift_type=drift_type,
                severity=severity,
                metric=metric_name,
                baseline_value=baseline["mean"],
                current_value=np.mean(current_values),
                p_value=min(ks_pvalue, t_pvalue, lev_pvalue)
            )

        return None

    def detect_concept_drift(self, predictions: List, actuals: List) -> Dict:
        """Detect concept drift through prediction accuracy changes."""
        # Calculate rolling accuracy
        window_size = 100
        accuracies = []

        for i in range(0, len(predictions) - window_size, window_size // 2):
            window_preds = predictions[i:i + window_size]
            window_actual = actuals[i:i + window_size]
            accuracy = sum(p == a for p, a in zip(window_preds, window_actual)) / window_size
            accuracies.append(accuracy)

        # Detect trend
        if len(accuracies) >= 5:
            trend = np.polyfit(range(len(accuracies)), accuracies, 1)[0]
            if trend < -0.01:  # Declining accuracy
                return {
                    "drift_detected": True,
                    "type": "concept_drift",
                    "trend": trend,
                    "recommendation": "Consider retraining or updating the model"
                }

        return {"drift_detected": False}

Proactive drift detection prevents silent AI performance degradation.\n\n## Takeaways\n\nAdd a concise, personal takeaway and recommended next steps here.\n

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.