Machine Learning Academy · leksjon

Konseptdrift: Når forholdet mellom X og Y endres

Deltakere vil skille datadrift fra konseptdrift ved hjelp av et tidsserieeksempel og forstå hvorfor datadrift ikke alltid innebærer redusert modellytelse.

Leksjon 2 av 413 trinn

Konseptdrift: Når forholdet mellom X og Y endres er en gratis leksjon i Machine Learning Academy på CoddyKit. Dette er leksjon 2 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Machine Learning Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Machine Learning Academy inneholder totalt 4 leksjoner.

Hva er konseptdrift?

Konseptdrift oppstår når forholdet mellom inndatafeatures X og målvariabelen Y endres over tid – selv om selve featurefordelingene forblir stabile. I svindeloppdagelse lærer svindlere hvilke transaksjoner som flagges, og endrer mønstrene sine, slik at transaksjoner som så svindelaktige ut i 2022, ser harmløse ut i 2024. Konseptet som læres (hvordan svindel ser ut) har endret seg, men featurefordelingene kan se uendrede ut. Derfor er konseptdrift vanskeligere å oppdage enn datadrift.

Datadrift versus konseptdrift: viktigste forskjell

Det avgjørende skillet er at datadrift er en endring i P(X) – fordelingen til inndatafeatures. Konseptdrift er en endring i P(Y|X) – det betingede forholdet mellom features og etiketter. Datadrift svekker ikke alltid modellens ytelse (hvis den nye fordelingen fortsatt ligger innenfor den innlærte beslutningsgrensen). Konseptdrift svekker alltid ytelsen fordi modellens innlærte avbildning fra X til Y nå er feil, uavhengig av om X ser lik ut.

import numpy as np
import pandas as pd

# Scenario: credit scoring model
# Feature: income. Label: 1 = defaults, 0 = repays

# Training period: incomes 30-50k correlate with defaults
np.random.seed(42)
train_income = np.random.normal(40000, 8000, 1000)
train_default = (train_income < 35000).astype(int)  # low income -> default

# Concept drift: inflation shifts threshold; now defaults start at 50k
prod_income = np.random.normal(40000, 8000, 500)  # SAME distribution (no data drift)
prod_default = (prod_income < 50000).astype(int)  # new relationship

print('Train default rate:', train_default.mean().round(3))
print('Prod default rate:', prod_default.mean().round(3))
print('Feature distribution same (no data drift).',
      'But Y|X relationship has changed (concept drift).')

Typer konseptdrift

Konseptdrift finnes i fire varianter. Plutselig drift: forholdet endres brått (for eksempel da COVID-19 endret forbruksmønstre over natten). Gradvis drift: det gamle konseptet forsvinner sakte, mens et nytt konsept oppstår (for eksempel en gradvis endring i definisjonen av søppelpost over flere måneder). Trinnvis drift: en kontinuerlig, langsom drift uten et tydelig bruddpunkt. Tilbakevendende drift: sesongmønstre – forholdet ved juletider er annerledes enn i juli, men juli kommer til slutt tilbake.

import numpy as np
import matplotlib.pyplot as plt

t = np.linspace(0, 100, 1000)

# Sudden drift: step function at t=50
sudden = np.where(t < 50, 0.8, 0.3)  # accuracy drops at t=50

# Gradual drift: linear transition
gradual = np.where(t < 40, 0.8,
          np.where(t > 60, 0.4,
          0.8 - (t - 40) * 0.02))

# Recurring drift: seasonal pattern
recurring = 0.6 + 0.2 * np.sin(2 * np.pi * t / 20)

for name, series in [('Sudden', sudden), ('Gradual', gradual), ('Recurring', recurring)]:
    print(f'{name} drift -- min acc: {series.min():.2f}, max: {series.max():.2f}')

Oppdage konseptdrift gjennom ytelsesovervåking

Det mest pålitelige signalet på konseptdrift er fallende modell­ytelse på merkede produksjonsdata. Følg med på det valgte målet Deres (accuracy, F1, AUC) i et rullerende vindu med nylige prediksjoner der fasitetiketter har blitt tilgjengelige. En fallende ytelsestrend som ikke forklares av datadrift (features ser like ut), er et sterkt bevis på konseptdrift. Dette krever en tilbakemeldingssløyfe: innsamling av sanne etiketter for produksjonsprediksjoner, noe som kan ta fra dager til måneder avhengig av oppgaven.

