39.3 Független értékelés és hibaelemzés

Tesztfegyelem: a teszteredmény megtekintése után végzett modell-, küszöb- vagy feature-választás a tesztet fejlesztési adathalmazzá alakítja. Ilyenkor új, érintetlen vagy későbbi időablak szükséges a végső független értékeléshez.

39.3.1 Cél és konkrét helyzet

A Feature-pipeline, baseline és tanulás alfejezetben a befagyasztott spliten, foldon belüli preprocessinggel és kontrollált modellkereséssel elkészült a Northstar késésmodell aktuális jelöltje: model_v3. Most nem fejlesztünk tovább. Egyetlen, előre rögzített tesztprotokollt alkalmazunk a félretett tesztablakra, és visszakereshető értékelési jelentést készítünk.

A bemenet:

A megfigyelési egység egy rendelés, a predikció pillanata az order_ts. A teszt csak a cutoff utáni rendeléseket tartalmazza, és a generált adat végére a címkék teljesen megfigyeltek, ezért nincs cenzorálás ebben a kiértékelésben.

A döntési cél: rendeléskor riasszunk-e a várhatóan 7 napot meghaladó kézbesítésre. A költségarányból levezetett, a teszt kiértékelése előtt befagyasztott küszöb t*=0,333t^* = 0{,}333. Előzetes becslésünk a tanítási cross-validation alapján: PR-AUC 0,46, ROC-AUC 0,71; a teszten 0,40–0,52 közötti PR-AUC-t és 0,66–0,75 közötti ROC-AUC-t várunk. A lentebb közölt konkrét értékek szemléltető számok, nem a labor valódi futtatásából származó mérések; a laborban a manifest és az eredményjegyzék az ellenőrzési alap.

39.3.2 Fogalmi magyarázat

39.3.2.1 Test freeze

A tesztbefagyasztás (test freeze) azt jelenti, hogy a teszt kiértékelése előtt minden, a döntést befolyásoló elemet verzióhoz kötünk: a splitet, a feature-definíciókat, a modellt, a küszöböt, a metrikákat és az intervallumszámítás módját. A teszt eredményének ismeretében a modellt már nem tervezzük át. Ha mégis változtatunk, akkor az új modellhez új, független bizonyíték kell.

A technikai megvalósítás itt nem a modell újbóli betöltése, hanem a már elmentett predikciók, a split manifest és a config hash-ének ellenőrzése. A script hibát dob, ha a predikciós parquet split="test" sorainak order_id halmaza nem egyezik a manifest test_order_ids halmazával.

39.3.2.2 PR és ROC

A zavaró mátrix (confusion matrix) rögzített küszöbnél négy számot ad:

Predikált 0 Predikált 1
Tényleges 0 TN FP
Tényleges 1 FN TP

A két alapmetrika:

Precision=TPTP+FP,Recall=TPR=TPTP+FN.\text{Precision} = \frac{TP}{TP+FP}, \qquad \text{Recall} = \text{TPR} = \frac{TP}{TP+FN}.

A ROC-görbe az FPR–TPR síkon fut, miközben a küszöböt változtatjuk; a ROC-AUC annak a valószínűsége, hogy egy véletlen pozitív rendelés nagyobb pontszámot kap, mint egy véletlen negatív. A PR-görbe a recall–precision síkon fut; a PR-AUC (average precision, AP) a görbe alatti terület. Amikor a pozitív osztály ritkább, a ROC-AUC magas lehet pusztán a sok negatív mintából; ilyenkor a PR-AUC jobban bünteti a hamis riasztásokat. A Northstar projektben a késések aránya nem extrém ritka, de a döntési cél a késések megtalálása, ezért a PR-AUC az elsődleges görbemérték.

Kis kézi kontroll. Legyen 6 tesztrendelés:

