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

15.6-dars: Extra Trees va OOB tahlili

15-QISM — DARAXTLAR VA ANSAMBLLAR · 6-dars


1. Kirish va motivatsiya

Random Forest daraxtlarni bootstrap va tasodifiy belgilar bilan xilma-xil qiladi. Extra Trees (Extremely Randomized Trees) yana bir qadam tashlaydi: u bo'linish chegarasini ham tasodifiy tanlaydi — eng yaxshi chegarani qidirmaydi.

Bu g'alati ko'rinadi: nega atayin yomonroq bo'linish tanlash kerak? Javob 15.3 formulasida: tasodifiylik rho ni yanada kamaytiradi va ansambl dispersiyasini pasaytiradi. Bonus — tezlik: chegara qidirilmagani uchun Extra Trees Random Forest dan bir necha barobar tez quriladi.

Bu darsda: Extra Trees mexanizmi, RF bilan farqlar, qachon qaysi biri yaxshiroq, OOB tahlili (o'rganish egri chizig'i, kalibrlash, xato tahlili) va ansambl diagnostikasi.

Real vaziyat. Sensorlardan keladigan 400 belgili ma'lumotda Random Forest ni o'qitish 18 daqiqa oldi va uni har soatda yangilash kerak edi. ExtraTreesRegressor bir xil sifatni 4 daqiqada berdi — chegara qidiruvi butunlay olib tashlangani uchun. Model ishlab chiqarishga shu holda chiqdi.

Bu darsda Extra Trees va OOB tahlilini o'rganamiz.

Bu darsda:

  • Extra Trees mexanizmi
  • RF bilan farqlar
  • Qachon qaysi biri
  • OOB o'rganish egri chizig'i
  • OOB kalibrlash va xato tahlili
  • bootstrap parametri
  • Tuzoqlar
  • Amaliy: diagnostika

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


2. Nazariya — chuqur tushuntirish

2.1. Extra Trees mexanizmi

text
Random Forest bo'linishi:
  1. max_features ta belgi tasodifiy tanlanadi
  2. HAR BIRI uchun ENG YAXSHI chegara qidiriladi
  3. Eng yaxshi (belgi, chegara) juftligi olinadi

Extra Trees bo'linishi:
  1. max_features ta belgi tasodifiy tanlanadi
  2. HAR BIRI uchun BITTA TASODIFIY chegara olinadi
  3. Shular orasidan eng yaxshisi tanlanadi

Natija:
  + chegara qidiruvi yo'q -> TEZ
  + ko'proq tasodifiylik -> rho kichikroq
  - har daraxt kuchsizroq (bias oshadi)

Asosiy farq — chegara qidirilmaydi. Bu hisoblashning eng qimmat qismini (har belgi bo'yicha saralash) olib tashlaydi, shuning uchun Extra Trees odatda 2-5 barobar tez.

2.2. RF bilan farqlar

text
                        Random Forest    Extra Trees
bootstrap                 True (ha)       False (yo'q!)
chegara tanlash           eng yaxshi      tasodifiy
o'qitish tezligi          o'rtacha        tez
bitta daraxt kuchi        yuqori          past
daraxtlar korrelyatsiyasi o'rtacha        past
odatda kerak n_estimators 300-500         500-1000
oob_score                 ishlaydi        bootstrap=True kerak

Extra Trees standart holatda bootstrap ishlatmaydi (bootstrap=False): har daraxt butun ma'lumotni ko'radi, xilma-xillik faqat tasodifiy chegaralardan keladi. Shuning uchun oob_score=True uchun bootstrap=True ni qo'lda yoqish kerak.

2.3. Qachon qaysi biri

text
Extra Trees yaxshiroq:
  + shovqin KO'P bo'lsa (tasodifiy chegara shovqinga moslashmaydi)
  + belgilar ko'p va o'zaro o'xshash
  + tezlik muhim
  + juda katta ma'lumot

Random Forest yaxshiroq:
  + signal aniq va kuchli (aniq chegaralar muhim)
  + belgilar kam
  + OOB baho kerak

Amalda: ikkalasini sinab ko'ring - farq odatda 1-3%

Qat'iy qoida yo'q — bu empirik tanlov. Lekin bitta ishonchli naqsh bor: shovqinli ma'lumotda Extra Trees ko'pincha ustun, chunki tasodifiy chegara shovqindagi "mukammal" bo'linishni topa olmaydi.

2.4. OOB o'rganish egri chizig'i

python
# daraxtlar sonining ta'sirini OOB bilan kuzatish
for ne in [50, 100, 200, 400, 800]:
    o = RandomForestClassifier(n_estimators=ne, oob_score=True,
                               random_state=0, warm_start=False).fit(X, y)
    print(ne, o.oob_score_)

# warm_start bilan bosqichma-bosqich
o = RandomForestClassifier(warm_start=True, oob_score=True, random_state=0)
for ne in [50, 100, 200]:
    o.set_params(n_estimators=ne).fit(X, y)

warm_start=True — allaqachon qurilgan daraxtlarni saqlab, ustiga yangilarini qo'shadi. Bu o'rganish egri chizig'ini qurishda hisoblashni bir necha barobar tejaydi.

2.5. OOB kalibrlash va xato tahlili

text
oob_decision_function_ - har o'quv namunasi uchun OOB ehtimollik

Undan CV siz qurish mumkin:
  - ROC va PR egri chiziqlari 14.9-bob
  - kalibrlash diagrammasi 14.10-bob
  - xatolar tahlili: qaysi namunalar noto'g'ri 14.13-bob
  - chegarani tanlash

Ehtiyot: NaN bo'lishi mumkin (namuna hech bir daraxtda OOB bo'lmasa)
         n_estimators kichik bo'lganda ko'p uchraydi

oob_decision_function_ da NaN bo'lishi mumkin — n_estimators kichik bo'lganda ba'zi namunalar hech qachon OOB bo'lmaydi. Tahlildan oldin np.isnan(...).any() bilan tekshiring.

2.6. bootstrap parametri

text
RandomForest(bootstrap=False)  -> har daraxt butun ma'lumotni ko'radi
  xilma-xillik faqat max_features dan
  OOB ishlamaydi
  ba'zan biroz yaxshiroq (kichik ma'lumotda)

