IlmHamroh
Data Science va sun'iy intellekt/Daraxtlar va ansambllar14/14-dars23 daqiqa
Mundarija (22)

15.14-dars: Amaliyot — to'liq ansambl loyihasi

15-QISM — DARAXTLAR VA ANSAMBLLAR · 14-dars


1. Kirish va motivatsiya

Bu qismda qaror daraxtidan boshlab gradient boosting va stacking gacha bo'lgan yo'lni bosib o'tdik. Endi hammasini bitta loyihada birlashtiramiz: ma'lumotni ko'rishdan boshlab, ishlab chiqarishga tayyor modelgacha.

Amaliyot alohida usullarni takrorlash emas — qaror qabul qilish tartibini mashq qilish: qaysi modelni birinchi sinash, qachon sozlashni to'xtatish, qaysi metrikaga qarash, natijani qanday tekshirish va nima hujjatlashtirish.

Bu darsda: to'liq oqim (bazaviy model → ansambl → sozlash → tahlil → chiqarish), modellarni halol taqqoslash, xatolar tahlili, belgi muhimligi va yakuniy hisobot.

Real vaziyat. Ko'p loyiha "model 0.87 AUC berdi" bilan tugaydi va hech qachon ishlatilmaydi — chunki chegara tanlanmagan, kechikish o'lchanmagan, drift kuzatuvi yo'q va hech kim modelning nima qilishini tushuntira olmaydi. Bu darsdagi tartib shu holatning oldini oladi.

Bu darsda to'liq ansambl loyihasini quramiz.

Bu darsda:

  • To'liq oqim
  • Modellarni halol taqqoslash
  • Sozlash
  • Xatolar tahlili
  • Belgi muhimligi
  • Chiqarish tayyorgarligi
  • Tuzoqlar
  • Amaliy: yakuniy loyiha

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


2. Nazariya — chuqur tushuntirish

2.1. To'liq oqim

text
1. MA'LUMOT: hajm, yo'qolgan qiymatlar, sinf nisbati, leakage tekshiruvi
2. AJRATISH: o'quv / validatsiya / test (yoki CV + test)
3. BAZAVIY: DummyClassifier va logistik regressiya 12.6-bob
4. ANSAMBL: RandomForest sozlanmasdan -> haqiqiy boshlang'ich
5. BOOSTING: HistGB / LightGBM, erta to'xtatish bilan
6. SOZLASH: tartib bilan 15.9-bob, tasodifiy qidiruv
7. TAHLIL: xatolar, muhimlik, kalibrlash, segmentlar
8. QAROR: chegara, narx-foyda
9. CHIQARISH: Pipeline saqlash, kechikish, drift rejasi

3 va 4-qadamni o'tkazib yubormang: DummyClassifier va sozlanmagan Random Forest sizga realistik kutish beradi. Ularsiz 0.87 AUC yaxshimi yoki yomonmi — bilib bo'lmaydi.

2.2. Modellarni halol taqqoslash

text
BIR XIL shartlarda:
  - bir xil CV bo'linishi (random_state qotirilgan)
  - bir xil metrika
  - bir xil tayyorlash (Pipeline ichida)
  - har model uchun O'ZIGA MOS sozlash byudjeti

NOTO'G'RI: RF ni sozlab, logistik regressiyani standart holda qoldirish
NOTO'G'RI: turli CV bo'linishlarida solishtirish
NOTO'G'RI: test to'plamida ko'p marta baholash

Farq MUHIMmi? CV foldlar bo'yicha std ni ko'ring
  farq < 1 std bo'lsa - ehtimol shovqin

CV standart og'ishi taqqoslashning ajralmas qismi: 0.842 va 0.847 farqi, agar std 0.008 bo'lsa, ahamiyatsiz. Bunday holda soddaroq yoki tezroq modelni tanlang.

2.3. Sozlash

text
Byudjetni oqilona taqsimlang:
  RandomForest: 5-10 konfiguratsiya (max_features)
  Boosting: 40-80 konfiguratsiya (tasodifiy qidiruv)
  Stacking: faqat vaqt qolsa

Qachon to'xtash:
  - so'nggi 20 sinov yaxshilanish bermasa
  - yutuq CV std dan kichik bo'lsa
  - narx-foyda salbiy bo'lsa

To'xtash qoidasini oldindan belgilang, aks holda sozlash cheksiz davom etadi va siz validatsiyaga overfitting qilasiz.

2.4. Xatolar tahlili

text
Har doim quyidagilarni ko'ring 14.13-bob:
  1. Eng ishonchli XATO bashoratlar (p > 0.9 lekin y = 0)
  2. Segmentlar bo'yicha metrika (hudud, kanal, davr)
  3. Kalibrlash diagrammasi 14.10-bob
  4. Chalkashlik matritsasi va chegara ta'siri

Ko'pincha topiladi:
  - bitta segmentda model umuman ishlamaydi
  - yorliq xatolari
  - leakage belgisi (juda yaxshi natija)

Segmentlar bo'yicha bo'lish — xatolar tahlilining eng samarali usuli: umumiy 0.85 AUC ostida bitta muhim segmentdagi 0.58 yashiringan bo'lishi mumkin.

2.5. Belgi muhimligi