A prediktált osztály: [0,0,1,0,1,1][0,0,1,0,1,1]. Ebből TP=3TP=3, FP=0FP=0, FN=0FN=0, TN=3TN=3, tehát precision =3/3=1=3/3=1, recall =3/3=1=3/3=1. Mivel minden pozitív pontszáma nagyobb minden negatívénál, a ROC-AUC és a PR-AUC is 1.

39.3.2.3 Calibration

A kalibráció azt állítja, hogy a pip_i pontszám értelmezhető-e valószínűségként: ha a modell 0,30 körüli pontszámot ad sok rendelésnek, akkor ezek között valóban közel 30% a késő kézbesítés. A reliabilitási diagram a pontszám szerinti binekben ábrázolja a bin átlagos előre jelzett valószínűsége és a megfigyelt pozitív arány közötti eltérést. A Brier score mindkét irányú eltérést bünteti:

B=1n∑i=1n(pi−yi)2,B = \frac{1}{n}\sum_{i=1}^{n}(p_i-y_i)^2,

ahol pip_i shape (n,)(n,), yi∈{0,1}y_i\in\{0,1\}. A lehetséges érték [0,1][0,1], alacsonyabb jobb. A konstans baseline B0=y‾(1−y‾)B_0 = \bar y(1-\bar y), ahol y‾\bar y a pozitív arány. Például 29% pozitív aránynál B0=0,29⋅0,71=0,2059B_0 = 0{,}29\cdot 0{,}71 = 0{,}2059. Ha a modell Brier-értéke 0,187, akkor jobb a konstansnál, de a javulás szerény.

39.3.2.4 Thresholds

A döntési küszöb az üzleti költségarányból származik, nem a teszt adatból optimalizáljuk. Legyen CFPC_{FP} a hamis riasztás, CFNC_{FN} a kimaradt késés átlagos költsége. Ha a pp valószínűségű késésre nem riasztunk, a várható költség pCFNp C_{FN}; ha riasztunk, (1−p)CFP(1-p)C_{FP}. A riasztás akkor olcsóbb, ha

pCFN>(1−p)CFP,p C_{FN} > (1-p)C_{FP},

azaz

p>t*=CFPCFP+CFN.p > t^* = \frac{C_{FP}}{C_{FP}+C_{FN}}.

A projekt configja CFP=4C_{FP}=4, CFN=8C_{FN}=8 egységet rögzít, tehát t*=4/12=0,333t^* = 4/12 = 0{,}333. A képlet feltételezi a lineáris, konstans költségeket; ez modell, nem tényleges pénzügyi állítás. A küszöböt az F2-mértékkel is jellemezzük, mert a kimaradt késés fontosabb, mint a hamis riasztás:

F2=5P⋅R4P+R,F_2 = 5\frac{P \cdot R}{4P + R},

ahol PP a precision, RR a recall.

39.3.2.5 Slice

A szeletelt értékelés (slice evaluation) ugyanazt a befagyasztott modellt és küszöböt a teszt előre megadott részhalmazain méri: segment, region, priority_flag. Nem tanítunk szeletenként új modellt. A cél annak felderítése, hogy a globális modell nem egyetlen ügyfélkörre optimalizált-e. A kis szeletekben a metrika mintavételi bizonytalansága nagy, ezért mindig a mintanagyságot és az intervallumot együtt közöljük. A legrosszabb szelet alapján utólag módosított modellhez szintén új független értékelés kell.

39.3.2.6 Uncertainty

A tesztmetrika egy mintából becsült szám, ezért nem elég a pontérték. A rendelésszintű bootstrap 1000 ismétlésben, rögzített seed mellett, a teszt sorok visszatevéses újramintavételezésével ad percentilis 95%-os konfidenciaintervallumot. A mintavételi egység itt a rendelés; ha ugyanazon ügyfél több tesztrendelése is szerepel, az ügyfélen belüli korreláció miatt ez az intervallum optimista lehet. Érvényességi korlátként később visszatérünk rá. A ritka szeletek esetén a binomiális arányokra a Wilson-intervallumot használjuk:

p̂+z22n±zp̂(1−p̂)n+z24n21+z2n,\frac{\hat p + \frac{z^2}{2n} \pm z\sqrt{\frac{\hat p(1-\hat p)}{n}+\frac{z^2}{4n^2}}}{1+\frac{z^2}{n}},

ahol p̂\hat p az arány, nn a nevezőben lévő megfigyelésszám, z=1,96z=1{,}96.

39.3.3 Teljes minimális munkapélda

Az értékelő script a projektgyökér evaluate_model.py fájlja. Nem tölti be a modellt, hanem a batch predikció kimenetét ellenőrzi a split manifesttel szemben, majd kiszámítja a metrikákat, kalibrációs bineket, szeleteket és CI-ket.

# evaluate_model.py — befagyasztott tesztprotokoll
import argparse
import hashlib
import json
from datetime import datetime, timezone
from pathlib import Path

import numpy as np
import pandas as pd
from sklearn.metrics import (
    average_precision_score,
    brier_score_loss,
    fbeta_score,
    precision_score,
    recall_score,
    roc_auc_score,
)


def wilson_ci(k: int, n: int, z: float = 1.96):
    if n == 0:
        return (np.nan, np.nan)
    p_hat = k / n
    denom = 1 + z * z / n
    center = (p_hat + z * z / (2 * n)) / denom
    margin = z * np.sqrt(p_hat * (1 - p_hat) / n + z * z / (4 * n * n)) / denom
    return (max(0.0, center - margin), min(1.0, center + margin))