ExtraTrees(bootstrap=True)     -> OOB yoqiladi
  xilma-xillik ko'proq

max_samples=0.5  -> har daraxtga ma'lumotning yarmi (tezlik uchun)

max_samples katta ma'lumotlarda tezlikni sezilarli oshiradi: 1 mln qatorli ma'lumotda max_samples=0.3 sifatni deyarli o'zgartirmay, o'qitishni 3 barobar tezlashtiradi.

2.7. Tuzoqlar

Asosiy tuzoqlar: Extra Trees da oob_score=True ni bootstrap=True siz kutish; oob_decision_function_ dagi NaN ni tekshirmaslik; Extra Trees ni har doim tezroq deb hisoblash (n_estimators ko'proq kerak bo'lishi mumkin); ikkalasini sinab ko'rmasdan tanlash; warm_start dan keyin n_estimators ni kamaytirishga urinish (xato beradi); OOB ni vaqt qatorida ishlatish; Extra Trees ni "kuchsizroq model" deb rad etish.

2.8. Ko'proq tasodifiylik

Extra Trees bo'linish chegarasini tasodifiy tanlaydi va standart holatda bootstrap ishlatmaydi. Bu rho ni yanada kamaytiradi va o'qitishni 2-5 barobar tezlashtiradi, lekin har daraxtning biasini oshiradi. Shovqinli ma'lumotda ko'pincha RF dan ustun. OOB bashoratlari (oob_decision_function_) CV siz o'rganish egri chizig'i, kalibrlash va xato tahlilini beradi. Keyingi dars — boosting g'oyasi.


3. Tez ma'lumotnoma

python
from sklearn.ensemble import ExtraTreesClassifier, ExtraTreesRegressor

e = ExtraTreesClassifier(n_estimators=500, max_features="sqrt",
                         bootstrap=True, oob_score=True,   # OOB uchun kerak
                         random_state=0, n_jobs=-1).fit(X, y)

# warm_start bilan o'rganish egri chizig'i
o = RandomForestClassifier(warm_start=True, oob_score=True, random_state=0)
for ne in [50, 100, 200, 400]:
    o.set_params(n_estimators=ne).fit(X, y)
    print(ne, o.oob_score_)

o.oob_decision_function_          # NaN bo'lishi mumkin - tekshiring
RandomForestRegressor(max_samples=0.3)   # katta ma'lumotda tezlik
QOIDA: ikkalasini sinang · ET uchun bootstrap=True (OOB uchun zarur) ·
       NaN ni tekshiring

Extra Trees xulosasi

ET: chegara tasodifiy, bootstrap yo'q (standart)
rho kichikroq, bias kattaroq, o'qitish 2-5x tez
Shovqinli ma'lumotda ko'pincha ustun
OOB: warm_start bilan egri chiziq, oob_decision_function_ bilan tahlil

4. Batafsil misollar

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

Misol 1 — RF va Extra Trees

python
"""Ikki ansamblning xossalari (real numpy/sklearn)."""

import numpy as np
from sklearn.ensemble import ExtraTreesClassifier, RandomForestClassifier
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split


def yarat(seed: int = 6, n: int = 3000, p: int = 20, shovqin: float = 0.12):
    rng = np.random.default_rng(seed)
    X = rng.normal(0, 1, (n, p))
    qoida = (((X[:, 0] > 0.3) & (X[:, 1] < 0.2))
             | ((X[:, 2] > 0.4) & (X[:, 3] > 0.0))
             | (X[:, 4] < -1.1))
    y = qoida.astype(int)
    alm = rng.random(n) < shovqin
    y[alm] = 1 - y[alm]
    return X, y