import numpy as np
import pandas as pd

np.random.seed(42)

# Simulate weekly model accuracy tracking
weekly_accuracy = [
    0.92, 0.91, 0.90, 0.89, 0.88,  # slight decline
    0.86, 0.83, 0.79, 0.74, 0.68,  # accelerating decline = concept drift
    0.65, 0.61
]

df = pd.DataFrame({'week': range(1, 13), 'accuracy': weekly_accuracy})
df['rolling_mean'] = df['accuracy'].rolling(3).mean()
df['alert'] = df['accuracy'] < 0.75  # threshold

print(df.to_string(index=False))
print('Weeks with alerts:', df[df['alert']]['week'].tolist())

Oppdage konseptdrift uten etiketter

Det tar lang tid å vente på fasitetiketter. Når etiketter kommer med høy forsinkelse, kan De bruke overvåking av prediksjonsfordelingen som et tidlig varsel. Hvis P(X) er stabil (ingen datadrift), men fordelingen av modellens predikerte etiketter endres betydelig, tyder dette på at det underliggende konseptet har endret seg. Hvis for eksempel andelen positive prediksjoner fra en binær klassifikator faller fra 30 % til 5 % uten at featurefordelingene endres, ser modellen sannsynligvis et annet forhold mellom features og den positive klassen.

import numpy as np

# Monitoring prediction distributions as a proxy for concept drift
# Period 1 (training distribution): ~30% positive predictions
period1_probs = np.random.beta(2, 5, 1000)  # right-skewed, ~30% above 0.5
period1_pos_rate = (period1_probs > 0.5).mean()

# Period 2 (concept drifted): only ~5% positive predictions (model confused)
period2_probs = np.random.beta(1, 15, 500)  # very right-skewed
period2_pos_rate = (period2_probs > 0.5).mean()

print(f'Period 1 positive rate: {period1_pos_rate:.2%}')
print(f'Period 2 positive rate: {period2_pos_rate:.2%}')
print(f'Rate drop: {(period1_pos_rate - period2_pos_rate):.2%}')
print('Possible concept drift detected!')

Ny trening med vinduer: tilpasning til konseptdrift

Den vanligste strategien for å håndtere konseptdrift er ny trening med vinduer: tren modellen regelmessig på nytt ved å bruke bare de nyeste N eksemplene og forkaste gamle data som gjenspeiler utdaterte mønstre. Et glidende vindu beholder de nyeste N eksemplene, mens et utvidende vindu bruker alle data med vekting etter aktualitet. Den optimale vindusstørrelsen avhenger av hvor raskt konseptet utvikler seg – domener i rask endring (finansmarkeder) trenger mindre vinduer enn domener i langsom endring (værvarsling).

import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

np.random.seed(42)

def simulate_concept_drift(n, t):
    X = np.random.normal(0, 1, (n, 2))
    # Decision boundary rotates over time
    y = ((X[:, 0] * np.cos(t) - X[:, 1] * np.sin(t)) > 0).astype(int)
    return X, y