def bootstrap_ci(metric_fn, y, p, rng, n_repl=1000):
    n = len(y)
    idx = np.arange(n)
    values = []
    for _ in range(n_repl):
        sample_idx = rng.choice(idx, size=n, replace=True)
        y_s, p_s = y[sample_idx], p[sample_idx]
        if len(np.unique(y_s)) < 2:
            continue
        values.append(metric_fn(y_s, p_s))
    arr = np.asarray(values)
    return float(np.quantile(arr, 0.025)), float(np.quantile(arr, 0.975))


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--config", type=Path, required=True)
    ap.add_argument("--predictions", type=Path, required=True)
    ap.add_argument("--split-manifest", type=Path, required=True)
    ap.add_argument("--report", type=Path, required=True)
    args = ap.parse_args()

    cfg = json.loads(args.config.read_text(encoding="utf-8"))
    pred = pd.read_parquet(args.predictions)
    split_manifest = json.loads(args.split_manifest.read_text(encoding="utf-8"))

    test_ids_expected = set(split_manifest["test_order_ids"])
    test_pred = pred.loc[pred["split"] == "test"].copy()
    test_ids_actual = set(test_pred["order_id"])
    if test_ids_expected != test_ids_actual:
        raise SystemExit("Split manifest nem egyezik a tesztpredikciókkal.")

    y = test_pred["target_late"].to_numpy()
    p = test_pred["score_late"].to_numpy()
    threshold = float(cfg["decision_threshold"])
    y_hat = (p >= threshold).astype(int)

    rng = np.random.default_rng(cfg["bootstrap_seed"])
    roc_low, roc_high = bootstrap_ci(roc_auc_score, y, p, rng)
    pr_low, pr_high = bootstrap_ci(average_precision_score, y, p, rng)

    precision = precision_score(y, y_hat)
    recall = recall_score(y, y_hat)
    f2 = fbeta_score(y, y_hat, beta=2)
    fp = int((y_hat == 1).sum() - (y[y_hat == 1] == 1).sum())
    tn = int((y == 0).sum() - ((y == 0) & (y_hat == 0)).sum())
    fpr = fp / (fp + tn) if fp + tn > 0 else np.nan
    p_low, p_high = wilson_ci(int((y[y_hat == 1] == 1).sum()), int((y_hat == 1).sum()))
    r_low, r_high = wilson_ci(int((y[y_hat == 1] == 1).sum()), int(y.sum()))

    bins = np.linspace(0.0, 1.0, 11)
    bin_idx = np.digitize(p, bins) - 1
    cal_rows = []
    for i in range(10):
        mask = bin_idx == i
        n_bin = int(mask.sum())
        if n_bin == 0:
            continue
        cal_rows.append({
            "bin": f"[{bins[i]:.1f},{bins[i+1]:.1f})",
            "n": n_bin,
            "mean_predicted": round(float(p[mask].mean()), 3),
            "observed_rate": round(float(y[mask].mean()), 3),
        })

    slice_rows = []
    for slice_name in cfg["slices"]:
        for key, group in test_pred.groupby(slice_name):
            y_s = group["target_late"].to_numpy()
            p_s = group["score_late"].to_numpy()
            y_s_hat = (p_s >= threshold).astype(int)
            slice_rows.append({
                "slice": f"{slice_name}={key}",
                "n": len(group),
                "precision": round(float(precision_score(y_s, y_s_hat)), 3),
                "recall": round(float(recall_score(y_s, y_s_hat)), 3),
            })

    report = {
        "evaluation_timestamp": datetime.now(timezone.utc).isoformat(),
        "decision_threshold": threshold,
        "config_sha256": hashlib.sha256(args.config.read_bytes()).hexdigest(),
        "n_test": len(test_pred),
        "positive_rate": round(float(y.mean()), 3),
        "metrics": {
            "roc_auc": round(float(roc_auc_score(y, p)), 3),
            "roc_auc_ci95": [round(roc_low, 3), round(roc_high, 3)],
            "pr_auc": round(float(average_precision_score(y, p)), 3),
            "pr_auc_ci95": [round(pr_low, 3), round(pr_high, 3)],
            "brier": round(float(brier_score_loss(y, p)), 3),
            "precision_at_threshold": round(float(precision), 3),
            "precision_ci95": [round(p_low, 3), round(p_high, 3)],
            "recall_at_threshold": round(float(recall), 3),
            "recall_ci95": [round(r_low, 3), round(r_high, 3)],
            "f2_at_threshold": round(float(f2), 3),
            "false_positive_rate": round(float(fpr), 3),
        },
        "calibration_bins": cal_rows,
        "slices": slice_rows,
    }

    args.report.write_text(json.dumps(report, indent=2, ensure_ascii=False), encoding="utf-8")
    print(json.dumps(report["metrics"], indent=2))


if __name__ == "__main__":
    main()

A befagyasztott konfiguráció:

{
  "decision_threshold": 0.333,
  "threshold_rationale": "C_FP=4, C_FN=8, t*=4/(4+8)",
  "slices": ["segment", "region", "priority_flag"],
  "bootstrap_replications": 1000,
  "bootstrap_seed": 20261020
}

Futtatás a projektgyökérből:

# Linux/macOS, munkakönyvtár: ~/northstar_lab
python evaluate_model.py \
  --config config/evaluation_config.json \
  --predictions artifacts/test_predictions_v3.parquet \
  --split-manifest artifacts/split.json \
  --report artifacts/evaluation_report.json

Windows PowerShellben a sorvégi backtickkel, a munkakönyvtár azonos.

A parancs kimenete szemléltető, nem tényleges futtatásból származik:

roc_auc: 0.712, roc_auc_ci95: [0.664, 0.757]
pr_auc: 0.418, pr_auc_ci95: [0.351, 0.478]
brier: 0.187
precision_at_threshold: 0.247, recall_at_threshold: 0.621
f2_at_threshold: 0.478, false_positive_rate: 0.392

A jelentést git commit is rögzíti:

# Linux/macOS
git add artifacts/evaluation_report.json config/evaluation_config.json
git commit -m "Evaluate frozen model_v3 on held-out test"