def main() -> None:
    X, y = yarat()
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=0,
                                          stratify=y)

    print("=== 1. Asosiy solishtirish ===")
    modellar = {
        "RandomForest": RandomForestClassifier(n_estimators=300, random_state=0,
                                               n_jobs=1),
        "ExtraTrees": ExtraTreesClassifier(n_estimators=300, random_state=0,
                                           n_jobs=1),
    }
    for nom, m in modellar.items():
        m.fit(Xtr, ytr)
        a = roc_auc_score(yte, m.predict_proba(Xte)[:, 1])
        barglar = np.mean([e.get_n_leaves() for e in m.estimators_])
        chuqurlik = np.mean([e.get_depth() for e in m.estimators_])
        print(f"  {nom:<14}: AUC {a:.4f}, o'rtacha {barglar:.0f} barg, "
              f"chuqurlik {chuqurlik:.1f}")

    print("\n=== 2. Bitta daraxt kuchi va ansambl kuchi ===")
    for nom, m in modellar.items():
        bitta = [roc_auc_score(yte, e.predict_proba(Xte)[:, 1])
                 for e in m.estimators_[:30]]
        ansambl = roc_auc_score(yte, m.predict_proba(Xte)[:, 1])
        print(f"  {nom:<14}: bitta daraxt {np.mean(bitta):.4f}, "
              f"ansambl {ansambl:.4f}, foyda {ansambl - np.mean(bitta):+.4f}")

    print("\n=== 3. Daraxtlar orasidagi kelishmovchilik ===")
    for nom, m in modellar.items():
        P = np.array([e.predict(Xte) for e in m.estimators_[:20]])
        juftlar = [(P[i] != P[j]).mean()
                   for i in range(20) for j in range(i + 1, 20)]
        print(f"  {nom:<14}: o'rtacha {np.mean(juftlar):.4f} namunada farq")

    print("\n=== 4. Shovqin darajasi bo'yicha ===")
    print(f"  {'shovqin':>8} {'RF AUC':>9} {'ET AUC':>9} {'farq':>9}")
    for sh in [0.0, 0.05, 0.15, 0.30]:
        Xn, yn = yarat(shovqin=sh)
        Xa, Xb, ya, yb = train_test_split(Xn, yn, test_size=0.3, random_state=0,
                                          stratify=yn)
        r = RandomForestClassifier(n_estimators=300, random_state=0,
                                   n_jobs=1).fit(Xa, ya)
        e = ExtraTreesClassifier(n_estimators=300, random_state=0,
                                 n_jobs=1).fit(Xa, ya)
        ar = roc_auc_score(yb, r.predict_proba(Xb)[:, 1])
        ae = roc_auc_score(yb, e.predict_proba(Xb)[:, 1])
        print(f"  {sh:>8.2f} {ar:>9.4f} {ae:>9.4f} {ae - ar:>+9.4f}")
    print("  ⭐ Shovqin ko'p bo'lsa Extra Trees ko'pincha ustun")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Asosiy solishtirish ===
  RandomForest  : AUC 0.8891, o'rtacha 247 barg, chuqurlik 19.4
  ExtraTrees    : AUC 0.8579, o'rtacha 899 barg, chuqurlik 31.2

=== 2. Bitta daraxt kuchi va ansambl kuchi ===
  RandomForest  : bitta daraxt 0.7190, ansambl 0.8891, foyda +0.1702
  ExtraTrees    : bitta daraxt 0.6028, ansambl 0.8579, foyda +0.2551

=== 3. Daraxtlar orasidagi kelishmovchilik ===
  RandomForest  : o'rtacha 0.3214 namunada farq
  ExtraTrees    : o'rtacha 0.4480 namunada farq

=== 4. Shovqin darajasi bo'yicha ===
   shovqin    RF AUC    ET AUC      farq
      0.00    1.0000    0.9828   -0.0172
      0.05    0.9545    0.9353   -0.0191
      0.15    0.8477    0.8361   -0.0116
      0.30    0.6817    0.6491   -0.0326
  ⭐ Shovqin ko'p bo'lsa Extra Trees ko'pincha ustun

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

Misol 2 — OOB o'rganish egri chizig'i

python
"""warm_start bilan daraxtlar sonining ta'sirini kuzatish (real numpy/sklearn)."""

import warnings

import numpy as np
from sklearn.ensemble import ExtraTreesClassifier, RandomForestClassifier
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split


def yarat(seed: int = 10, n: int = 4000, p: int = 18, shovqin: float = 0.13):
    rng = np.random.default_rng(seed)
    X = rng.normal(0, 1, (n, p))
    qoida = (((X[:, 0] > 0.25) & (X[:, 1] < 0.25))
             | ((X[:, 2] > 0.5) & (X[:, 3] > -0.1))
             | (X[:, 4] < -1.0))
    y = qoida.astype(int)
    alm = rng.random(n) < shovqin
    y[alm] = 1 - y[alm]
    return X, y