# Full retrain vs sliding window retrain
for window_size in [100, 500, None]:  # None = all data
    all_X, all_y = [], []
    accs = []
    for t in np.linspace(0, np.pi, 10):
        X, y = simulate_concept_drift(200, t)
        all_X.append(X)
        all_y.append(y)
        if window_size:
            train_X = np.vstack(all_X[-window_size//200:])
            train_y = np.hstack(all_y[-window_size//200:])
        else:
            train_X = np.vstack(all_X)
            train_y = np.hstack(all_y)
        clf = LogisticRegression().fit(train_X, train_y)
        accs.append(clf.score(X, y))
    print(f'Window={window_size}: avg accuracy={np.mean(accs):.3f}')

Utvalgsvekting: redusere vekten av gamle data

I stedet for en fast grense for vinduet kan De tildele eksponentielt avtakende vekter til treningseksemplene, slik at nyere eksempler bidrar mer til modellen. Eksempler fra forrige uke får vekten 1.0, eksempler fra forrige måned får vekten 0.5, og eksempler fra seks måneder siden får vekten 0.1. Mange scikit-learn-estimatorer godtar en sample_weight-parameter i fit-metoden, noe som gjør dette enkelt å implementere uten å forkaste data.

import numpy as np
from sklearn.ensemble import GradientBoostingClassifier

np.random.seed(42)
# Simulate 1000 training examples collected over 10 weeks
X = np.random.normal(0, 1, (1000, 5))
y = (X[:, 0] + np.random.normal(0, 0.5, 1000) > 0).astype(int)
weeks_ago = np.linspace(10, 0, 1000)  # example 0 is oldest, 999 is newest

# Exponential decay: half-life of 3 weeks
half_life = 3.0
sample_weights = np.exp(-weeks_ago * np.log(2) / half_life)
sample_weights /= sample_weights.sum()

clf = GradientBoostingClassifier(n_estimators=100, random_state=42)
clf.fit(X, y, sample_weight=sample_weights * len(y))  # scale up
print('Model trained with recency-weighted samples.')
print('Weight ratio new/old:', round(sample_weights[-1] / sample_weights[0], 2))

CUSUM- og ADWIN-driftsdetektorer

Dedikerte algoritmer for oppdaging av konseptdrift gir mer velbegrunnede varsler. CUSUM (Cumulative Sum) oppdager endringer i gjennomsnittet til en sekvens ved å akkumulere avvik fra en referanseverdi. ADWIN (Adaptive Windowing) opprettholder et vindu med variabel lengde og gjør det mindre når en statistisk test oppdager en endring i fordelingen innenfor vinduet. Biblioteket river (tidligere scikit-multiflow) implementerer begge for strømmende data.

# Using the river library for streaming drift detection
# pip install river

# from river.drift import ADWIN

# adwin = ADWIN(delta=0.002)  # delta controls sensitivity
# error_sequence = [0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1]  # errors over time
#
# for i, error in enumerate(error_sequence):
#     adwin.update(error)
#     if adwin.drift_detected:
#         print(f'ADWIN detected drift at step {i}')
#         adwin = ADWIN(delta=0.002)  # reset detector

# Manual CUSUM example:
def cusum(errors, threshold=5, drift=0.01):
    cum_sum, alerts = 0, []
    for i, e in enumerate(errors):
        cum_sum = max(0, cum_sum + e - drift)
        if cum_sum > threshold:
            alerts.append(i)
            cum_sum = 0
    return alerts

errors = [0]*10 + [1]*15  # errors spike after step 10
print('CUSUM drift alerts at steps:', cusum(errors))

Konseptdrift versus sesongvariasjon

Sesongvariasjon er forutsigbar, periodisk variasjon (topper i julehandelen og reisemønstre om sommeren), mens konseptdrift er en uforutsigbar forskyvning i én retning. Et godt overvåkingssystem skiller mellom dem ved å undersøke historiske sesongmønstre. Hvis den nåværende fordelingen samsvarer med fordelingen fra samme periode i fjor, er det sannsynligvis sesongvariasjon og ikke drift. Inkluder tidsfunksjoner i modellen for å håndtere forutsigbar sesongvariasjon i stedet for å starte unødvendig ny trening.

import numpy as np
from scipy.stats import ks_2samp

np.random.seed(42)

# Training: July 2023 data
july_2023 = np.random.normal(100, 20, 1000)  # low activity (summer)

# Monitoring: July 2024 (seasonal -- same month last year)
july_2024 = np.random.normal(102, 21, 500)   # similar to last July

# Monitoring: December 2024 (seasonal spike -- same as Dec 2023)
dec_2024 = np.random.normal(180, 30, 500)    # high activity (Christmas)

stat_july, p_july = ks_2samp(july_2023, july_2024)
stat_dec, p_dec = ks_2samp(july_2023, dec_2024)

print(f'July 2024 vs July 2023: KS={stat_july:.3f} p={p_july:.3f} -> {"drift" if p_july < 0.05 else "seasonal OK"}')
print(f'Dec 2024 vs July 2023:  KS={stat_dec:.3f} p={p_dec:.3f} -> Expected seasonal shift')

Utarbeide en responsplan for konseptdrift

Håndter konseptdrift med en trinnvis plan. Nivå 1 (tidlig varsel): varsle om endringer i prediksjonsfordelingen uten å vente på etiketter. Nivå 2 (bekreftelse): bekreft at ytelsesfallet overstiger 5 % relativt når etikettene blir tilgjengelige. Nivå 3 (handling): start automatisk ny trening med vindu, og bruk tidsstempelet for driftsoppdagelsen som grense for vinduet. Nivå 4 (eskalering): eskaler til en data scientist for gjennomgang av feature-engineeringen hvis ny trening ikke gjenoppretter ytelsen.

def concept_drift_response(current_accuracy, baseline_accuracy,
                            data_drift_detected, prediction_rate_shift):
    relative_drop = (baseline_accuracy - current_accuracy) / baseline_accuracy

    if relative_drop > 0.10:
        return ('TIER 4 ESCALATION: >10% accuracy drop. '
                'Manual feature engineering review required.')
    elif relative_drop > 0.05:
        return ('TIER 3 ACTION: 5-10% accuracy drop. '
                'Trigger windowed retraining immediately.')
    elif data_drift_detected or prediction_rate_shift > 0.15:
        return ('TIER 2 MONITOR: Early warning signals present. '
                'Increase monitoring to daily. Queue retraining.')
    else:
        return 'TIER 1 OK: No significant concept drift detected.'

print(concept_drift_response(0.84, 0.92, False, 0.05))   # TIER 3
print(concept_drift_response(0.91, 0.92, True, 0.18))    # TIER 2
print(concept_drift_response(0.91, 0.92, False, 0.03))   # TIER 1

Ensemblemodeller og motstandsdyktighet mot konseptdrift

Ensemblemetoder som random forests og gradient boosting kan skjule konseptdrift lenger enn enkeltmodeller fordi mangfoldet deres gjør dem mindre følsomme for endringer i fordelingen til én enkelt feature. Denne motstandsdyktigheten er imidlertid et tveegget sverd: modellen svekkes saktere og mer ubemerket. Overvåk uenighetsraten mellom de enkelte trærne i en skog – når trærne i økende grad er uenige om prediksjonene, er det et tidlig signal om at konseptet endrer seg og at ensemblet har problemer med å nå enighet.

import numpy as np
from sklearn.ensemble import RandomForestClassifier

# Measure inter-tree disagreement on current data as drift signal
def inter_tree_disagreement(forest, X):
    predictions = np.array([tree.predict(X) for tree in forest.estimators_])
    # Fraction of pairs of trees that disagree per sample, averaged over samples
    n_trees = len(forest.estimators_)
    disagreement_per_sample = []
    for i in range(X.shape[0]):
        preds = predictions[:, i]
        disagree = (preds != preds[0]).sum() / n_trees
        disagreement_per_sample.append(disagree)
    return np.mean(disagreement_per_sample)

# Higher disagreement = more concept drift
# print(inter_tree_disagreement(model, X_current))

Kort kontroll

Test forståelsen Deres av begrepene innen Machine Learning with Python fra denne leksjonen.

Oppsummering av leksjonen

I denne leksjonen lærte De at konseptdrift er en endring i P(Y|X) – avbildningen fra features til etiketter – som kan oppstå selv når featurefordelingene ser stabile ut, at fallende modell­ytelse på merkede produksjonsdata er det avgjørende signalet på konseptdrift, og at ny trening med vinduer og utvalgsvekting er de viktigste tilpasningsstrategiene for å holde modeller oppdaterte når konsepter utvikler seg. Deretter skal vi se på overvåking av prediksjonsfordelinger og konfidensskårer som et tidlig varslingssystem når fasitetiketter ennå ikke er tilgjengelige.

Gratis å komme i gang

Lær deg Python med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
30
Leksjoner
120

Ofte stilte spørsmål

Er leksjonen «Konseptdrift: Når forholdet mellom X og Y endres» gratis?

Ja – hele teksten i «Konseptdrift: Når forholdet mellom X og Y endres» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av Machine Learning Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i Machine Learning Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «Konseptdrift: Når forholdet mellom X og Y endres»?

Deltakere vil skille datadrift fra konseptdrift ved hjelp av et tidsserieeksempel og forstå hvorfor datadrift ikke alltid innebærer redusert modellytelse. Du øver på Machine Learning Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Machine Learning Academy?

Ingen tidligere erfaring er nødvendig. Machine Learning Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 2 av 4.

Hvor lang tid tar leksjonen «Konseptdrift: Når forholdet mellom X og Y endres»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Machine Learning Academy-leksjonen?

Ja. Alle Machine Learning Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. Datadrift: Endringer i egenskapsfordelinger over tid
  2. Konseptdrift: Når forholdet mellom X og Y endres
  3. Overvåke prediksjonsfordelinger og konfidensskårer
  4. Bygging av en pipeline for driftsvarsler med Evidently AI
← Tilbake til Machine Learning Academy