39.3.4 Eredmény értelmezése

A fenti szemléltető futásban a teszt 814 rendelést tartalmaz, a pozitív arány 0,29. A ROC-AUC 0,712 azt jelenti: ha véletlenszerűen kiválasztunk egy késő és egy nem késő rendelést, a modell 71,2% eséllyel ad nagyobb pontszámot a későnek. A PR-AUC 0,418 jóval szerényebb; a görbe a 0,29-es pozitív arány miatt nem éri el a 1-et. A Brier 0,187 alatta van a konstans baseline 0,2059-nek, tehát a modell ad némi valószínűségi értéket, de a javulás nem drámai.

A befagyasztott 0,333-as küszöbnél a modell a valódi késések 62,1%-át találja meg, de a riasztásainak csak 24,7%-a helyes. Az F2 0,478 a recall nagyobb súlyával mondja ugyanezt. A hamis riasztási arány 0,392: tíz nem késő rendelésből közel négyre riasztana a rendszer. Ez a döntési keretben elfogadható lehet, mert a kimaradt késés kétszer drágább, mint a hamis riasztás, de az értékelési jelentésben expliciten szerepel.

A kalibrációs binek (szemléltető részlet):

bin n mean_predicted observed_rate
[0.1,0.2) 63 0.16 0.11
[0.3,0.4) 97 0.35 0.31
[0.5,0.6) 112 0.55 0.60
[0.8,0.9) 71 0.84 0.80

A középső binek közel vannak az átlóhoz; a nagyon alacsony binnél a megfigyelt arány 0,11, míg az átlagos pontszám 0,16, tehát a modell ott kissé túlbecsül. A [0,5;0,6)[0{,}5;0{,}6) binben alulbecsül: 0,55-öt mond, de 0,60 a megfigyelt arány. A legmagasabb bin jól kalibrált.

A szeletek (szemléltető, kiragadott sorok):

slice n precision recall
segment=business 248 0.296 0.688
segment=consumer 566 0.221 0.584
region=north 271 0.238 0.602
priority_flag=1 194 0.310 0.714

A business szegmensben magasabb a recall; ez önmagában még nem jelenti, hogy a modell a business ügyfelekre „jobb”, mert a pozitív arány és a szegmensbeli döntési küszöb is eltérhet. A szelet csak kérdést tesz fel, nem igazol állítást.

Az intervallumok fontosak: a recall Wilson-CI-je a szemléltető adatban kb. 0,55–0,69, a precisioné 0,18–0,33. A döntéshez ez a bizonytalansági sáv szükséges. Kevés pozitív esetnél a sáv még szélesebb lenne; ez visszhangozza a LLM mint sztochasztikus komponens tanulságát.

39.3.5 Feladatok

  1. Értelmezés. Egy kolléga azt írja a jelentésben: „A teszt ROC-AUC 0,71, tehát a modell az esetek 71%-ában helyesen dönt.” Mi a hiba ebben az állításban? Fogalmazd meg, mit mér a ROC-AUC, és melyik metrika adná a helyes osztályozási arányt a rögzített küszöbön.

  2. Megvalósítás. Írj manual_pr_auc(y_true, y_score) függvényt, amely a precision_recall_curve kimenetéből trapéz integrállal számítja a PR-AUC-t, és hasonlítsd össze az average_precision_score értékével. Ellenőrizd a 6 soros kézi példán: y=[0,0,1,0,1,1]y=[0,0,1,0,1,1], p=[0,1,0,2,0,6,0,4,0,7,0,9]p=[0{,}1,0{,}2,0{,}6,0{,}4,0{,}7,0{,}9].

  3. Hibakeresés. A következő kód a küszöböt a tesztadaton optimalizálja, majd ugyanazon a teszten F2-t számol:

from sklearn.metrics import fbeta_score
import numpy as np