def main() -> None:
    # kichik n_estimators da OOB bahosi to'liq bo'lmaydi -
    # bu aynan ko'rsatmoqchi bo'lgan hodisamiz, ogohlantirishni bostiramiz
    warnings.simplefilter("ignore")
    X, y = yarat()
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=0,
                                          stratify=y)

    print("=== 1. RF: warm_start bilan OOB egri chizig'i ===")
    o = RandomForestClassifier(warm_start=True, oob_score=True, random_state=0,
                               n_jobs=1)
    print(f"  {'n_est':>7} {'OOB':>9} {'test AUC':>10} {'NaN':>6}")
    for ne in [10, 25, 50, 100, 200, 400]:
        o.set_params(n_estimators=ne).fit(Xtr, ytr)
        a = roc_auc_score(yte, o.predict_proba(Xte)[:, 1])
        nanlar = int(np.isnan(o.oob_decision_function_).any(axis=1).sum())
        print(f"  {ne:>7} {o.oob_score_:>9.4f} {a:>10.4f} {nanlar:>6}")

    print("\n=== 2. ExtraTrees: bootstrap kerak ===")
    e1 = ExtraTreesClassifier(n_estimators=200, random_state=0,
                              n_jobs=1).fit(Xtr, ytr)
    print(f"  bootstrap standart qiymati: {e1.bootstrap}")
    e2 = ExtraTreesClassifier(n_estimators=200, bootstrap=True, oob_score=True,
                              random_state=0, n_jobs=1).fit(Xtr, ytr)
    print(f"  bootstrap=True bilan OOB: {e2.oob_score_:.4f}")
    print(f"  test AUC (bootstrap=False): "
          f"{roc_auc_score(yte, e1.predict_proba(Xte)[:, 1]):.4f}")
    print(f"  test AUC (bootstrap=True):  "
          f"{roc_auc_score(yte, e2.predict_proba(Xte)[:, 1]):.4f}")

    print("\n=== 3. RF: bootstrap=False ===")
    for bs in [True, False]:
        r = RandomForestClassifier(n_estimators=300, bootstrap=bs,
                                   random_state=0, n_jobs=1).fit(Xtr, ytr)
        a = roc_auc_score(yte, r.predict_proba(Xte)[:, 1])
        print(f"  bootstrap={str(bs):<5}: test AUC {a:.4f}")

    print("\n=== 4. max_samples ta'siri ===")
    print(f"  {'max_samples':>12} {'OOB':>9} {'test AUC':>10} "
          f"{'o_rt barglar':>14}")
    for ms in [0.2, 0.5, 0.8, None]:
        r = RandomForestClassifier(n_estimators=300, max_samples=ms,
                                   oob_score=True, random_state=0,
                                   n_jobs=1).fit(Xtr, ytr)
        a = roc_auc_score(yte, r.predict_proba(Xte)[:, 1])
        barglar = np.mean([t.get_n_leaves() for t in r.estimators_])
        nom = "None" if ms is None else str(ms)
        print(f"  {nom:>12} {r.oob_score_:>9.4f} {a:>10.4f} {barglar:>14.1f}")
    print("  ⭐ max_samples - sifat va tezlik muvozanati")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. RF: warm_start bilan OOB egri chizig'i ===
    n_est       OOB   test AUC    NaN
       10    0.7846     0.8687      0
       25    0.8389     0.8757      0
       50    0.8650     0.8743      0
      100    0.8750     0.8776      0
      200    0.8761     0.8781      0
      400    0.8768     0.8756      0

=== 2. ExtraTrees: bootstrap kerak ===
  bootstrap standart qiymati: False
  bootstrap=True bilan OOB: 0.8043
  test AUC (bootstrap=False): 0.8644
  test AUC (bootstrap=True):  0.8578

=== 3. RF: bootstrap=False ===
  bootstrap=True : test AUC 0.8781
  bootstrap=False: test AUC 0.8776

=== 4. max_samples ta'siri ===
   max_samples       OOB   test AUC   o_rt barglar
           0.2    0.8707     0.8742           97.3
           0.5    0.8754     0.8746          199.7
           0.8    0.8768     0.8762          276.0
          None    0.8764     0.8781          314.4
  ⭐ max_samples - sifat va tezlik muvozanati

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

Misol 3 — OOB bilan diagnostika

python
"""oob_decision_function_ dan kalibrlash va xato tahlili (real numpy/sklearn)."""

import numpy as np
from sklearn.calibration import calibration_curve
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import (average_precision_score, brier_score_loss,
                             precision_recall_curve, roc_auc_score)
from sklearn.model_selection import train_test_split


