IlmHamroh
Data Science va sun'iy intellekt/Klassifikatsiya13/14-dars21 daqiqa
Mundarija (22)

14.13-dars: Xatolar tahlili

14-QISM — KLASSIFIKATSIYA · 13-dars


1. Kirish va motivatsiya

Model tanlandi, metrikalar o'lchandi. Endi eng ko'p foyda keltiradigan qadam: model qayerda va nega yanglishadi? Amaliyotda aniqlikni oshirishning eng samarali yo'li ko'pincha yangi algoritm emas — bu xatolarni guruhlash va ular ortidagi sababni topish.

Bu darsda: xatolarni segmentlar bo'yicha tahlil qilish, ishonch darajasi bo'yicha ajratish, yorliq sifati muammolarini topish, xato turlarini klassifikatsiya qilish, belgi muhimligi (permutation) va bitta bashoratni tushuntirish, hamda topilmalarni yaxshilash rejasiga aylantirish.

Real vaziyat. Kredit modelining F1 si 0.72 da qotib qoldi; jamoa 3 ta yangi algoritm sinab ko'rdi — foyda yo'q. Keyin xatolar tahlili qilindi: xatolarning 58% i "yangi mijoz" segmentiga tushdi (tarixi yo'q) va 19% i noto'g'ri yorliqlangan yozuvlar edi. Yangi segment uchun alohida qoida va yorliqlarni tozalash F1 ni 0.81 ga ko'tardi — model o'zgarmadi.

Bu darsda xatolar tahlilini o'rganamiz.

Bu darsda:

  • Segmentlar bo'yicha xato
  • Ishonch va xato bog'liqligi
  • Yorliq sifati
  • Xato turlari taksonomiyasi
  • Belgi muhimligi
  • Bitta bashoratni tushuntirish
  • Tuzoqlar
  • Amaliy: yaxshilash rejasi

ℹ Misollar real numpy/pandas/sklearn bilan (Python 3.14).


2. Nazariya — chuqur tushuntirish

2.1. Segmentlar bo'yicha xato

text
Umumiy metrika bitta son beradi; segmentlar qayerda muammo borligini ko'rsatadi

Segmentlar: kategoriyalar (hudud, tarif), diapazonlar (yosh, summa),
            vaqt (oy, hafta kuni), ma'lumot manbai, til, qurilma

Har segment uchun: n, sinf ulushi, precision/recall/F1, xato ulushi
Diqqat: kichik segmentlarda metrika juda shovqinli (n >= 50-100 bo'lsin)

Qidirish kerak:
  · metrikasi umumiy o'rtachadan sezilarli past segment
  · xatolarning katta ulushini beradigan segment (n katta bo'lgani uchun)

Segment tahlili — xatolar tahlilining asosi: u "model yomon" degan umumiy gapni "model shu yerda yomon" degan aniq topilmaga aylantiradi. Ikki savolni ajrating: qaysi segment eng yomon ishlaydi (sifat) va qaysi segment eng ko'p xato beradi (hajm) — ular har xil segmentlar bo'lishi mumkin.

2.2. Ishonch va xato

text
Bashoratlarni ishonch bo'yicha guruhlang: max(predict_proba)

Kutilgan naqsh:
  yuqori ishonch -> kam xato;  past ishonch -> ko'p xato

Anomaliyalar:
  · YUQORI ishonchli XATOLAR — eng qimmatli topilma
      (yorliq xatosi, leakage, model tuzilmasi noto'g'ri)
  · past ishonchda ham aniqlik yuqori — model ehtiyotkor (kalibrlash - 14.10)

Amaliy: past ishonchli holatlarni INSON ko'rigiga yo'naltirish
        ("abstain" yoki "selective prediction")

Yuqori ishonchli xatolar — xatolar tahlilidagi eng ma'lumotli guruh: model ishonch bilan yanglishsa, bu odatda ma'lumotdagi muammoni (noto'g'ri yorliq, ziddiyatli yozuv) yoki vazifa ta'rifidagi muammoni ko'rsatadi, algoritmnikini emas.

2.3. Yorliq sifati

text
Belgilar: bir xil (yoki juda o'xshash) namunalarda TURLI yorliq
          model ishonch bilan yanglishgan holatlar
          yorliqlovchilar orasidagi kelishmovchilik

Tekshirish usullari:
  1. Dublikat/yaqin namunalarni topib, yorliqlarini solishtirish
  2. Yuqori ishonchli xatolarni QO'LDA ko'rib chiqish (20-50 ta)
  3. Cross-validation bashorati bilan yorliq mos kelmagan holatlar (confident learning)

Yorliq shovqini 5-10% bo'lsa — u Bayes xatosiga o'xshab ishlaydi (14.1)

Ko'p loyihalarda yorliq sifati modelni almashtirishdan ko'ra ko'proq foyda beradi. Oltin qoida: 20-50 ta xatoni qo'lda ko'rib chiqing — bu bir soatlik ish odatda haftalik modellashtirish tajribasidan ko'proq ma'lumot beradi.

2.4. Xato turlari taksonomiyasi

text
Xatolarni SABABI bo'yicha guruhlang:

1. YORLIQ xatosi        — haqiqiy yorliq noto'g'ri
2. BELGI yetishmasligi  — kerakli ma'lumot belgilar ichida yo'q
3. AJRALMAS holat       — sinflar haqiqatan ustma-ust (Bayes xatosi - 14.1)
4. KAM NAMUNA           — shu turdagi holatlar o'quvda kam
5. TAQSIMOT siljishi    — test holati o'quvdan farq qiladi (drift)
6. MODEL cheklovi       — chegara shakli mos emas 14.7-bob

Har tur BOSHQA yechim talab qiladi:
  yorliq -> tozalash;  belgi -> yangi belgi;  kam namuna -> ma'lumot yig'ish
  ajralmas -> qabul qilish;  drift -> qayta o'qitish;  model -> boshqa algoritm

Taksonomiya — xatolar tahlilining mahsuloti: har xato turiga boshqa qaror mos keladi. "Aniqlikni oshirish" degan noaniq vazifa shu tarzda "yorliqlarni tozalash + 2 ta yangi belgi + shu segment uchun ma'lumot yig'ish" degan aniq rejaga aylanadi.

2.5. Belgi muhimligi

python
from sklearn.inspection import permutation_importance

nat = permutation_importance(model, X_te, y_te, n_repeats=10,
                             random_state=0, scoring="f1")
nat.importances_mean, nat.importances_std

Permutation importance — belgini aralashtirib, metrika qancha tushishini o'lchaydi: u har qanday model uchun ishlaydi va test ma'lumotida hisoblanadi. Diqqat: korrelyatsiyalangan belgilarda muhimlik "bo'linib ketadi" (ikkalasi ham past ko'rinadi) — bu 13.3 dagi multikollinearlik muammosining aksi.

2.6. Bitta bashoratni tushuntirish

text
Chiziqli modelda: hissa_j = koeffitsiyent_j * belgi_qiymati_j   (13.3, 14.11)
  -> to'g'ridan-to'g'ri o'qiladi

Daraxt/ansamblda: qaror yo'li yoki SHAP qiymatlari

Amaliy foyda:
  · xatoni tekshirish ("nega bu holatda yanglishdi?")
  · foydalanuvchiga sabab ko'rsatish (kredit rad etish sababi)
  · leakage topish (kutilmagan belgi hukmron - 12.9)

Bitta bashoratni tushuntirish xatolar tahlilini aniq qiladi: umumiy muhimlik "daromad muhim" desa, bitta holat "aynan shu arizada kechikishlar soni hal qildi" deydi. Chiziqli modellarda bu bepul keladi — bu ularning amaliy afzalligi 13.10-bob.

2.7. Tuzoqlar

Asosiy tuzoqlar: kichik segmentlarda metrikaga ishonish (shovqin); xatolar tahlilini test to'plamida qilib, keyin o'sha testda baholash (12.3 — validatsiyada qiling); qo'lda ko'rib chiqmaslik; yorliq shovqinini model kamchiligi deb hisoblash; korrelyatsiyalangan belgilarda permutation importance ni noto'g'ri o'qish; topilmalarni rejaga aylantirmaslik; faqat umumiy metrikaga qarash.

2.8. Xatolar — yaxshilash yo'l xaritasi

Xatolar tahlili umumiy metrikadan aniq harakat rejasiga o'tish vositasi: xatolarni segmentlar (qayerda yomon va qayerda ko'p), ishonch darajasi (yuqori ishonchli xatolar eng qimmatli) va sabab turlari (yorliq, belgi, ajralmas, kam namuna, drift, model) bo'yicha guruhlang. Permutation importance va bitta bashoratni tushuntirish sababni aniqlashtiradi. Har xato turi boshqa yechim talab qiladi — shuning uchun tahlil natijasi aniq reja bo'lishi kerak. Keyingi dars — amaliyot: to'liq klassifikatsiya loyihasi.


3. Tez ma'lumotnoma

python
import numpy as np
import pandas as pd
from sklearn.inspection import permutation_importance
from sklearn.metrics import classification_report, confusion_matrix

df = pd.DataFrame({"y": y_val, "p": proba, "pred": pred, **segmentlar})
df["xato"] = df["y"] != df["pred"]
df["ishonch"] = np.maximum(df["p"], 1 - df["p"])

# segmentlar bo'yicha
df.groupby("hudud").agg(n=("y", "size"), xato_ulushi=("xato", "mean"),
                        xatolar=("xato", "sum"))

# ishonch bo'yicha
df["guruh"] = pd.qcut(df["ishonch"], 5)
df.groupby("guruh", observed=True)["xato"].mean()

# yuqori ishonchli xatolar — qo'lda ko'rib chiqish
df[df.xato].nlargest(20, "ishonch")

permutation_importance(model, X_val, y_val, n_repeats=10, random_state=0)
QOIDA: validatsiyada tahlil qil · segment + ishonch · 20-50 xatoni qo'lda ko'r

Xatolar tahlili xulosasi

Segmentlar: qaysi yomon (sifat) va qaysi ko'p xato beradi (hajm)
Ishonch: yuqori ishonchli xatolar -> yorliq/leakage/vazifa muammosi
Turlari: yorliq, belgi, ajralmas, kam namuna, drift, model
Har turga boshqa yechim; natija — aniq reja

4. Batafsil misollar

Misollar real numpy/pandas/sklearn bilan (Python 3.14). Misollar bitta kredit ma'lumotidan foydalanadi.

Misol 1 — Segmentlar bo'yicha xato

python
"""Model qayerda yomon va qayerda ko'p xato qiladi (real pandas/sklearn)."""

import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import f1_score
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler


def yarat(seed: int = 7, n: int = 9000) -> pd.DataFrame:
    """Kredit: 'yangi mijoz' segmentida belgilar kam ma'lumot beradi."""
    rng = np.random.default_rng(seed)
    yangi = rng.random(n) < 0.22
    hudud = rng.choice(["markaz", "shimol", "janub", "chekka"], n,
                       p=[0.4, 0.25, 0.2, 0.15])
    daromad = rng.lognormal(14.6, 0.5, n)
    kechikish = rng.poisson(np.where(yangi, 0.15, 0.6), n).astype(float)
    muddat = rng.integers(3, 48, n).astype(float)
    ball = (-1.0 - 0.55 * (np.log(daromad) - 14.6) + 0.85 * kechikish
            - 0.012 * muddat)
    # yangi mijozlarda tarix yo'q -> ko'proq tasodifiylik
    ball = ball + np.where(yangi, rng.normal(0, 1.6, n), rng.normal(0, 0.5, n))
    y = (rng.random(n) < 1 / (1 + np.exp(-ball))).astype(int)
    return pd.DataFrame({"yangi": yangi, "hudud": hudud, "daromad": daromad,
                         "kechikish": kechikish, "muddat": muddat,
                         "qaytarmadi": y})


def main() -> None:
    df = yarat()
    SON = ["daromad", "kechikish", "muddat"]
    KAT = ["hudud"]
    X = df[SON + KAT]
    y = df["qaytarmadi"]
    Xtr, Xval, ytr, yval, dtr, dval = train_test_split(
        X, y, df, test_size=0.35, random_state=0, stratify=y)

    model = Pipeline([
        ("t", ColumnTransformer([("son", StandardScaler(), SON),
                                 ("kat", OneHotEncoder(handle_unknown="ignore",
                                                       drop="first"), KAT)])),
        ("m", LogisticRegression(max_iter=3000)),
    ]).fit(Xtr, ytr)

    nat = dval.copy()
    nat["p"] = model.predict_proba(Xval)[:, 1]
    nat["pred"] = (nat["p"] >= 0.5).astype(int)
    nat["xato"] = nat["pred"] != nat["qaytarmadi"]

    print("=== 1. Umumiy natija ===")
    print(f"  validatsiya {len(nat)} qator, musbat sinf {yval.mean():.1%}")
    print(f"  aniqlik {1 - nat['xato'].mean():.4f}, "
          f"F1 {f1_score(nat['qaytarmadi'], nat['pred']):.4f}")

    print("\n=== 2. Segment: yangi va eski mijozlar ===")
    for qiymat, qism in nat.groupby("yangi"):
        nom = "yangi" if qiymat else "eski"
        print(f"  {nom:<6}: n={len(qism):>4}, xato ulushi "
              f"{qism['xato'].mean():.4f}, "
              f"F1 {f1_score(qism['qaytarmadi'], qism['pred']):.4f}, "
              f"barcha xatolarning {qism['xato'].sum() / nat['xato'].sum():.1%} i")

    print("\n=== 3. Segment: hudud ===")
    for qiymat, qism in nat.groupby("hudud"):
        print(f"  {qiymat:<8}: n={len(qism):>4}, xato ulushi "
              f"{qism['xato'].mean():.4f}, "
              f"barcha xatolarning {qism['xato'].sum() / nat['xato'].sum():.1%} i")

    print("\n=== 4. Segment: daromad diapazoni ===")
    nat["daromad_guruh"] = pd.qcut(nat["daromad"], 4,
                                   labels=["past", "o_rta", "yuqori", "eng yuqori"])
    for qiymat, qism in nat.groupby("daromad_guruh", observed=True):
        print(f"  {str(qiymat):<10}: n={len(qism):>4}, xato ulushi "
              f"{qism['xato'].mean():.4f}, "
              f"musbat sinf {qism['qaytarmadi'].mean():.3f}")
    print("  ⭐ 'Eng yomon segment' va 'eng ko'p xato beruvchi segment' har xil")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Umumiy natija ===
  validatsiya 3150 qator, musbat sinf 32.8%
  aniqlik 0.6860, F1 0.2636

=== 2. Segment: yangi va eski mijozlar ===
  eski  : n=2477, xato ulushi 0.3121, F1 0.3141, barcha xatolarning 78.2% i
  yangi : n= 673, xato ulushi 0.3210, F1 0.0000, barcha xatolarning 21.8% i

=== 3. Segment: hudud ===
  chekka  : n= 465, xato ulushi 0.2796, barcha xatolarning 13.1% i
  janub   : n= 655, xato ulushi 0.3130, barcha xatolarning 20.7% i
  markaz  : n=1266, xato ulushi 0.3065, barcha xatolarning 39.2% i
  shimol  : n= 764, xato ulushi 0.3482, barcha xatolarning 26.9% i

=== 4. Segment: daromad diapazoni ===
  past      : n= 788, xato ulushi 0.3579, musbat sinf 0.385
  o_rta     : n= 787, xato ulushi 0.3380, musbat sinf 0.341
  yuqori    : n= 787, xato ulushi 0.2757, musbat sinf 0.307
  eng yuqori: n= 788, xato ulushi 0.2843, musbat sinf 0.280
  ⭐ 'Eng yomon segment' va 'eng ko'p xato beruvchi segment' har xil

Nima ko'rsatdi: 2.1-bo'lim.

Misol 2 — Ishonch va yuqori ishonchli xatolar

python
"""Ishonch darajasi bo'yicha xatolar (real pandas/sklearn)."""

import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler


def yarat(seed: int = 11, n: int = 9000, yorliq_shovqini: float = 0.05):
    """Ba'zi yorliqlar ataylab NOTO'G'RI (yorliq shovqini)."""
    rng = np.random.default_rng(seed)
    X = rng.normal(0, 1, (n, 6))
    ball = 1.2 * X[:, 0] - 1.0 * X[:, 1] + 0.7 * X[:, 2]
    y = (rng.random(n) < 1 / (1 + np.exp(-ball))).astype(int)
    buzuq = rng.random(n) < yorliq_shovqini
    y[buzuq] = 1 - y[buzuq]
    return X, y, buzuq


def main() -> None:
    X, y, buzuq = yarat()
    idx = np.arange(len(X))
    Xtr, Xval, ytr, yval, itr, ival = train_test_split(
        X, y, idx, test_size=0.35, random_state=0, stratify=y)
    model = Pipeline([("sc", StandardScaler()),
                      ("m", LogisticRegression(max_iter=3000))]).fit(Xtr, ytr)
    p = model.predict_proba(Xval)[:, 1]

    nat = pd.DataFrame({"y": yval, "p": p, "buzuq": buzuq[ival]})
    nat["pred"] = (nat["p"] >= 0.5).astype(int)
    nat["xato"] = nat["pred"] != nat["y"]
    nat["ishonch"] = np.maximum(nat["p"], 1 - nat["p"])

    print("=== 1. Umumiy ===")
    print(f"  {len(nat)} qator, xato ulushi {nat['xato'].mean():.4f}")
    print(f"  ataylab buzilgan yorliqlar: {nat['buzuq'].mean():.1%}")

    print("\n=== 2. Ishonch guruhlari bo'yicha xato ===")
    nat["guruh"] = pd.qcut(nat["ishonch"], 5,
                           labels=["eng past", "past", "o_rta", "yuqori",
                                   "eng yuqori"])
    for qiymat, qism in nat.groupby("guruh", observed=True):
        print(f"  {str(qiymat):<11}: ishonch {qism['ishonch'].mean():.3f}, "
              f"xato ulushi {qism['xato'].mean():.4f}, "
              f"n={len(qism):>4}")

    print("\n=== 3. Yuqori ishonchli xatolar ===")
    yuqori_xato = nat[nat["xato"] & (nat["ishonch"] > 0.9)]
    print(f"  ishonch > 0.9 bo'lgan xatolar: {len(yuqori_xato)} ta")
    print(f"  ulardan buzilgan yorliqli: {yuqori_xato['buzuq'].mean():.1%}")
    oddiy_xato = nat[nat["xato"] & (nat["ishonch"] <= 0.9)]
    print(f"  qolgan xatolarda buzilgan yorliq: {oddiy_xato['buzuq'].mean():.1%}")
    print("  (yuqori ishonchli xatolar — yorliq muammosining indikatori)")

    print("\n=== 4. Past ishonchda insonga yo'naltirish ===")
    for ulush in [0.05, 0.10, 0.20]:
        chegara = nat["ishonch"].quantile(ulush)
        qolgan = nat[nat["ishonch"] > chegara]
        print(f"  eng past {ulush:.0%} ni insonga bersak: "
              f"qolganda aniqlik {1 - qolgan['xato'].mean():.4f} "
              f"(umumiy {1 - nat['xato'].mean():.4f})")
    print("  ⭐ Selektiv bashorat: ishonchsiz holatlarni insonga bering")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Umumiy ===
  3150 qator, xato ulushi 0.2822
  ataylab buzilgan yorliqlar: 4.4%

=== 2. Ishonch guruhlari bo'yicha xato ===
  eng past   : ishonch 0.542, xato ulushi 0.4444, n= 630
  past       : ishonch 0.623, xato ulushi 0.4111, n= 630
  o_rta      : ishonch 0.709, xato ulushi 0.2508, n= 630
  yuqori     : ishonch 0.794, xato ulushi 0.2016, n= 630
  eng yuqori : ishonch 0.901, xato ulushi 0.1032, n= 630

=== 3. Yuqori ishonchli xatolar ===
  ishonch > 0.9 bo'lgan xatolar: 19 ta
  ulardan buzilgan yorliqli: 47.4%
  qolgan xatolarda buzilgan yorliq: 11.3%
  (yuqori ishonchli xatolar — yorliq muammosining indikatori)

=== 4. Past ishonchda insonga yo'naltirish ===
  eng past 5% ni insonga bersak: qolganda aniqlik 0.7269 (umumiy 0.7178)
  eng past 10% ni insonga bersak: qolganda aniqlik 0.7383 (umumiy 0.7178)
  eng past 20% ni insonga bersak: qolganda aniqlik 0.7583 (umumiy 0.7178)
  ⭐ Selektiv bashorat: ishonchsiz holatlarni insonga bering

Nima ko'rsatdi: 2.2, 2.3-bo'limlar.

Misol 3 — Xato turlari va belgi muhimligi

python
"""Xatolarni sababi bo'yicha guruhlash (real numpy/sklearn)."""

import numpy as np
import pandas as pd
from sklearn.inspection import permutation_importance
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler


def yarat(seed: int = 15, n: int = 8000):
    """Uch xil xato manbai: yorliq shovqini, yashirin belgi, ajralmas zona."""
    rng = np.random.default_rng(seed)
    X = rng.normal(0, 1, (n, 5))
    yashirin = rng.normal(0, 1, n)                 # modelga BERILMAYDI
    ball = 1.1 * X[:, 0] - 0.9 * X[:, 1] + 1.3 * yashirin
    y = (rng.random(n) < 1 / (1 + np.exp(-ball))).astype(int)
    buzuq = rng.random(n) < 0.04
    y[buzuq] = 1 - y[buzuq]
    return X, y, yashirin, buzuq


def main() -> None:
    X, y, yashirin, buzuq = yarat()
    idx = np.arange(len(X))
    Xtr, Xval, ytr, yval, itr, ival = train_test_split(
        X, y, idx, test_size=0.35, random_state=0, stratify=y)
    model = Pipeline([("sc", StandardScaler()),
                      ("m", LogisticRegression(max_iter=3000))]).fit(Xtr, ytr)
    p = model.predict_proba(Xval)[:, 1]
    pred = (p >= 0.5).astype(int)
    xato = pred != yval

    print("=== 1. Umumiy xato ===")
    print(f"  {len(yval)} qator, xato ulushi {xato.mean():.4f}")

    print("\n=== 2. Xato turlari ===")
    buzuq_val = buzuq[ival]
    yashirin_val = np.abs(yashirin[ival])
    ishonch = np.maximum(p, 1 - p)
    turlar = {
        "yorliq xatosi": xato & buzuq_val,
        "yashirin belgi kuchli": xato & ~buzuq_val & (yashirin_val > 1.2),
        "ajralmas zona (past ishonch)": xato & ~buzuq_val & (yashirin_val <= 1.2)
                                        & (ishonch < 0.65),
        "boshqa": xato & ~buzuq_val & (yashirin_val <= 1.2) & (ishonch >= 0.65),
    }
    for nom, mos in turlar.items():
        print(f"  {nom:<30}: {mos.sum():>4} ta "
              f"({mos.sum() / xato.sum():.1%} barcha xatolardan)")

    print("\n=== 3. Yashirin belgi qo'shilsa ===")
    X2tr = np.column_stack([Xtr, yashirin[itr]])
    X2val = np.column_stack([Xval, yashirin[ival]])
    model2 = Pipeline([("sc", StandardScaler()),
                       ("m", LogisticRegression(max_iter=3000))]).fit(X2tr, ytr)
    xato2 = (model2.predict(X2val) != yval)
    print(f"  belgi qo'shilmagan: xato {xato.mean():.4f}")
    print(f"  belgi qo'shilgan:   xato {xato2.mean():.4f}")
    print(f"  yaxshilanish: {(xato.mean() - xato2.mean()) / xato.mean():.1%}")

    print("\n=== 4. Permutation importance ===")
    nat = permutation_importance(model, Xval, yval, n_repeats=10,
                                 random_state=0, scoring="accuracy")
    tartib = np.argsort(nat.importances_mean)[::-1]
    for i in tartib:
        print(f"  belgi {i}: {nat.importances_mean[i]:+.4f} "
              f"+- {nat.importances_std[i]:.4f}")
    print("  ⭐ Har xato turiga boshqa yechim mos keladi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Umumiy xato ===
  2800 qator, xato ulushi 0.3193

=== 2. Xato turlari ===
  yorliq xatosi                 :   78 ta (8.7% barcha xatolardan)
  yashirin belgi kuchli         :  234 ta (26.2% barcha xatolardan)
  ajralmas zona (past ishonch)  :  384 ta (43.0% barcha xatolardan)
  boshqa                        :  198 ta (22.1% barcha xatolardan)

=== 3. Yashirin belgi qo'shilsa ===
  belgi qo'shilmagan: xato 0.3193
  belgi qo'shilgan:   xato 0.2482
  yaxshilanish: 22.3%

=== 4. Permutation importance ===
  belgi 0: +0.1248 +- 0.0061
  belgi 1: +0.0676 +- 0.0060
  belgi 3: +0.0005 +- 0.0004
  belgi 2: +0.0002 +- 0.0015
  belgi 4: -0.0006 +- 0.0003
  ⭐ Har xato turiga boshqa yechim mos keladi

Nima ko'rsatdi: 2.4, 2.5-bo'limlar.

Misol 4 — Bitta bashoratni tushuntirish va yaxshilash rejasi

python
"""Xatolar tahlilidan aniq rejaga (real pandas/sklearn)."""

import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import f1_score
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler


def yarat(seed: int = 7, n: int = 9000) -> pd.DataFrame:
    rng = np.random.default_rng(seed)
    yangi = rng.random(n) < 0.22
    hudud = rng.choice(["markaz", "shimol", "janub", "chekka"], n,
                       p=[0.4, 0.25, 0.2, 0.15])
    daromad = rng.lognormal(14.6, 0.5, n)
    kechikish = rng.poisson(np.where(yangi, 0.15, 0.6), n).astype(float)
    muddat = rng.integers(3, 48, n).astype(float)
    ball = (-1.0 - 0.55 * (np.log(daromad) - 14.6) + 0.85 * kechikish
            - 0.012 * muddat)
    ball = ball + np.where(yangi, rng.normal(0, 1.6, n), rng.normal(0, 0.5, n))
    y = (rng.random(n) < 1 / (1 + np.exp(-ball))).astype(int)
    return pd.DataFrame({"yangi": yangi, "hudud": hudud, "daromad": daromad,
                         "kechikish": kechikish, "muddat": muddat,
                         "qaytarmadi": y})


def main() -> None:
    df = yarat()
    SON = ["daromad", "kechikish", "muddat"]
    KAT = ["hudud"]
    X, y = df[SON + KAT], df["qaytarmadi"]
    Xtr, Xval, ytr, yval, dtr, dval = train_test_split(
        X, y, df, test_size=0.35, random_state=0, stratify=y)
    model = Pipeline([
        ("t", ColumnTransformer([("son", StandardScaler(), SON),
                                 ("kat", OneHotEncoder(handle_unknown="ignore",
                                                       drop="first"), KAT)])),
        ("m", LogisticRegression(max_iter=3000)),
    ]).fit(Xtr, ytr)

    nomlar = model.named_steps["t"].get_feature_names_out()
    w = model.named_steps["m"].coef_[0]
    kesma = model.named_steps["m"].intercept_[0]
    Z = model.named_steps["t"].transform(Xval)
    p = model.predict_proba(Xval)[:, 1]
    pred = (p >= 0.5).astype(int)
    xato = pred != yval.to_numpy()
    ishonch = np.maximum(p, 1 - p)

    print("=== 1. Eng ishonchli xatolar ===")
    tartib = np.argsort(np.where(xato, ishonch, -1))[::-1][:3]
    for i in tartib:
        qator = dval.iloc[i]
        print(f"  #{i}: haqiqiy {int(yval.iloc[i])}, bashorat {pred[i]} "
              f"(p={p[i]:.3f}), yangi={bool(qator['yangi'])}, "
              f"kechikish={qator['kechikish']:.0f}")

    print("\n=== 2. Bitta bashoratni tushuntirish ===")
    i = int(tartib[0])
    hissa = Z[i] * w
    tartib_h = np.argsort(np.abs(hissa))[::-1][:4]
    print(f"  kesma: {kesma:+.3f}")
    for j in tartib_h:
        print(f"  {nomlar[j]:<16}: {hissa[j]:+.3f}")
    z = float(hissa.sum() + kesma)
    print(f"  jami log-odds {z:+.3f} -> ehtimol {1 / (1 + np.exp(-z)):.3f}")

    print("\n=== 3. Topilmalar jadvali ===")
    yangi_val = dval["yangi"].to_numpy()
    topilmalar = [
        ("yangi mijozlar segmenti",
         f"xato ulushi {xato[yangi_val].mean():.3f} vs "
         f"{xato[~yangi_val].mean():.3f}",
         "tarix belgilari yo'q",
         "alohida model yoki qo'shimcha belgilar"),
        ("barcha xatolarning ulushi",
         f"{xato[yangi_val].sum() / xato.sum():.1%} yangi mijozlardan",
         f"segment hajmi {yangi_val.mean():.0%}",
         "shu segmentga ustuvorlik berish"),
        ("yuqori ishonchli xatolar",
         f"{(xato & (ishonch > 0.85)).sum()} ta",
         "yorliq yoki ziddiyatli yozuv",
         "20-50 tasini qo'lda ko'rib chiqish"),
    ]
    for nom, olchov, sabab, harakat in topilmalar:
        print(f"  [{nom}]")
        print(f"    o'lchov: {olchov}")
        print(f"    taxminiy sabab: {sabab}")
        print(f"    harakat: {harakat}")

    print("\n=== 4. Rejani sinash: segment belgisi qo'shish ===")
    X2tr = Xtr.assign(yangi=dtr["yangi"].astype(float))
    X2val = Xval.assign(yangi=dval["yangi"].astype(float))
    model2 = Pipeline([
        ("t", ColumnTransformer([("son", StandardScaler(), SON + ["yangi"]),
                                 ("kat", OneHotEncoder(handle_unknown="ignore",
                                                       drop="first"), KAT)])),
        ("m", LogisticRegression(max_iter=3000)),
    ]).fit(X2tr, ytr)
    pred2 = model2.predict(X2val)
    print(f"  F1: {f1_score(yval, pred):.4f} -> {f1_score(yval, pred2):.4f}")
    print(f"  yangi mijozlarda xato: {xato[yangi_val].mean():.4f} -> "
          f"{(pred2 != yval.to_numpy())[yangi_val].mean():.4f}")
    print("  ⭐ Tahlil natijasi — aniq reja, keyin uni sinash")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Eng ishonchli xatolar ===
  #788: haqiqiy 0, bashorat 1 (p=0.891), yangi=False, kechikish=4
  #1795: haqiqiy 0, bashorat 1 (p=0.878), yangi=False, kechikish=4
  #2623: haqiqiy 1, bashorat 0 (p=0.131), yangi=False, kechikish=0

=== 2. Bitta bashoratni tushuntirish ===
  kesma: -0.819
  son__kechikish  : +2.671
  son__daromad    : +0.190
  son__muddat     : +0.058
  kat__hudud_markaz: +0.007
  jami log-odds +2.106 -> ehtimol 0.891

=== 3. Topilmalar jadvali ===
  [yangi mijozlar segmenti]
    o'lchov: xato ulushi 0.321 vs 0.312
    taxminiy sabab: tarix belgilari yo'q
    harakat: alohida model yoki qo'shimcha belgilar
  [barcha xatolarning ulushi]
    o'lchov: 21.8% yangi mijozlardan
    taxminiy sabab: segment hajmi 21%
    harakat: shu segmentga ustuvorlik berish
  [yuqori ishonchli xatolar]
    o'lchov: 7 ta
    taxminiy sabab: yorliq yoki ziddiyatli yozuv
    harakat: 20-50 tasini qo'lda ko'rib chiqish

=== 4. Rejani sinash: segment belgisi qo'shish ===
  F1: 0.2636 -> 0.2674
  yangi mijozlarda xato: 0.3210 -> 0.3254
  ⭐ Tahlil natijasi — aniq reja, keyin uni sinash

Nima ko'rsatdi: 2.6-bo'lim.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"Aniqlikni oshirish — yangi algoritm" Ko'pincha ma'lumot muammosi
"Xatolar tasodifiy" Segmentlarga to'planadi
"Yuqori ishonchli xato — model aybi" Ko'pincha yorliq muammosi
"Qo'lda ko'rib chiqish — vaqt isrofi" Eng ma'lumotli qadam
"Barcha xatolar bir xil" Turlari va yechimlari har xil
"Permutation importance — sababiy" Bashorat hissasi
"Tahlil test'da qilinadi" Validatsiyada
"Kichik segment ham ishonchli" Shovqin katta

6. Keng tarqalgan xatolar va yechimlari

1. Faqat umumiy metrikaga qarash

python
print(f"F1 = {f1:.3f}")                                           # ⚠️
df.groupby("segment")["xato"].agg(["mean", "sum", "size"])        # ✅

2. Test to'plamida tahlil

python
# test xatolarini tahlil qilib, shu testda qayta baholash          # ⚠️
# tahlil validatsiyada, test faqat yakuniy baho uchun 12.3-bob      # ✅

3. Kichik segmentlarga ishonish

python
# n = 12 bo'lgan segmentda F1 = 0.42 -> "muammo"                  # ⚠️
# n >= 50-100 bo'lgan segmentlarni ko'ring                        # ✅

4. Qo'lda ko'rmaslik

python
# faqat sonlarga qarash                                           # ⚠️
df[df.xato].nlargest(30, "ishonch")   # va o'qib chiqing          # ✅

5. Yorliq shovqinini e'tiborsiz qoldirish

python
# "model 8% xato qiladi" (yorliqlarning 5% i noto'g'ri)           # ⚠️
# yorliq sifatini alohida o'lchang                                # ✅

6. Korrelyatsiyalangan belgilarda muhimlikni noto'g'ri o'qish

python
# "ikkala belgi ham muhim emas" (ular bir-birini almashtiradi)    # ⚠️
# guruh bo'lib aralashtiring yoki korrelyatsiyani tekshiring      # ✅

7. Topilmalarni rejaga aylantirmaslik

python
# "yangi mijozlarda yomon" — va shu yerda to'xtash                # ⚠️
# har topilma uchun: sabab + harakat + kutilgan ta'sir            # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 12.6-dars (o'tilgan): Xatolar tahlili oqimda
  • 12.9-dars (o'tilgan): Leakage indikatorlari
  • 14.8-dars (o'tilgan): Chalkashlik matritsasi
  • 14.14-dars: Amaliy loyiha
  • MLOps qismi: Monitoring va drift

8. Eng yaxshi amaliyotlar

  1. Tahlilni validatsiyada qiling.

  2. Segmentlarni ikki savol bilan ko'ring: sifat va hajm.

  3. Ishonch bo'yicha guruhlang.

  4. 20-50 xatoni qo'lda o'qing.

  5. Xatolarni turlarga ajrating.

  6. Permutation importance ni qo'shing.

  7. Bitta bashoratni tushuntirib ko'ring.

  8. Har topilmaga harakat yozing.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # segment tahlilining ikki savoli?
2.  # kichik segment chegarasi?
3.  # ishonch qanday hisoblanadi?
4.  # yuqori ishonchli xato nimani anglatadi?
5.  # selektiv bashorat nima?
6.  # yorliq shovqinini qanday topish?
7.  # xato turlari?
8.  # yorliq xatosiga yechim?
9.  # belgi yetishmasligiga?
10. # permutation importance nima o'lchaydi?
11. # korrelyatsiyada u qanday buziladi?
12. # tahlil qaysi to'plamda?
Javoblar
  1. Qayerda yomon va qayerda ko'p xato
  2. n >= 50-100
  3. max(p, 1-p)
  4. Yorliq yoki vazifa muammosi
  5. Ishonchsizlarni insonga yo'naltirish
  6. Yuqori ishonchli xatolarni qo'lda ko'rish
  7. Yorliq, belgi, ajralmas, kam namuna, drift, model
  8. Tozalash
  9. Yangi belgi
  10. Belgi aralashtirilsa metrika tushishi
  11. Muhimlik bo'linib ketadi
  12. Validatsiyada

Vazifa 2: Xatolarni tuzating

python
1.  print(f"F1 = {f1:.3f}")   # boshqa tahlil yo'q

2.  # test xatolarini tahlil qilib, o'sha testda baholash

3.  # n = 15 bo'lgan segmentda xulosa chiqarish

4.  # "model 8% xato" (yorliqlarning 5% i noto'g'ri)

5.  # "yangi mijozlarda yomon" — xulosa shu yerda tugadi
Javoblar
python
1.  df.groupby("segment")["xato"].agg(["mean", "sum", "size"])

2.  # tahlil validatsiyada

3.  # n >= 50-100 bo'lgan segmentlar

4.  # yorliq sifatini alohida o'lchang

5.  # sabab + harakat + kutilgan ta'sir yozing

Vazifa 3: Segmentlar

Modellang:

  1. Bir nechta segment
  2. Sifat va hajm
  3. Eng muammoli
  4. Xulosa

Vazifa 4: Ishonch

Modellang:

  1. Ishonch guruhlari
  2. Yuqori ishonchli xatolar
  3. Yorliq bog'liqligi
  4. Selektiv bashorat

Vazifa 5: Turlar

Modellang:

  1. Uch xato manbai
  2. Taksonomiya
  3. Yangi belgi ta'siri
  4. Muhimlik

Vazifa 6: Reja

Modellang:

  1. Tushuntirish
  2. Topilmalar jadvali
  3. Harakatlar
  4. Sinash

Vazifa 7: O'ylash

Andrew Ng "data-centric AI" g'oyasini targ'ib qiladi: modelni qotirib, ma'lumot sifatini yaxshilash. Bu yondashuv qachon to'g'ri va uning chegarasi qayerda?

Javob

Qisqa javob: ma'lumot sifatiga e'tibor ko'p amaliy loyihada eng yuqori qaytim beradi — ayniqsa ma'lumot kichik, yorliqlar shovqinli yoki vazifa ta'rifi noaniq bo'lsa. Chegarasi: ma'lumot toza va katta bo'lsa, model va belgi muhandisligi yana yetakchi bo'ladi.

1. Nega ma'lumotga e'tibor samarali

  • Yorliq shovqini Bayes xatosiga o'xshab ishlaydi 14.1-bob — uni model yenga olmaydi
  • Kam segmentlar uchun ma'lumot yig'ish to'g'ridan-to'g'ri yordam beradi
  • Vazifa ta'rifini aniqlashtirish (sinflar chegarasi) ko'pincha eng katta yutuq (14.8)
  • Model o'zgarmagani uchun natija izohlanadigan bo'ladi

2. Amaliy qadamlar

Qadam Foyda
Yorliqlash qo'llanmasini aniqlashtirish Ziddiyatli yorliqlar kamayadi
Ikkilamchi yorliqlash (kelishuvni o'lchash) Shovqin darajasi ma'lum bo'ladi
Yuqori ishonchli xatolarni tozalash Tez va arzon
Kam segmentga ma'lumot yig'ish Aniq segmentda yaxshilanish

3. Chegaralari

  • Ma'lumot toza va ko'p bo'lsa, qaytim kamayadi
  • Ba'zi vazifalarda yorliqlash juda qimmat (tibbiyot)
  • Model cheklovi haqiqatan asosiy bo'lishi mumkin (14.7)
  • "Ma'lumotni tozalash" leakage yoki siljish kiritishi mumkin

4. Muvozanatli yondashuv

  1. Xatolar tahlili bilan sababni aniqlang
  2. Sabab ma'lumotda bo'lsa — ma'lumot bilan ishlang
  3. Sabab modelda bo'lsa — model bilan
  4. Har ikkalasini o'lchab taqqoslang

5. Xulosa

  1. "Data-centric" — usul emas, ustuvorlik
  2. Xatolar tahlili qaysi yo'lni tanlashni aytadi
  3. Yorliq sifati ko'pincha eng arzon yutuq
  4. Chegara: ma'lumot yetarli va toza bo'lganda

Nimani mustahkamlaydi: 2.3, 2.4-bo'limlar.


Xulosa

Bu darsda xatolar tahlilini o'rgandik.

Eng muhim uch fikr:

  1. Xatolar tasodifiy emas — ular segmentlarga to'planadi. Har segment uchun ikki savol bering: qaysi segment eng yomon ishlaydi (sifat) va qaysi segment eng ko'p xato beradi (hajm) — bular ko'pincha har xil segmentlar. Kichik segmentlarda metrika juda shovqinli (n >= 50-100 bo'lsin).

  2. Yuqori ishonchli xatolar — eng qimmatli topilma. Model ishonch bilan yanglishsa, sabab odatda yorliq xatosi, ziddiyatli yozuv yoki vazifa ta'rifidagi muammo bo'ladi. Shuning uchun 20-50 ta xatoni qo'lda ko'rib chiqish bir soatlik ish sifatida haftalik modellashtirish tajribasidan ko'proq ma'lumot beradi.

  3. Har xato turiga boshqa yechim. Xatolarni sababi bo'yicha guruhlang: yorliq xatosi (tozalash), belgi yetishmasligi (yangi belgi), ajralmas holat (qabul qilish — Bayes xatosi), kam namuna (ma'lumot yig'ish), drift (qayta o'qitish), model cheklovi (boshqa algoritm). Tahlil natijasi — aniq reja: har topilma uchun sabab, harakat va kutilgan ta'sir.

Keyingi darsda amaliyot — 14-qismning to'liq klassifikatsiya loyihasi: ma'lumotdan qarorgacha.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
14.13-dars: Xatolar tahlili — IlmHamroh