best_f2, best_t = -1, 0.5
for t in np.linspace(0.05, 0.95, 100):
    f2 = fbeta_score(y_test, (p_test >= t).astype(int), beta=2)
    if f2 > best_f2:
        best_f2, best_t = f2, t
print("t=", best_t, "F2=", best_f2)

Miért nem használható ez az értékelés a modell jóváhagyásához? Írd át a protokollt úgy, hogy a küszöb a befagyasztott configból jöjjön.

  1. Megváltozott feltétel. Az üzlet döntése szerint a kimaradt késés költsége ötszörösére nő: CFN=40C_{FN}=40, CFP=4C_{FP}=4 marad. Számold ki az új befagyasztott küszöböt. Milyen irányba mozdul várhatóan a recall, a precision és a hamis riasztási arány? Kell-e új modellt tanítani, és kell-e új független teszt a pontszámokhoz?

  2. Kalibráció. A modell Brier-értéke 0,187, a teszt pozitív aránya 0,29. Számold ki a konstans baseline Brier-értéket, és magyarázd, hogy a Brier miért nem tisztán kalibrációs mérőszám.

39.3.6 Megoldások és indoklás

  1. A ROC-AUC nem az egyedi osztályozások pontossága, hanem a rangsorolási képesség mutatója: annak a valószínűsége, hogy a modell egy véletlen pozitív rendelést nagyobb pontszámmal lát el, mint egy véletlen negatívat. A rögzített küszöbnél a helyes osztályozási arányt az accuracy adná: (TP+TN)/(TP+TN+FP+FN)(TP+TN)/(TP+TN+FP+FN). A fenti szemléltető számmal ez 1−(hiba)1 - \text{(hiba)}, és általában magasabb is lehet 0,71-nél; az AUC-nak nincs ilyen egyedi értelmezése. Ha a kolléga 71%-os „esélyt” akar írni, akkor azt mondhatja, hogy a rangsorolási valószínűség 71%.

  2. A precision_recall_curve a precision és recall vektorokat adja; a recall a sklearn kimenetében monoton növekvő, így a trapéz integrál a precision–recall síkon:

import numpy as np
from sklearn.metrics import average_precision_score, precision_recall_curve

def manual_pr_auc(y_true, y_score):
    precision, recall, _ = precision_recall_curve(y_true, y_score)
    return float(np.trapezoid(precision, recall))

y = [0, 0, 1, 0, 1, 1]
p = [0.1, 0.2, 0.6, 0.4, 0.7, 0.9]
print(manual_pr_auc(y, p), average_precision_score(y, p))

Mindkét függvény 1,0-t ad a példán, mert minden pozitív pontszáma a negatívok fölött van. A np.trapezoid NumPy 2.x-ben szerepel; korábbi verzióban np.trapz. Az average_precision_score numerikusan stabilabb; valódi adaton kis eltérés lehet, de az eltérés 0,001 alatt marad.

  1. A hiba a teszt újrahasznosítása. Amikor a küszöböt a tesztadaton belül keressük maximális F2-re, majd ugyanazon a teszten mérjük az F2-t, a mért érték felfelé torzított: a tesztből kiválasztott küszöb a zajhoz is illeszkedik, ezért a jelentés optimista. A javított protokoll a configból olvas be egy rögzített küszöböt, és csak arra számolja a metrikákat:
threshold = float(cfg["decision_threshold"])
y_hat = (p_test >= threshold).astype(int)
f2 = fbeta_score(y_test, y_hat, beta=2)