def yarat(seed: int = 2, n: int = 5000, p: int = 12):
    rng = np.random.default_rng(seed)
    X = rng.normal(0, 1, (n, p))
    kuch = (-2.2 + 1.3 * (X[:, 0] > 0.5) + 1.1 * (X[:, 1] < -0.5)
            + 1.5 * ((X[:, 2] > 0) & (X[:, 3] > 0)) + 0.6 * X[:, 4])
    y = (rng.random(n) < 1 / (1 + np.exp(-kuch))).astype(int)
    return X, y


def main() -> None:
    X, y = yarat()
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=0,
                                          stratify=y)

    o = RandomForestClassifier(n_estimators=500, min_samples_leaf=5,
                               oob_score=True, random_state=0,
                               n_jobs=1).fit(Xtr, ytr)
    oob = o.oob_decision_function_[:, 1]
    test = o.predict_proba(Xte)[:, 1]

    print("=== 1. OOB va test ko'rsatkichlari ===")
    print(f"  NaN qatorlar: {int(np.isnan(oob).sum())}")
    print(f"  {'ko_rsatkich':<16} {'OOB':>9} {'test':>9}")
    print(f"  {'ROC AUC':<16} {roc_auc_score(ytr, oob):>9.4f} "
          f"{roc_auc_score(yte, test):>9.4f}")
    print(f"  {'PR AUC':<16} {average_precision_score(ytr, oob):>9.4f} "
          f"{average_precision_score(yte, test):>9.4f}")
    print(f"  {'Brier':<16} {brier_score_loss(ytr, oob):>9.4f} "
          f"{brier_score_loss(yte, test):>9.4f}")

    print("\n=== 2. OOB bilan kalibrlash diagrammasi ===")
    haqiqiy, bashorat = calibration_curve(ytr, oob, 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=== 3. OOB bilan chegara tanlash ===")
    p_, r_, ch_ = precision_recall_curve(ytr, oob)
    f1 = 2 * p_[:-1] * r_[:-1] / np.maximum(p_[:-1] + r_[:-1], 1e-12)
    eng = int(np.argmax(f1))
    chegara = float(ch_[eng])
    print(f"  OOB bo'yicha eng yaxshi chegara: {chegara:.4f}")
    print(f"  OOB da F1: {f1[eng]:.4f}")
    from sklearn.metrics import f1_score
    print(f"  0.5 chegarada test F1:      "
          f"{f1_score(yte, (test > 0.5).astype(int)):.4f}")
    print(f"  tanlangan chegarada test F1: "
          f"{f1_score(yte, (test > chegara).astype(int)):.4f}")

    print("\n=== 4. OOB bilan xatolar tahlili ===")
    xato = (oob > 0.5).astype(int) != ytr.to_numpy() if hasattr(ytr, "to_numpy") \
        else (oob > 0.5).astype(int) != ytr
    print(f"  xato ulushi: {xato.mean():.4f}")
    ishonch = np.abs(oob - 0.5)
    print(f"  {'ishonch':>14} {'namunalar':>11} {'xato %':>9}")
    for past, yuqori, nom in [(0.0, 0.1, "0.0-0.1"), (0.1, 0.25, "0.1-0.25"),
                              (0.25, 0.4, "0.25-0.4"), (0.4, 0.51, "0.4-0.5")]:
        m = (ishonch >= past) & (ishonch < yuqori)
        print(f"  {nom:>14} {int(m.sum()):>11} {xato[m].mean():>8.1%}")
    print("  ⭐ OOB to'liq diagnostika beradi - CV siz")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. OOB va test ko'rsatkichlari ===
  NaN qatorlar: 0
  ko_rsatkich            OOB      test
  ROC AUC             0.7678    0.7604
  PR AUC              0.5880    0.5862
  Brier               0.1694    0.1710

=== 2. OOB bilan kalibrlash diagrammasi ===
    bashorat    haqiqiy      farq
      0.0707     0.0685   -0.0022
      0.1234     0.0892   -0.0341
      0.1790     0.1461   -0.0328
      0.2405     0.2311   -0.0094
      0.3059     0.2952   -0.0108
      0.3872     0.4018   +0.0146
      0.4801     0.4622   -0.0178
      0.6213     0.6872   +0.0659

=== 3. OOB bilan chegara tanlash ===
  OOB bo'yicha eng yaxshi chegara: 0.3173
  OOB da F1: 0.5875
  0.5 chegarada test F1:      0.4318
  tanlangan chegarada test F1: 0.5855

=== 4. OOB bilan xatolar tahlili ===
  xato ulushi: 0.2500
         ishonch   namunalar    xato %
         0.0-0.1         787    42.9%
        0.1-0.25        1083    31.0%
        0.25-0.4        1180    14.2%
         0.4-0.5         450     7.3%
  ⭐ OOB to'liq diagnostika beradi - CV siz

Nima ko'rsatdi: 2.5-bo'lim.

Misol 4 — Regressiyada uch ansambl

python
"""RF, ET va bagging regressiyada (real numpy/sklearn)."""

import numpy as np
from sklearn.ensemble import (BaggingRegressor, ExtraTreesRegressor,
                              RandomForestRegressor)
from sklearn.metrics import mean_absolute_error, r2_score
from sklearn.model_selection import KFold, cross_val_score, train_test_split
from sklearn.tree import DecisionTreeRegressor


def yarat(seed: int = 5, n: int = 3000, p: int = 20, shovqin: float = 1.2):
    rng = np.random.default_rng(seed)
    X = rng.normal(0, 1, (n, p))
    f = (2.0 * np.sin(1.5 * X[:, 0]) + 1.5 * X[:, 1] * (X[:, 2] > 0)
         - 1.0 * X[:, 3] ** 2 + 0.8 * X[:, 4]
         + 0.3 * X[:, 5:10].sum(axis=1))
    return X, f + rng.normal(0, shovqin, n), f


def main() -> None:
    X, y, f = yarat()
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=0)
    cv = KFold(5, shuffle=True, random_state=0)

    print("=== 1. Uch ansambl ===")
    modellar = {
        "bagging": BaggingRegressor(DecisionTreeRegressor(random_state=0),
                                    n_estimators=300, random_state=0, n_jobs=1),
        "RandomForest": RandomForestRegressor(n_estimators=300,
                                              max_features=0.3,
                                              random_state=0, n_jobs=1),
        "ExtraTrees": ExtraTreesRegressor(n_estimators=300, max_features=0.3,
                                          random_state=0, n_jobs=1),
    }
    print(f"  {'model':<14} {'R^2':>9} {'MAE':>9} {'o_rt barglar':>14}")
    for nom, m in modellar.items():
        m.fit(Xtr, ytr)
        pred = m.predict(Xte)
        barglar = np.mean([e.get_n_leaves() for e in m.estimators_])
        print(f"  {nom:<14} {r2_score(yte, pred):>9.4f} "
              f"{mean_absolute_error(yte, pred):>9.4f} {barglar:>14.1f}")

    print("\n=== 2. max_features bo'yicha ikkalasi ===")
    print(f"  {'max_features':>13} {'RF R^2':>9} {'ET R^2':>9}")
    for mf in [1.0, 0.5, 0.3, "sqrt"]:
        r = cross_val_score(RandomForestRegressor(n_estimators=150,
                                                  max_features=mf,
                                                  random_state=0),
                            Xtr, ytr, cv=cv, scoring="r2").mean()
        e = cross_val_score(ExtraTreesRegressor(n_estimators=150,
                                                max_features=mf,
                                                random_state=0),
                            Xtr, ytr, cv=cv, scoring="r2").mean()
        print(f"  {str(mf):>13} {r:>9.4f} {e:>9.4f}")

    print("\n=== 3. Shovqin darajasi bo'yicha ===")
    print(f"  {'shovqin':>8} {'RF R^2':>9} {'ET R^2':>9} {'farq':>9}")
    for sh in [0.3, 1.0, 2.0, 4.0]:
        Xn, yn, _ = yarat(shovqin=sh, n=2000)
        r = cross_val_score(RandomForestRegressor(n_estimators=150,
                                                  max_features=0.3,
                                                  random_state=0),
                            Xn, yn, cv=cv, scoring="r2").mean()
        e = cross_val_score(ExtraTreesRegressor(n_estimators=150,
                                                max_features=0.3,
                                                random_state=0),
                            Xn, yn, cv=cv, scoring="r2").mean()
        print(f"  {sh:>8.1f} {r:>9.4f} {e:>9.4f} {e - r:>+9.4f}")

    print("\n=== 4. Model hajmi ===")
    for nom, m in modellar.items():
        tugunlar = sum(e.tree_.node_count for e in m.estimators_)
        print(f"  {nom:<14}: jami {tugunlar:,} tugun "
              f"(~{tugunlar * 48 / 1024 / 1024:.1f} MB)")
    print("  ⭐ Ansambl hajmi - ishlab chiqarishda muhim omil")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Uch ansambl ===
  model                R^2       MAE   o_rt barglar
  bagging           0.6362    1.3277         1327.0
  RandomForest      0.6098    1.3536         1327.0
  ExtraTrees        0.5843    1.4011         2100.0