text
Yakuniy hisobot uchun 15.11-bob:
  - permutation importance (TEST to'plamida, n_repeats >= 10)
  - korrelyatsiyali guruhlar bo'yicha
  - partial dependence bilan yo'nalish
  - MDI ni faqat ichki ko'rikda

Va albatta yozing: "bu bashorat foydaliligi, sababiy ta'sir emas"

Hisobotdagi muhimlik diagrammasiga ogohlantirish yozuvi qo'shing — aks holda uni albatta sababiy talqin qilishadi.

2.6. Chiqarish tayyorgarligi

text
Yakunda tayyor bo'lishi kerak:
  [ ] Pipeline (tayyorlash + model) joblib da
  [ ] Versiyalar, belgilar ro'yxati, metrikalar
  [ ] Tanlangan chegara va uning asosi
  [ ] Kechikish va hajm o'lchovlari
  [ ] Xatolar tahlili hisoboti
  [ ] Drift kuzatuvi rejasi
  [ ] Qayta o'qitish siyosati
  [ ] Rollback rejasi

Bu ro'yxat model kartasi (model card) ning asosi: u modelni topshirishda va keyinchalik uni qo'llab-quvvatlashda kerak bo'ladi.

2.7. Tuzoqlar

Asosiy tuzoqlar: bazaviy modelsiz boshlash; test to'plamida ko'p marta baholash; modellarni turli shartlarda taqqoslash; CV std ni hisobga olmaslik; xatolar tahlilini o'tkazib yuborish; chegarani 0.5 da qoldirish; muhimlikni sababiy talqin qilish; kechikish va hajmni oxirida tekshirish.

2.8. Tartib — asosiy ko'nikma

Ansambl loyihasi tartib bilan olib boriladi: bazaviy model → sozlanmagan RF → boosting + erta to'xtatish → tartibli sozlash → xatolar tahlili → chegara → chiqarish. Modellarni faqat bir xil shartlarda taqqoslang va CV std ni hisobga oling. Yutuq std dan kichik bo'lsa — soddaroq modelni tanlang. Keyingi qism — nazoratsiz o'rganish.


3. Tez ma'lumotnoma

python
from sklearn.dummy import DummyClassifier
from sklearn.model_selection import StratifiedKFold, cross_validate

cv = StratifiedKFold(5, shuffle=True, random_state=0)
for nom, m in modellar.items():
    n = cross_validate(m, Xtr, ytr, cv=cv, scoring=["roc_auc", "average_precision"])
    print(nom, n["test_roc_auc"].mean(), n["test_roc_auc"].std())

# chegarani validatsiyada tanlash
pr, rc, ch = precision_recall_curve(yval, pval)
f1 = 2 * pr[:-1] * rc[:-1] / np.maximum(pr[:-1] + rc[:-1], 1e-12)
chegara = ch[np.argmax(f1)]
QOIDA: bazaviy model bilan boshla · bir xil CV · std ni ko'r ·
       testda bir marta

Amaliyot xulosasi

1 ma'lumot -> 2 ajratish -> 3 bazaviy -> 4 RF -> 5 boosting
-> 6 sozlash -> 7 tahlil -> 8 chegara -> 9 chiqarish
Bir xil shartlarda taqqosla; CV std ni hisobga ol
Testda faqat bir marta; chegarani validatsiyada tanla

4. Batafsil misollar

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

Misol 1 — Ma'lumot va bazaviy modellar

python
"""1-4 qadamlar: ma'lumot, ajratish, bazaviy, sozlanmagan RF (real pandas/sklearn)."""

import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.dummy import DummyClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold, cross_validate, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler


def yarat(seed: int = 42, n: int = 12000) -> pd.DataFrame:
    """Yetkazib berish kechikishi: aralash belgilar, o'zaro ta'sirlar."""
    rng = np.random.default_rng(seed)
    hudud = rng.choice(["toshkent", "samarqand", "buxoro", "fargona",
                        "namangan"], n, p=[0.35, 0.2, 0.15, 0.2, 0.1])
    tur = rng.choice(["oddiy", "tezkor", "yirik"], n, p=[0.6, 0.3, 0.1])
    kanal = rng.choice(["ilova", "sayt", "qongiroq"], n, p=[0.5, 0.35, 0.15])
    masofa = rng.gamma(3, 60, n)
    ogirlik = rng.gamma(2, 4, n)
    soat = rng.integers(0, 24, n).astype(float)
    hafta_kuni = rng.integers(0, 7, n).astype(float)
    kuryer_tajribasi = rng.gamma(2, 8, n)

    hq = pd.Series(hudud).map({"toshkent": 0.0, "samarqand": 0.5,
                               "buxoro": 0.9, "fargona": 0.4,
                               "namangan": 0.6}).to_numpy()
    tt = pd.Series(tur).map({"oddiy": 0.0, "tezkor": -0.9,
                             "yirik": 1.1}).to_numpy()
    tig = ((soat >= 7) & (soat <= 10)) | ((soat >= 17) & (soat <= 19))
    kuch = (-3.2 + 0.005 * masofa + 0.04 * ogirlik + hq + tt
            + 1.0 * tig                                  # tig'iz soatlar
            + 0.8 * (tig & (hq > 0.4))                   # o'zaro ta'sir
            - 0.04 * kuryer_tajribasi
            + 0.4 * (hafta_kuni >= 5))
    y = (rng.random(n) < 1 / (1 + np.exp(-kuch))).astype(int)
    df = pd.DataFrame({"hudud": hudud, "tur": tur, "kanal": kanal,
                       "masofa": masofa, "ogirlik": ogirlik, "soat": soat,
                       "hafta_kuni": hafta_kuni,
                       "kuryer_tajribasi": kuryer_tajribasi, "kechikdi": y})
    df.loc[rng.random(n) < 0.05, "kuryer_tajribasi"] = np.nan
    return df


def tayyorlagich(kategoriya, sonli, masshtab: bool = False):
    sonli_quvur = ([("imp", SimpleImputer(strategy="median")),
                    ("sc", StandardScaler())] if masshtab
                   else [("imp", SimpleImputer(strategy="median"))])
    return ColumnTransformer([
        ("k", OneHotEncoder(handle_unknown="ignore"), kategoriya),
        ("s", Pipeline(sonli_quvur), sonli)])


def main() -> None:
    df = yarat()
    print("=== 1. Ma'lumot ===")
    print(f"  qatorlar: {len(df)}, belgilar: {df.shape[1] - 1}")
    print(f"  kechikish ulushi: {df['kechikdi'].mean():.2%}")
    print(f"  yo'qolgan qiymatlar: "
          f"{int(df.isna().sum().sum())} ta "
          f"({df.isna().sum().sum() / df.size:.2%})")
    print(f"  kategoriyali: hudud({df['hudud'].nunique()}), "
          f"tur({df['tur'].nunique()}), kanal({df['kanal'].nunique()})")

    X = df.drop(columns="kechikdi")
    y = df["kechikdi"]
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.25, random_state=0,
                                          stratify=y)
    print("\n=== 2. Ajratish ===")
    print(f"  o'quv {len(Xtr)}, test {len(Xte)}")
    print(f"  o'quvda kechikish {ytr.mean():.2%}, "
          f"testda {yte.mean():.2%}")

    kategoriya = ["hudud", "tur", "kanal"]
    sonli = ["masofa", "ogirlik", "soat", "hafta_kuni", "kuryer_tajribasi"]
    cv = StratifiedKFold(5, shuffle=True, random_state=0)

    print("\n=== 3. Bazaviy modellar ===")
    modellar = {
        "Dummy(prior)": Pipeline([("t", tayyorlagich(kategoriya, sonli)),
                                  ("m", DummyClassifier(strategy="prior"))]),
        "LogReg": Pipeline([("t", tayyorlagich(kategoriya, sonli, True)),
                            ("m", LogisticRegression(max_iter=2000))]),
    }
    natijalar = {}
    for nom, m in modellar.items():
        n = cross_validate(m, Xtr, ytr, cv=cv,
                           scoring=["roc_auc", "average_precision"], n_jobs=1)
        natijalar[nom] = n
        print(f"  {nom:<14}: ROC AUC {n['test_roc_auc'].mean():.4f} "
              f"(+-{n['test_roc_auc'].std():.4f}), PR AUC "
              f"{n['test_average_precision'].mean():.4f}")

    print("\n=== 4. Sozlanmagan Random Forest ===")
    rf = Pipeline([("t", tayyorlagich(kategoriya, sonli)),
                   ("m", RandomForestClassifier(n_estimators=300,
                                                random_state=0, n_jobs=1))])
    n = cross_validate(rf, Xtr, ytr, cv=cv,
                       scoring=["roc_auc", "average_precision"], n_jobs=1)
    natijalar["RandomForest"] = n
    print(f"  RandomForest  : ROC AUC {n['test_roc_auc'].mean():.4f} "
          f"(+-{n['test_roc_auc'].std():.4f}), PR AUC "
          f"{n['test_average_precision'].mean():.4f}")
    lr = natijalar["LogReg"]["test_roc_auc"].mean()
    print(f"  LogReg dan farq: {n['test_roc_auc'].mean() - lr:+.4f} "
          f"(CV std {n['test_roc_auc'].std():.4f})")
    print("  ⭐ Bazaviy modellar realistik kutish beradi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Ma'lumot ===
  qatorlar: 12000, belgilar: 8
  kechikish ulushi: 17.82%
  yo'qolgan qiymatlar: 579 ta (0.54%)
  kategoriyali: hudud(5), tur(3), kanal(3)

=== 2. Ajratish ===
  o'quv 9000, test 3000
  o'quvda kechikish 17.82%, testda 17.83%

=== 3. Bazaviy modellar ===
  Dummy(prior)  : ROC AUC 0.5000 (+-0.0000), PR AUC 0.1782
  LogReg        : ROC AUC 0.7338 (+-0.0118), PR AUC 0.3965

=== 4. Sozlanmagan Random Forest ===
  RandomForest  : ROC AUC 0.7316 (+-0.0154), PR AUC 0.3969
  LogReg dan farq: -0.0022 (CV std 0.0154)
  ⭐ Bazaviy modellar realistik kutish beradi

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

Misol 2 — Ansambllarni taqqoslash va sozlash

python
"""5-6 qadamlar: boosting, erta to'xtatish, tasodifiy qidiruv (real sklearn)."""

import numpy as np
import pandas as pd
from scipy.stats import randint, uniform
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import (ExtraTreesClassifier,
                              HistGradientBoostingClassifier,
                              RandomForestClassifier)
from sklearn.impute import SimpleImputer
from sklearn.model_selection import (RandomizedSearchCV, StratifiedKFold,
                                     cross_validate, train_test_split)
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder


def yarat(seed: int = 42, n: int = 12000) -> pd.DataFrame:
    rng = np.random.default_rng(seed)
    hudud = rng.choice(["toshkent", "samarqand", "buxoro", "fargona",
                        "namangan"], n, p=[0.35, 0.2, 0.15, 0.2, 0.1])
    tur = rng.choice(["oddiy", "tezkor", "yirik"], n, p=[0.6, 0.3, 0.1])
    kanal = rng.choice(["ilova", "sayt", "qongiroq"], n, p=[0.5, 0.35, 0.15])
    masofa = rng.gamma(3, 60, n)
    ogirlik = rng.gamma(2, 4, n)
    soat = rng.integers(0, 24, n).astype(float)
    hafta_kuni = rng.integers(0, 7, n).astype(float)
    kuryer_tajribasi = rng.gamma(2, 8, n)
    hq = pd.Series(hudud).map({"toshkent": 0.0, "samarqand": 0.5,
                               "buxoro": 0.9, "fargona": 0.4,
                               "namangan": 0.6}).to_numpy()
    tt = pd.Series(tur).map({"oddiy": 0.0, "tezkor": -0.9,
                             "yirik": 1.1}).to_numpy()
    tig = ((soat >= 7) & (soat <= 10)) | ((soat >= 17) & (soat <= 19))
    kuch = (-3.2 + 0.005 * masofa + 0.04 * ogirlik + hq + tt + 1.0 * tig
            + 0.8 * (tig & (hq > 0.4)) - 0.04 * kuryer_tajribasi
            + 0.4 * (hafta_kuni >= 5))
    y = (rng.random(n) < 1 / (1 + np.exp(-kuch))).astype(int)
    df = pd.DataFrame({"hudud": hudud, "tur": tur, "kanal": kanal,
                       "masofa": masofa, "ogirlik": ogirlik, "soat": soat,
                       "hafta_kuni": hafta_kuni,
                       "kuryer_tajribasi": kuryer_tajribasi, "kechikdi": y})
    df.loc[rng.random(n) < 0.05, "kuryer_tajribasi"] = np.nan
    return df


def tayyorlagich(kategoriya, sonli):
    return ColumnTransformer([
        ("k", OneHotEncoder(handle_unknown="ignore"), kategoriya),
        ("s", SimpleImputer(strategy="median"), sonli)])


def main() -> None:
    df = yarat()
    X = df.drop(columns="kechikdi")
    y = df["kechikdi"]
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.25, random_state=0,
                                          stratify=y)
    kategoriya = ["hudud", "tur", "kanal"]
    sonli = ["masofa", "ogirlik", "soat", "hafta_kuni", "kuryer_tajribasi"]
    cv = StratifiedKFold(5, shuffle=True, random_state=0)

    def quvur(model):
        return Pipeline([("t", tayyorlagich(kategoriya, sonli)),
                         ("m", model)])

    print("=== 1. Uch ansambl (sozlanmagan) ===")
    variantlar = {
        "RandomForest": RandomForestClassifier(n_estimators=300, random_state=0,
                                               n_jobs=1),
        "ExtraTrees": ExtraTreesClassifier(n_estimators=300, random_state=0,
                                           n_jobs=1),
        "HistGB": HistGradientBoostingClassifier(learning_rate=0.1,
                                                 max_iter=500,
                                                 early_stopping=True,
                                                 validation_fraction=0.15,
                                                 n_iter_no_change=20,
                                                 random_state=0),
    }
    ballar = {}
    print(f"  {'model':<14} {'ROC AUC':>9} {'std':>8} {'PR AUC':>9}")
    for nom, m in variantlar.items():
        n = cross_validate(quvur(m), Xtr, ytr, cv=cv,
                           scoring=["roc_auc", "average_precision"], n_jobs=1)
        ballar[nom] = (n["test_roc_auc"].mean(), n["test_roc_auc"].std())
        print(f"  {nom:<14} {n['test_roc_auc'].mean():>9.4f} "
              f"{n['test_roc_auc'].std():>8.4f} "
              f"{n['test_average_precision'].mean():>9.4f}")

    print("\n=== 2. Random Forest: max_features ===")
    print(f"  {'max_features':>13} {'ROC AUC':>9} {'std':>8}")
    for mf in ["sqrt", 0.3, 0.5, None]:
        n = cross_validate(quvur(RandomForestClassifier(n_estimators=250,
                                                        max_features=mf,
                                                        random_state=0)),
                           Xtr, ytr, cv=cv, scoring="roc_auc", n_jobs=1)
        nom = "None" if mf is None else str(mf)
        print(f"  {nom:>13} {n['test_score'].mean():>9.4f} "
              f"{n['test_score'].std():>8.4f}")

    print("\n=== 3. Boosting: tasodifiy qidiruv ===")
    asos = quvur(HistGradientBoostingClassifier(learning_rate=0.1,
                                                max_iter=600,
                                                early_stopping=True,
                                                validation_fraction=0.15,
                                                n_iter_no_change=20,
                                                random_state=0))
    taqsimot = {"m__max_depth": randint(2, 9),
                "m__min_samples_leaf": randint(10, 120),
                "m__l2_regularization": uniform(0, 6),
                "m__max_features": uniform(0.5, 0.5)}
    q = RandomizedSearchCV(asos, taqsimot, n_iter=20, cv=cv, scoring="roc_auc",
                           random_state=0, n_jobs=1).fit(Xtr, ytr)
    print(f"  sinovlar: {len(q.cv_results_['params'])}")
    qisqa = {k.replace("m__", ""): (round(float(v), 3)
                                   if isinstance(v, (float, np.floating))
                                   else int(v))
             for k, v in q.best_params_.items()}
    print(f"  eng yaxshi: {qisqa}")
    print(f"  CV ROC AUC: {q.best_score_:.4f} "
          f"(sozlanmagan {ballar['HistGB'][0]:.4f})")
    print(f"  yutuq: {q.best_score_ - ballar['HistGB'][0]:+.4f} "
          f"(CV std {ballar['HistGB'][1]:.4f})")

    print("\n=== 4. Yakuniy: eta ni kamaytirib qayta o'qitish ===")
    eng = {k.replace("m__", ""): v for k, v in q.best_params_.items()}
    print(f"  {'eta':>6} {'CV ROC AUC':>12} {'std':>8}")
    for eta in [0.1, 0.05]:
        m = quvur(HistGradientBoostingClassifier(learning_rate=eta,
                                                 max_iter=2000,
                                                 early_stopping=True,
                                                 validation_fraction=0.15,
                                                 n_iter_no_change=30,
                                                 random_state=0, **eng))
        n = cross_validate(m, Xtr, ytr, cv=cv, scoring="roc_auc", n_jobs=1)
        print(f"  {eta:>6.2f} {n['test_score'].mean():>12.4f} "
              f"{n['test_score'].std():>8.4f}")
    print("  ⭐ Yutuqni CV std bilan solishtiring")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Uch ansambl (sozlanmagan) ===
  model            ROC AUC      std    PR AUC
  RandomForest      0.7316   0.0154    0.3969
  ExtraTrees        0.6972   0.0147    0.3460
  HistGB            0.7592   0.0112    0.4367