Ha a küszöböt mégis optimalizálni akarjuk, azt a tanító/validációs foldokon, a teszt kiértékelése előtt kell megtenni, és a választott értéket a configba kell fagyasztani.

  1. Az új küszöb t*=4/(4+40)=4/44≈0,0909t^* = 4/(4+40) = 4/44 \approx 0{,}0909. Az alacsonyabb küszöb miatt a modell több rendelést riaszt pozitívnak, ezért a recall várhatóan nő, a precision csökken, és a hamis riasztási arány nő. A modell pontszámai változatlanok, tehát a paraméterek újratanítása nem szükséges. A pontszámokat ugyanazon befagyasztott teszten újra lehet értékelni, mert a küszöböt az üzleti költségekből vezettük le, nem a teszt eloszlásából. Fontos korlát: ha sok küszöböt próbálnánk a teszten ki, és a legjobbat jelentenénk, az már szelekciós torzítást vinne be, és új független adat kellene.

  2. A konstans baseline Brier: B0=y‾(1−y‾)=0,29⋅0,71=0,2059B_0 = \bar y(1-\bar y) = 0{,}29 \cdot 0{,}71 = 0{,}2059. A modell 0,187-es értéke jobb, de a különbség 0,019. A Brier nem tisztán kalibrációs mérőszám: két jól kalibrált modell közül a jobban diszkrimináló kisebb Brier-t kap, ha a pontszámok közelebb vannak 0-hoz és 1-hez. Ezért a Brier-t a reliabilitási binekkel együtt kell értelmezni; a Brier javulhat attól is, hogy a modell határozottabban szélsőséges pontszámokat ad, miközben a kalibráció nem javul.

39.3.7 Gyakori tévedés ellenpéldával

A leggyakoribb hiba a teszt eredménye utáni újratervezésből utólagos validálásnak álcázása. Tegyük fel, hogy a fejlesztő három modellt tanít, mindhármat lefuttatja a tesztre, és a legjobb ROC-AUC-t, 0,72-t jelenti. Ez a 0,72 már nem független becslés: a három tesztmetrika közül a legnagyobb felfelé torzított, még akkor is, ha mindhárom modell valódi értéke 0,5. Ha 10 modellt próbál a teszten, a legjobb várhatóan már pusztán zajból is 0,55–0,62 közé eshet. A helyes munkafolyamat: a modellek közötti választás a belső validációs foldokon történik; a tesztre csak egyetlen, előre rögzített jelölt kerül. Ha a teszt után bármilyen okból változtatunk a modellen, az új modellváltozathoz új, független bizonyíték szükséges, például a következő időablak tesztje. Ez a szabály összhangban van a LLM mint sztochasztikus komponens alfejezetben tanult mintavételi bizonytalansággal: a ritka pozitív esetek miatt a metrika sávja széles, ezért utólagos szelekcióval könnyű a sávon belül kedvezőnek látszó eredményt találni.

39.3.8 Önellenőrzés

Válaszok röviden: A teszt utáni küszöboptimalizálás ugyanazt az adatot használja kiválasztásra és értékelésre, ezért a metrika nem független. A rendelésszintű bootstrap figyelmen kívül hagyja az ügyfélen belüli korrelációt, ezért az intervallum szűkebb lehet a ténylegesnél; konzervatívabb ügyfélszintű mintavétel kell. A bin a modell 0,35-ös átlagos pontszámánál 0,31 megfigyelt arányt mutat, tehát a modell kissé túlbecsül, 0,04 eltéréssel.

39.3.9 Rövid összefoglaló

A független tesztértékelés nem a metrikák kiszámítása, hanem egy befagyasztott mérési szerződés végrehajtása: rögzített modellpontszámok, split manifest, előre levezetett döntési küszöb, rögzített metrikák. A PR-AUC, ROC-AUC, Brier, küszöbös precision/recall/F2, kalibrációs binek és szeletek együtt adnak visszakereshető jelentést, minden pontérték mellett mintavételi bizonytalansággal. A teszt kiértékelése után újrahasznosított adat vagy újrahangolt küszöb már nem hoz független bizonyítékot. A következő lépés a jelentés alapján a modell átadása és új környezetes, reprodukálható ismétlés a záróprojekt további lépésében.