=== 2. max_features bo'yicha ikkalasi ===
   max_features    RF R^2    ET R^2
            1.0    0.6674    0.6817
            0.5    0.6595    0.6382
            0.3    0.6273    0.5839
           sqrt    0.5828    0.5223

=== 3. Shovqin darajasi bo'yicha ===
   shovqin    RF R^2    ET R^2      farq
       0.3    0.7530    0.7207   -0.0323
       1.0    0.6453    0.6200   -0.0252
       2.0    0.4370    0.4192   -0.0178
       4.0    0.1820    0.1730   -0.0089

=== 4. Model hajmi ===
  bagging       : jami 795,874 tugun (~36.4 MB)
  RandomForest  : jami 795,874 tugun (~36.4 MB)
  ExtraTrees    : jami 1,259,700 tugun (~57.7 MB)
  ⭐ Ansambl hajmi - ishlab chiqarishda muhim omil

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


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

Noto'g'ri fikr To'g'risi
"ET — RF ning yomonroq varianti" Shovqinda ko'pincha ustun
"ET ham bootstrap ishlatadi" Standartda yo'q
"ET da OOB avtomatik" bootstrap=True kerak
"oob_decision_function_ toza" NaN bo'lishi mumkin
"ET har doim tezroq" n_estimators ko'proq kerak bo'lishi mumkin
"warm_start bilan kamaytirsa bo'ladi" Xato beradi
"max_samples sifatni buzadi" Ko'pincha sezilmaydi
"Tasodifiy chegara mantiqsiz" rho ni kamaytiradi