=== 2. Random Forest: max_features ===
   max_features   ROC AUC      std
           sqrt    0.7308   0.0146
            0.3    0.7308   0.0146
            0.5    0.7338   0.0134
           None    0.7331   0.0090

=== 3. Boosting: tasodifiy qidiruv ===
  sinovlar: 20
  eng yaxshi: {'l2_regularization': 5.016, 'max_depth': 2, 'max_features': 0.544, 'min_samples_leaf': 90}
  CV ROC AUC: 0.7738 (sozlanmagan 0.7592)
  yutuq: +0.0146 (CV std 0.0112)

=== 4. Yakuniy: eta ni kamaytirib qayta o'qitish ===
     eta   CV ROC AUC      std
    0.10       0.7735   0.0095
    0.05       0.7725   0.0097
  ⭐ Yutuqni CV std bilan solishtiring

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

Misol 3 — Xatolar tahlili va muhimlik

python
"""7-qadam: segmentlar, kalibrlash, muhimlik (real pandas/sklearn)."""

import numpy as np
import pandas as pd
from sklearn.calibration import calibration_curve
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.impute import SimpleImputer
from sklearn.inspection import permutation_importance
from sklearn.metrics import brier_score_loss, roc_auc_score
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder


def yarat(seed: int = 42, n: int = 12000) -> pd.DataFrame:
    rng = np.random.default_rng(seed)
    hudud = rng.choice(["toshkent", "samarqand", "buxoro", "fargona",
                        "namangan"], n, p=[0.35, 0.2, 0.15, 0.2, 0.1])
    tur = rng.choice(["oddiy", "tezkor", "yirik"], n, p=[0.6, 0.3, 0.1])
    kanal = rng.choice(["ilova", "sayt", "qongiroq"], n, p=[0.5, 0.35, 0.15])
    masofa = rng.gamma(3, 60, n)
    ogirlik = rng.gamma(2, 4, n)
    soat = rng.integers(0, 24, n).astype(float)
    hafta_kuni = rng.integers(0, 7, n).astype(float)
    kuryer_tajribasi = rng.gamma(2, 8, n)
    hq = pd.Series(hudud).map({"toshkent": 0.0, "samarqand": 0.5,
                               "buxoro": 0.9, "fargona": 0.4,
                               "namangan": 0.6}).to_numpy()
    tt = pd.Series(tur).map({"oddiy": 0.0, "tezkor": -0.9,
                             "yirik": 1.1}).to_numpy()
    tig = ((soat >= 7) & (soat <= 10)) | ((soat >= 17) & (soat <= 19))
    kuch = (-3.2 + 0.005 * masofa + 0.04 * ogirlik + hq + tt + 1.0 * tig
            + 0.8 * (tig & (hq > 0.4)) - 0.04 * kuryer_tajribasi
            + 0.4 * (hafta_kuni >= 5))
    # namangan: belgilar bog'liqligi deyarli yo'q - modellash qiyin segment
    qiyin = (hudud == "namangan")
    kuch[qiyin] = -1.5 + rng.normal(0, 0.4, int(qiyin.sum()))
    y = (rng.random(n) < 1 / (1 + np.exp(-kuch))).astype(int)
    df = pd.DataFrame({"hudud": hudud, "tur": tur, "kanal": kanal,
                       "masofa": masofa, "ogirlik": ogirlik, "soat": soat,
                       "hafta_kuni": hafta_kuni,
                       "kuryer_tajribasi": kuryer_tajribasi, "kechikdi": y})
    df.loc[rng.random(n) < 0.05, "kuryer_tajribasi"] = np.nan
    return df