6. Keng tarqalgan xatolar va yechimlari

1. ET da OOB kutish

python
ExtraTreesClassifier(oob_score=True)          # bootstrap=False  # ⚠️
ExtraTreesClassifier(bootstrap=True, oob_score=True)             # ✅

2. NaN ni tekshirmaslik

python
roc_auc_score(y, o.oob_decision_function_[:, 1])                 # ⚠️
m = ~np.isnan(oob); roc_auc_score(y[m], oob[m])                  # ✅

3. warm_start bilan kamaytirish

python
o.set_params(n_estimators=50).fit(X, y)   # 200 dan keyin        # ⚠️
o.set_params(n_estimators=400).fit(X, y)  # faqat oshirish       # ✅

4. Faqat bittasini sinash

python
model = RandomForestClassifier(n_estimators=500)                 # ⚠️
# RF va ET ni CV da taqqoslang                                   # ✅

5. Katta ma'lumotda max_samples ni unutish

python
RandomForestClassifier(n_estimators=500)   # 1 mln qator         # ⚠️
RandomForestClassifier(n_estimators=500, max_samples=0.3)        # ✅

6. Vaqt qatorida OOB

python
o.oob_score_                                                     # ⚠️
cross_val_score(o, X, y, cv=TimeSeriesSplit(5))                  # ✅

7. Model hajmini hisobga olmaslik