def main() -> None:
    df = yarat()
    X = df.drop(columns="kechikdi")
    y = df["kechikdi"]
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.25, random_state=0,
                                          stratify=y)
    kategoriya = ["hudud", "tur", "kanal"]
    sonli = ["masofa", "ogirlik", "soat", "hafta_kuni", "kuryer_tajribasi"]
    quvur = Pipeline([
        ("t", ColumnTransformer([
            ("k", OneHotEncoder(handle_unknown="ignore"), kategoriya),
            ("s", SimpleImputer(strategy="median"), sonli)])),
        ("m", HistGradientBoostingClassifier(learning_rate=0.05, max_iter=1000,
                                             max_depth=5, min_samples_leaf=40,
                                             early_stopping=True,
                                             validation_fraction=0.15,
                                             n_iter_no_change=30,
                                             random_state=0))]).fit(Xtr, ytr)
    p = quvur.predict_proba(Xte)[:, 1]

    print("=== 1. Umumiy natija ===")
    print(f"  test ROC AUC: {roc_auc_score(yte, p):.4f}")
    print(f"  Brier: {brier_score_loss(yte, p):.5f}")
    print(f"  o'rtacha bashorat {p.mean():.4f}, haqiqiy {yte.mean():.4f}")

    print("\n=== 2. Segmentlar bo'yicha ===")
    print(f"  {'hudud':<12} {'namunalar':>10} {'kechikish':>10} {'AUC':>8}")
    for h in sorted(Xte["hudud"].unique()):
        m = (Xte["hudud"] == h).to_numpy()
        if yte[m].nunique() < 2:
            continue
        print(f"  {h:<12} {int(m.sum()):>10} {yte[m].mean():>9.2%} "
              f"{roc_auc_score(yte[m], p[m]):>8.4f}")
    print("  (namangan segmentida signal yo'q - AUC tasodifiyga yaqin)")

    print("\n=== 3. Kalibrlash ===")
    haqiqiy, bashorat = calibration_curve(yte, p, n_bins=8, strategy="quantile")
    print(f"  {'bashorat':>10} {'haqiqiy':>10} {'farq':>9}")
    for b, h in zip(bashorat, haqiqiy):
        print(f"  {b:>10.4f} {h:>10.4f} {h - b:>+9.4f}")

    print("\n=== 4. Permutation importance (test) ===")
    r = permutation_importance(quvur, Xte, yte, n_repeats=10,
                               scoring="roc_auc", random_state=0, n_jobs=1)
    tartib = np.argsort(-r.importances_mean)
    print(f"  {'belgi':<20} {'muhimlik':>10} {'std':>8}")
    for i in tartib:
        print(f"  {X.columns[i]:<20} {r.importances_mean[i]:>+10.4f} "
              f"{r.importances_std[i]:>8.4f}")
    print("  (bu bashorat foydaliligi, sababiy ta'sir EMAS)")
    print("  ⭐ Segment tahlili umumiy metrika yashirgan muammoni ochadi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Umumiy natija ===
  test ROC AUC: 0.7394
  Brier: 0.12813
  o'rtacha bashorat 0.1770, haqiqiy 0.1780

=== 2. Segmentlar bo'yicha ===
  hudud         namunalar  kechikish      AUC
  buxoro              479    22.55%   0.7553
  fargona             597    16.92%   0.7394
  namangan            258    21.71%   0.4860
  samarqand           593    22.26%   0.7744
  toshkent           1073    12.77%   0.7452
  (namangan segmentida signal yo'q - AUC tasodifiyga yaqin)

=== 3. Kalibrlash ===
    bashorat    haqiqiy      farq
      0.0332     0.0347   +0.0014
      0.0647     0.0853   +0.0206
      0.0897     0.0667   -0.0230
      0.1159     0.1253   +0.0094
      0.1523     0.1600   +0.0077
      0.2052     0.2347   +0.0295
      0.2855     0.2427   -0.0429
      0.4697     0.4747   +0.0050

=== 4. Permutation importance (test) ===
  belgi                  muhimlik      std
  soat                    +0.0562   0.0069
  masofa                  +0.0548   0.0027
  tur                     +0.0533   0.0080
  hudud                   +0.0418   0.0049
  kuryer_tajribasi        +0.0217   0.0058
  ogirlik                 +0.0091   0.0026
  hafta_kuni              +0.0032   0.0013
  kanal                   +0.0006   0.0009
  (bu bashorat foydaliligi, sababiy ta'sir EMAS)
  ⭐ Segment tahlili umumiy metrika yashirgan muammoni ochadi

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

Misol 4 — Chegara, taqqoslash va chiqarish

python
"""8-9 qadamlar: chegara, yakuniy baho, saqlash (real pandas/sklearn/joblib)."""

import io
import pickle

import numpy as np
import pandas as pd
import sklearn
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import HistGradientBoostingClassifier, RandomForestClassifier
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import (average_precision_score, f1_score,
                             precision_recall_curve, precision_score,
                             recall_score, roc_auc_score)
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler


def yarat(seed: int = 42, n: int = 12000) -> pd.DataFrame:
    rng = np.random.default_rng(seed)
    hudud = rng.choice(["toshkent", "samarqand", "buxoro", "fargona",
                        "namangan"], n, p=[0.35, 0.2, 0.15, 0.2, 0.1])
    tur = rng.choice(["oddiy", "tezkor", "yirik"], n, p=[0.6, 0.3, 0.1])
    kanal = rng.choice(["ilova", "sayt", "qongiroq"], n, p=[0.5, 0.35, 0.15])
    masofa = rng.gamma(3, 60, n)
    ogirlik = rng.gamma(2, 4, n)
    soat = rng.integers(0, 24, n).astype(float)
    hafta_kuni = rng.integers(0, 7, n).astype(float)
    kuryer_tajribasi = rng.gamma(2, 8, n)
    hq = pd.Series(hudud).map({"toshkent": 0.0, "samarqand": 0.5,
                               "buxoro": 0.9, "fargona": 0.4,
                               "namangan": 0.6}).to_numpy()
    tt = pd.Series(tur).map({"oddiy": 0.0, "tezkor": -0.9,
                             "yirik": 1.1}).to_numpy()
    tig = ((soat >= 7) & (soat <= 10)) | ((soat >= 17) & (soat <= 19))
    kuch = (-3.2 + 0.005 * masofa + 0.04 * ogirlik + hq + tt + 1.0 * tig
            + 0.8 * (tig & (hq > 0.4)) - 0.04 * kuryer_tajribasi
            + 0.4 * (hafta_kuni >= 5))
    y = (rng.random(n) < 1 / (1 + np.exp(-kuch))).astype(int)
    df = pd.DataFrame({"hudud": hudud, "tur": tur, "kanal": kanal,
                       "masofa": masofa, "ogirlik": ogirlik, "soat": soat,
                       "hafta_kuni": hafta_kuni,
                       "kuryer_tajribasi": kuryer_tajribasi, "kechikdi": y})
    df.loc[rng.random(n) < 0.05, "kuryer_tajribasi"] = np.nan
    return df


def tayyorlagich(kategoriya, sonli, masshtab: bool = False):
    sonli_quvur = ([("imp", SimpleImputer(strategy="median")),
                    ("sc", StandardScaler())] if masshtab
                   else [("imp", SimpleImputer(strategy="median"))])
    return ColumnTransformer([
        ("k", OneHotEncoder(handle_unknown="ignore"), kategoriya),
        ("s", Pipeline(sonli_quvur), sonli)])


def hajm_kb(model) -> float:
    bufer = io.BytesIO()
    pickle.dump(model, bufer, protocol=pickle.HIGHEST_PROTOCOL)
    return bufer.tell() / 1024


def main() -> None:
    df = yarat()
    X = df.drop(columns="kechikdi")
    y = df["kechikdi"]
    Xtr, Xqol, ytr, yqol = train_test_split(X, y, test_size=0.4,
                                            random_state=0, stratify=y)
    Xval, Xte, yval, yte = train_test_split(Xqol, yqol, test_size=0.5,
                                            random_state=0, stratify=yqol)
    kategoriya = ["hudud", "tur", "kanal"]
    sonli = ["masofa", "ogirlik", "soat", "hafta_kuni", "kuryer_tajribasi"]

    print("=== 1. Yakuniy nomzodlar (test da BIR MARTA) ===")
    nomzodlar = {
        "LogReg": Pipeline([("t", tayyorlagich(kategoriya, sonli, True)),
                            ("m", LogisticRegression(max_iter=2000))]),
        "RandomForest": Pipeline([("t", tayyorlagich(kategoriya, sonli)),
                                  ("m", RandomForestClassifier(
                                      n_estimators=400, max_features="sqrt",
                                      min_samples_leaf=5, random_state=0,
                                      n_jobs=1))]),
        "HistGB": Pipeline([("t", tayyorlagich(kategoriya, sonli)),
                            ("m", HistGradientBoostingClassifier(
                                learning_rate=0.05, max_iter=1000, max_depth=5,
                                min_samples_leaf=40, early_stopping=True,
                                validation_fraction=0.15, n_iter_no_change=30,
                                random_state=0))]),
    }
    print(f"  {'model':<14} {'ROC AUC':>9} {'PR AUC':>9} {'hajm KB':>10}")
    ehtimolliklar = {}
    for nom, m in nomzodlar.items():
        m.fit(Xtr, ytr)
        pv = m.predict_proba(Xval)[:, 1]
        pt = m.predict_proba(Xte)[:, 1]
        ehtimolliklar[nom] = (pv, pt)
        print(f"  {nom:<14} {roc_auc_score(yte, pt):>9.4f} "
              f"{average_precision_score(yte, pt):>9.4f} "
              f"{hajm_kb(m):>10.0f}")

    print("\n=== 2. Chegarani validatsiyada tanlash (HistGB) ===")
    pv, pt = ehtimolliklar["HistGB"]
    pr, rc, ch = precision_recall_curve(yval, pv)
    f1 = 2 * pr[:-1] * rc[:-1] / np.maximum(pr[:-1] + rc[:-1], 1e-12)
    eng_f1 = float(ch[int(np.argmax(f1))])
    # biznes cheklovi: aniqlik (precision) >= 0.60
    mos = np.where(pr[:-1] >= 0.60)[0]
    eng_biz = float(ch[mos[int(np.argmax(rc[:-1][mos]))]]) if len(mos) else 0.5
    print(f"  F1 bo'yicha: {eng_f1:.4f}")
    print(f"  precision>=0.60 sharti bilan: {eng_biz:.4f}")

    print("\n=== 3. Chegaralar test da ===")
    print(f"  {'chegara':>9} {'precision':>11} {'recall':>9} {'F1':>8} "
          f"{'belgilangan %':>15}")
    for nom, t in [("0.50", 0.5), ("F1", eng_f1), ("biznes", eng_biz)]:
        tahmin = (pt > t).astype(int)
        print(f"  {nom:>9} {precision_score(yte, tahmin):>11.4f} "
              f"{recall_score(yte, tahmin):>9.4f} "
              f"{f1_score(yte, tahmin):>8.4f} {tahmin.mean():>14.1%}")

    print("\n=== 4. Chiqarish paketi ===")
    yakuniy = nomzodlar["HistGB"]
    paket = {
        "quvur": yakuniy,
        "belgilar": list(X.columns),
        "chegara": round(eng_biz, 4),
        "chegara_asosi": "validatsiyada precision >= 0.60 sharti bilan",
        "versiyalar": {"sklearn": sklearn.__version__,
                       "numpy": np.__version__, "pandas": pd.__version__},
        "metrika": {"test_roc_auc": round(float(roc_auc_score(yte, pt)), 4),
                    "test_pr_auc": round(float(
                        average_precision_score(yte, pt)), 4)},
        "o_quv_hajmi": len(Xtr),
    }
    print(f"  kalitlar: {sorted(paket)}")
    print(f"  chegara: {paket['chegara']} ({paket['chegara_asosi']})")
    print(f"  metrika: {paket['metrika']}")
    print(f"  model hajmi: {hajm_kb(yakuniy):.0f} KB")
    print(f"  belgilar soni: {len(paket['belgilar'])}")
    print("  ⭐ Model + chegara + metama'lumot = chiqarishga tayyor")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Yakuniy nomzodlar (test da BIR MARTA) ===
  model            ROC AUC    PR AUC    hajm KB
  LogReg            0.7453    0.3874          3
  RandomForest      0.7725    0.4408      30639
  HistGB            0.7851    0.4653        272

=== 2. Chegarani validatsiyada tanlash (HistGB) ===
  F1 bo'yicha: 0.2323
  precision>=0.60 sharti bilan: 0.4403

=== 3. Chegaralar test da ===
    chegara   precision    recall       F1   belgilangan %
       0.50      0.6350    0.2033   0.3080           5.7%
         F1      0.4058    0.5888   0.4805          25.9%
     biznes      0.5950    0.2780   0.3790           8.3%

=== 4. Chiqarish paketi ===
  kalitlar: ['belgilar', 'chegara', 'chegara_asosi', 'metrika', 'o_quv_hajmi', 'quvur', 'versiyalar']
  chegara: 0.4403 (validatsiyada precision >= 0.60 sharti bilan)
  metrika: {'test_roc_auc': 0.7851, 'test_pr_auc': 0.4653}
  model hajmi: 272 KB
  belgilar soni: 8
  ⭐ Model + chegara + metama'lumot = chiqarishga tayyor

Nima ko'rsatdi: 2.6-bo'lim.


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

Noto'g'ri fikr To'g'risi
"Bazaviy model keraksiz" Realistik kutish beradi
"Yuqori AUC — tayyor model" Chegara, kechikish, drift ham kerak
"Kichik farq — yaxshilanish" CV std bilan solishtiring
"Testda bir necha marta baholash mumkin" Bir marta
"Umumiy metrika yetarli" Segmentlarga bo'ling
"0.5 chegara standart" Vazifaga qarab tanlang
"Sozlash qancha uzoq bo'lsa, shuncha yaxshi" Validatsiyaga overfitting
"Eng aniq model eng yaxshi" Narx-foyda

6. Keng tarqalgan xatolar va yechimlari

1. Bazaviy modelsiz

python
# to'g'ridan-to'g'ri boosting sozlash                              # ⚠️
# DummyClassifier + LogisticRegression bilan boshlang              # ✅

2. Testda ko'p marta baholash

python
for m in modellar: print(m.score(Xte, yte))   # tanlov uchun       # ⚠️
# CV da tanlang, testda faqat yakuniy baho                         # ✅

3. std ni hisobga olmaslik

python
# "0.847 > 0.842, demak yaxshiroq"                                 # ⚠️
# std 0.008 bo'lsa - farq ahamiyatsiz                              # ✅

4. Turli shartlarda taqqoslash

python
# RF sozlangan, LogReg standart                                    # ⚠️
# har modelga mos byudjet ajrating                                 # ✅

5. Chegarani 0.5 da qoldirish

python
model.predict(Xte)                                                 # ⚠️
(model.predict_proba(Xte)[:, 1] > tanlangan).astype(int)           # ✅

6. Segment tahlilisiz

python
print(roc_auc_score(yte, p))                                       # ⚠️
# hudud/kanal/davr bo'yicha bo'lib ko'ring                         # ✅

7. Hujjatsiz topshirish

python
joblib.dump(model, "model.joblib")                                 # ⚠️
# quvur + chegara + metrika + versiyalar + tahlil hisoboti         # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 12-qism (o'tilgan): ML asoslari
  • 15.5, 15.8-darslar (o'tilgan): RF va boosting
  • 15.11-dars (o'tilgan): Muhimlik
  • 15.13-dars (o'tilgan): Ishlab chiqarish
  • Keyingi qism: Nazoratsiz o'rganish

8. Eng yaxshi amaliyotlar

  1. Bazaviy modeldan boshlang.

  2. Bir xil shartlarda taqqoslang.

  3. CV std ni ko'ring.

  4. Sozlashni tartib bilan qiling.

  5. Segmentlarga bo'ling.

  6. Chegarani asoslang.

  7. Testni oxirida ishlating.

  8. Hamma narsani hujjatlashtiring.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # oqimning birinchi qadami?
2.  # bazaviy modellar?
3.  # sozlanmagan RF nima uchun?
4.  # halol taqqoslash sharti?
5.  # farq muhimligini qanday bilish?
6.  # RF uchun byudjet?
7.  # boosting uchun?
8.  # xatolar tahlilida birinchi nima?
9.  # muhimlik qaysi to'plamda?
10. # chegara qayerda tanlanadi?
11. # test necha marta?
12. # chiqarishda nima saqlanadi?
Javoblar
  1. Ma'lumotni ko'rish
  2. Dummy va LogisticRegression
  3. Haqiqiy boshlang'ich nuqta
  4. Bir xil CV, metrika, tayyorlash
  5. CV std bilan solishtirish
  6. 5-10 konfiguratsiya
  7. 40-80
  8. Segmentlarga bo'lish
  9. Test
  10. Validatsiyada
  11. Bir marta
  12. Pipeline + metama'lumot + chegara

Vazifa 2: Xatolarni tuzating

python
1.  # to'g'ridan-to'g'ri boosting sozlashdan boshlash

2.  for m in modellar: print(m.score(Xte, yte))

3.  # "0.847 > 0.842, yaxshiroq"   (std 0.008)

4.  model.predict(Xte)   # chegara 0.5

5.  joblib.dump(model, "model.joblib")
Javoblar
python
1.  # DummyClassifier + LogisticRegression bilan boshlang

2.  # CV da tanlang, testda bir marta

3.  # farq std dan kichik - ahamiyatsiz

4.  (model.predict_proba(Xte)[:, 1] > tanlangan).astype(int)

5.  joblib.dump({"quvur": ..., "chegara": ..., "versiyalar": ...}, ...)

Vazifa 3: Bazaviy

Modellang:

  1. Ma'lumot
  2. Ajratish
  3. Bazaviy modellar
  4. Sozlanmagan RF

Vazifa 4: Ansambllar

Modellang:

  1. Uch ansambl
  2. max_features
  3. Tasodifiy qidiruv
  4. eta

Vazifa 5: Tahlil

Modellang:

  1. Umumiy natija
  2. Segmentlar
  3. Kalibrlash
  4. Muhimlik

Vazifa 6: Chiqarish

Modellang:

  1. Nomzodlar
  2. Chegara
  3. Testda chegaralar
  4. Paket

Vazifa 7: O'ylash

Loyihada HistGB 0.8412, Random Forest 0.8389, logistik regressiya 0.8201 AUC berdi (CV std 0.006). Qaysi birini ishlab chiqarishga chiqarish kerak?

Javob

Qisqa javob: HistGB va Random Forest farqi (0.0023) CV standart og'ishidan (0.006) kichik — ya'ni statistik jihatdan ular teng. Tanlov shuning uchun muhandislik mezonlari bo'yicha qilinadi. Logistik regressiya esa sezilarli ortda (0.021 ≈ 3.5 std) — lekin u ham butunlay rad etilmaydi.

1. Farqlarni baholash

Taqqoslash Farq std ga nisbatan Xulosa
HistGB vs RF 0.0023 0.4 std Teng
HistGB vs LogReg 0.0211 3.5 std Sezilarli

2. Teng bo'lganda nima hal qiladi

  1. Model hajmi: RF odatda ancha katta (15.13)
  2. Kechikish: GB odatda tezroq (sayoz daraxtlar)
  3. OOB: RF da bepul validatsiya bor
  4. Sozlash barqarorligi: RF kam sozlanadi, qayta o'qitishda ishonchliroq
  5. Jamoaning tajribasi: qo'llab-quvvatlash osonligi

3. Logistik regressiyani qachon tanlash mumkin

  • Talqin qilish majburiy (regulyator talabi)
  • Kechikish juda qattiq (mikrosekundlar)
  • Model juda tez-tez qayta o'qitiladi
  • 0.021 AUC farqi biznes uchun ahamiyatsiz bo'lsa

Bu qarorni biznes qiymati bilan hisoblang: 0.021 AUC necha so'mga teng?

4. Amaliy tavsiya

  1. HistGB va RF ni kechikish va hajm bo'yicha o'lchang
  2. Ikkalasini segmentlar bo'yicha solishtiring
  3. Kalibrlashni tekshiring
  4. Qolgan mezonlar teng bo'lsa — kichikroq va tezroq modelni tanlang
  5. Qarorni va uning asosini hujjatlashtiring

5. Xulosa

  1. Farq std dan kichik bo'lsa — modellar teng
  2. Tanlov muhandislik mezonlari bo'yicha
  3. Soddaroq model — kamroq xavf
  4. Qarorni hujjatlashtiring

Nimani mustahkamlaydi: 2.2, 2.6-bo'limlar.


Xulosa

Bu darsda to'liq ansambl loyihasini qurdik.

Eng muhim uch fikr:

  1. Tartib bilan ishlang. Ma'lumot → ajratish → bazaviy (Dummy + LogReg) → sozlanmagan RF → boosting + erta to'xtatish → tartibli sozlash → xatolar tahlili → chegara → chiqarish. Bazaviy modellar sizga realistik kutish beradi: ularsiz 0.87 AUC yaxshimi yoki yomonmi — bilib bo'lmaydi.

  2. Halol taqqoslang va std ni ko'ring. Modellarni bir xil CV bo'linishi, metrika va tayyorlash bilan solishtiring, har biriga mos sozlash byudjeti ajrating. Eng muhimi: yutuqni CV standart og'ishi bilan taqqoslang — farq std dan kichik bo'lsa, modellar teng va soddaroq/tezroq bo'lganini tanlang.

  3. Metrika — ishning yarmi. Umumiy AUC segmentlar bo'yicha bo'linganda ko'pincha bitta muammoli guruhni yashiradi. Chegarani validatsiyada, biznes sharti bilan tanlang va asoslang. Yakunda Pipeline + chegara + metrikalar + versiyalar + tahlil hisoboti topshiriladi — modelning o'zi emas.

Bu bilan 15-qism — Daraxtlar va ansambllar yakunlandi. Keyingi qismda nazoratsiz o'rganishni o'rganamiz: klasterlash, o'lchamni kamaytirish va anomaliyalarni aniqlash.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
15.14-dars: Amaliyot — to'liq ansambl loyihasi — IlmHamroh