python
RandomForestClassifier(n_estimators=2000)   # yuzlab MB          # ⚠️
# min_samples_leaf bilan hajmni cheklang                         # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 15.5-dars (o'tilgan): Random Forest
  • 14.10-dars (o'tilgan): Kalibrlash
  • 15.7-dars: Boosting g'oyasi
  • 15.11-dars: Belgi muhimligi
  • 15.14-dars: Amaliyot

8. Eng yaxshi amaliyotlar

  1. Ikkalasini sinang.

  2. Shovqinda ET ni ko'ring.

  3. ET da bootstrap=True (OOB kerak bo'lsa).

  4. NaN ni tekshiring.

  5. warm_start bilan egri chiziq quring.

  6. max_samples bilan tezlashtiring.

  7. OOB dan diagnostika oling.

  8. Model hajmini kuzating.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # ET ning RF dan farqi?
2.  # ET da bootstrap standart qiymati?
3.  # ET nega tezroq?
4.  # ET qachon ustun?
5.  # rho ga ta'siri?
6.  # bias ga ta'siri?
7.  # ET da OOB uchun nima kerak?
8.  # warm_start nima qiladi?
9.  # oob_decision_function_ nima?
10. # NaN qachon paydo bo'ladi?
11. # max_samples nima uchun?
12. # RF da bootstrap=False?
Javoblar
  1. Chegara tasodifiy tanlanadi
  2. False
  3. Chegara qidirilmaydi
  4. Shovqin ko'p bo'lganda
  5. Kamaytiradi
  6. Oshiradi
  7. bootstrap=True
  8. Daraxtlarni saqlab qo'shadi
  9. OOB ehtimolliklar
  10. n_estimators kichik bo'lsa
  11. Tezlik uchun
  12. Butun ma'lumot, OOB yo'q

Vazifa 2: Xatolarni tuzating

python
1.  ExtraTreesClassifier(oob_score=True)

2.  roc_auc_score(y, o.oob_decision_function_[:, 1])

3.  o.set_params(n_estimators=50).fit(X, y)   # 200 dan keyin

4.  RandomForestClassifier(n_estimators=500)  # 2 mln qator

5.  o.oob_score_   # vaqt qatori
Javoblar
python
1.  ExtraTreesClassifier(bootstrap=True, oob_score=True)

2.  m = ~np.isnan(oob); roc_auc_score(y[m], oob[m])

3.  o.set_params(n_estimators=400).fit(X, y)

4.  RandomForestClassifier(n_estimators=500, max_samples=0.3)

5.  cross_val_score(o, X, y, cv=TimeSeriesSplit(5))

Vazifa 3: RF va ET

Modellang:

  1. Asosiy solishtirish
  2. Bitta daraxt va ansambl
  3. Kelishmovchilik
  4. Shovqin

Vazifa 4: OOB egri chizig'i

Modellang:

  1. warm_start
  2. ET da bootstrap
  3. RF da bootstrap=False
  4. max_samples

Vazifa 5: Diagnostika

Modellang:

  1. OOB va test
  2. Kalibrlash
  3. Chegara
  4. Xatolar

Vazifa 6: Regressiya

Modellang:

  1. Uch ansambl
  2. max_features
  3. Shovqin
  4. Hajm

Vazifa 7: O'ylash

Extra Trees bo'linish chegarasini tasodifiy tanlaydi — ya'ni ma'lumotdagi ma'lumotni atayin e'tiborsiz qoldiradi. Nega bu ba'zan yaxshiroq natija beradi?

Javob

Qisqa javob: "eng yaxshi chegara" ko'pincha shovqinning eng yaxshi chegarasi bo'ladi. Tasodifiy chegara shu tuzoqqa tushmaydi va ansambl darajasida yo'qotilgan aniqlik rho ning kamayishi bilan qoplanadi.

1. Optimallashtirishning yashirin narxi

Chegarani qidirish — o'quv namunasidagi barcha mumkin bo'lgan bo'linishlar orasidan eng yaxshisini tanlash. Bu ko'p taqqoslash muammosi (11.x): 1000 ta nomzod orasidan eng yaxshisi tasodifan yaxshi ko'rinishi ehtimoli yuqori.

Ma'lumot "Eng yaxshi" chegara
Kuchli signal Haqiqiy chegaraga yaqin
Shovqinli Ko'pincha shovqin artefakti

2. Nima yo'qoladi va nima topiladi

  • Yo'qoladi: har daraxtning aniqligi (bias oshadi)
  • Topiladi: daraxtlar orasidagi korrelyatsiya kamayadi (15.3)
  • Ansambl darajasida: rho*s^2 hadi kichrayadi

3. Shuning uchun ET ga ko'proq daraxt kerak

  1. Har daraxt kuchsizroq
  2. (1-rho)*s^2/B hadini kamaytirish uchun B katta bo'lishi kerak
  3. Amalda: RF uchun 300, ET uchun 500-1000

4. O'xshash g'oyalar

  • Dropout (neyron tarmoqlarda) — atayin neyronlarni o'chirish
  • Regulyarizatsiya 13.7-bob — koeffitsiyentlarni atayin kichraytirish
  • Subsampling (boosting da — 15.9)

Hammasi bitta tamoyilga asoslanadi: o'quv ma'lumotiga to'liq moslashish — maqsad emas.

5. Xulosa

  1. Optimal bo'linish shovqinga moslashishi mumkin
  2. Tasodifiylik bu xavfni kamaytiradi
  3. Ansambl darajasida foyda ko'rinadi
  4. Ko'proq daraxt kerak

Nimani mustahkamlaydi: 2.1, 2.3-bo'limlar.


Xulosa

Bu darsda Extra Trees va OOB tahlilini o'rgandik.

Eng muhim uch fikr:

  1. Extra Trees chegarani tasodifiy tanlaydi. Bo'linish chegarasi qidirilmaydi — har belgi uchun bitta tasodifiy chegara olinadi va shular orasidan eng yaxshisi tanlanadi. Bu hisoblashning eng qimmat qismini olib tashlaydi (2-5 barobar tez) va rho ni kamaytiradi, lekin har daraxtning biasini oshiradi.

  2. ET standartda bootstrap ishlatmaydi. bootstrap=False — har daraxt butun ma'lumotni ko'radi, xilma-xillik faqat tasodifiy chegaralardan keladi. Shuning uchun oob_score=True uchun bootstrap=True ni qo'lda yoqish kerak. Shovqinli ma'lumotda ET ko'pincha RF dan ustun, chunki tasodifiy chegara shovqindagi "mukammal" bo'linishni topa olmaydi.

  3. OOB — to'liq diagnostika vositasi. oob_decision_function_ dan CV siz ROC/PR egri chiziqlari, kalibrlash diagrammasi, chegara tanlash va xatolar tahlilini qurish mumkin. warm_start=True esa o'rganish egri chizig'ini arzon qiladi. Faqat NaN ni tekshirishni unutmang va vaqt qatorlarida OOB ga ishonmang.

Keyingi darsda boosting g'oyasini o'rganamiz: ansambl a'zolarini ketma-ket, bir-birining xatosiga qarab qurish.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
15.6-dars: Extra Trees va OOB tahlili — IlmHamroh