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

15.5-dars: Random Forest

15-QISM — DARAXTLAR VA ANSAMBLLAR · 5-dars


1. Kirish va motivatsiya

Random Forest — bagging ustiga bitta g'oya qo'shilgan model: har bo'linishda belgilarning tasodifiy qismi ko'riladi. Bu kichik o'zgarish daraxtlar orasidagi korrelyatsiyani (rho, 15.3) sezilarli kamaytiradi va shu orqali ansambl dispersiyasini bagging dan ham pastga tushiradi.

Natija — jadval ma'lumotlari uchun eng ishonchli standart model: u deyarli sozlashsiz ishlaydi, masshtablash talab qilmaydi, overfitting ga chidamli va OOB baho beradi. Ko'p loyihada Random Forest "bazaviy natija" (baseline) sifatida qo'yiladi va ko'pincha shundayligicha qoladi.

Bu darsda: max_features ning roli, n_estimators, chuqurlik, class_weight, OOB, ExtraTrees bilan farq va sozlash tartibi.

Real vaziyat. Logistika kompaniyasida yetkazib berish kechikishini bashorat qilish uchun uch oy davomida xususiyatlar muhandisligi va chiziqli model sozlandi — ROC AUC 0.74. Bir kunda qurilgan sozlanmagan RandomForestClassifier(n_estimators=500) 0.81 berdi. Xususiyatlar muhandisligining ko'p qismi (log, kvadrat, birliklar) daraxtga keraksiz edi.

Bu darsda Random Forest ni o'rganamiz.

Bu darsda:

  • Bagging + tasodifiy belgilar
  • max_features ning roli
  • n_estimators va chuqurlik
  • OOB baho
  • class_weight
  • Sozlash tartibi
  • Tuzoqlar
  • Amaliy: to'liq oqim

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


2. Nazariya — chuqur tushuntirish

2.1. Random Forest = bagging + tasodifiy belgilar

text
Har daraxt uchun:
  1. BOOTSTRAP namuna olinadi (bagging kabi)
  2. Har bo'linishda BELGILARNING TASODIFIY QISMI ko'riladi  <- YANGI

Ikkinchi qadam daraxtlarni bir-biridan uzoqlashtiradi:
  kuchli belgi har daraxtda ildizda bo'lolmaydi
  -> rho kamayadi -> var(o'rtacha) kamayadi 15.3-bob

Daraxtlar TO'LIQ o'stiriladi (max_depth=None) - dispersiya kerak

Farq bitta qatorda: max_features. Aynan shu parametr Random Forest ni bagging dan ajratadi va uning asosiy kuchini beradi. max_features=None qo'ysangiz, Random Forest oddiy bagging ga aylanadi.

2.2. max_features

text
sklearn standarti:
  klassifikatsiya: "sqrt"  -> sqrt(p) ta belgi
  regressiya:      1.0     -> barcha belgilar (!)

Kichik max_features:
  + rho kichik (daraxtlar xilma-xil)
  - har daraxt kuchsizroq (bias oshadi)

Katta max_features:
  + har daraxt kuchli
  - rho katta (foyda kam)

OPTIMUM o'rtada; regressiyada odatda 0.3-0.5 yaxshiroq

Regressiyada standart qiymat ko'pincha yomon: max_features=1.0 degani daraxtlar juda korrelyatsiyali bo'ladi. max_features=0.3 yoki "sqrt" ni sinab ko'ring — bu Random Forest regressiyasida eng ko'p foyda beradigan sozlash.

2.3. n_estimators va chuqurlik

text
n_estimators: ko'proq har doim yaxshi (overfitting yo'q)
  100 - boshlang'ich, 300-1000 - yakuniy
  OOB egri chizig'i to'yinishni ko'rsatadi

max_depth: odatda None (to'liq)
  juda shovqinli/kichik ma'lumotda min_samples_leaf=5..20 foydali
  lekin agressiv cheklash ansambl foydasini yo'qotadi

min_samples_leaf: 1 (standart) ko'p hollarda to'g'ri

Random Forest da cheklash odatda kerak emas — bu bitta daraxtdan 15.2-bob asosiy farq. Cheklash faqat ma'lumot juda shovqinli yoki xotira cheklangan bo'lsa foydali.

2.4. OOB baho

python
o = RandomForestClassifier(n_estimators=500, oob_score=True,
                           random_state=0, n_jobs=-1).fit(X, y)
o.oob_score_                   # aniqlik (yoki R^2)
o.oob_decision_function_       # har namuna uchun OOB ehtimolliklar

oob_decision_function_ — OOB bashoratlari to'liq matritsasi: undan ROC AUC, PR-egri va kalibrlash grafigini CV siz qurish mumkin. Bu katta ma'lumotlarda juda qulay.

2.5. class_weight

text
Nomutanosib sinflarda 14.9-bob:
  class_weight="balanced"           — butun ma'lumot bo'yicha
  class_weight="balanced_subsample"  — har bootstrap namuna bo'yicha
  class_weight={0: 1, 1: 10}         — qo'lda

"balanced_subsample" — Random Forest uchun tabiiyroq
Muqobil: chegarani sozlash 14.9-bob yoki nomutanosiblikni qabul qilish

class_weight bashorat ehtimolliklarini buzadi (kalibrlash yo'qoladi — 14.10). Agar sizga ehtimollik kerak bo'lsa, class_weight o'rniga chegarani sozlang.

2.6. Sozlash tartibi

text
1. n_estimators = 500 (sozlamang, imkon qadar ko'p)
2. max_features — ENG MUHIM: ["sqrt", 0.3, 0.5, 0.8, None]
3. min_samples_leaf — [1, 3, 10] (faqat shovqinli ma'lumotda)
4. max_depth — odatda None
5. class_weight — nomutanosib bo'lsa

Ko'p hollarda 2-qadamdan keyin to'xtash mumkin

Random Forest ning kam sozlanishi — uning asosiy amaliy afzalligi: 5-10 konfiguratsiya yetarli, boosting da esa 15.9-bob o'nlab. Vaqt cheklangan bo'lsa, faqat max_features ni sozlang.

2.7. Tuzoqlar

Asosiy tuzoqlar: regressiyada max_features ni standart qoldirish; n_estimators ni CV bilan sozlash; daraxtlarni agressiv cheklash; n_jobs ni unutish; feature_importances_ ni sababiy talqin qilish 15.11-bob; vaqt qatorida OOB ga ishonish; kategoriyali belgilarni butun son sifatida berish (14.x — tartib paydo bo'ladi); Random Forest dan ekstrapolyatsiya kutish (15.1 — daraxt kabi qotib qoladi).

2.8. Ishonchli standart

Random Forest = bagging + har bo'linishda tasodifiy belgilar qismi. Bu daraxtlar orasidagi korrelyatsiyani kamaytiradi va dispersiyani bagging dan pastroqqa tushiradi. Eng muhim giperparametr — max_features (regressiyada standart qiymat ko'pincha yomon). n_estimators ni ko'p qo'ying (overfitting yo'q), daraxtlarni odatda cheklamang, oob_score dan bepul validatsiya sifatida foydalaning. Keyingi dars — Extra Trees va OOB tahlili.


3. Tez ma'lumotnoma

python
from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor

o = RandomForestClassifier(n_estimators=500, max_features="sqrt",
                           min_samples_leaf=1, max_depth=None,
                           class_weight=None, oob_score=True,
                           random_state=0, n_jobs=-1).fit(X, y)
o.oob_score_, o.oob_decision_function_
o.feature_importances_                 # 15.11 - ehtiyot
o.estimators_[0].get_n_leaves()

RandomForestRegressor(n_estimators=500, max_features=0.3,   # MUHIM
                      random_state=0, n_jobs=-1)
QOIDA: max_features ni sozla · n_estimators ni ko'p qo'y ·
       cheklama · n_jobs=-1

Random Forest xulosasi

RF = bagging + har bo'linishda tasodifiy belgilar qismi
max_features - eng muhim parametr (regressiyada 0.3-0.5 sinang)
n_estimators ko'p bo'lsin; overfitting bermaydi
oob_score va oob_decision_function_ - bepul validatsiya

4. Batafsil misollar

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

Misol 1 — Bagging va Random Forest

python
"""Tasodifiy belgi tanlash nima beradi (real numpy/sklearn)."""

import numpy as np
from sklearn.ensemble import BaggingClassifier, RandomForestClassifier
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier


def yarat(seed: int = 7, n: int = 3000, p: int = 20, shovqin: float = 0.12):
    """Bir necha kuchli va ko'p zaif belgi."""
    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.5) & (X[:, 3] > 0.0))
             | (X[:, 4] < -1.0))
    zaif = 0.25 * X[:, 5:10].sum(axis=1)
    y = ((qoida.astype(float) + zaif) > 0.5).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)

    def auc(model):
        model.fit(Xtr, ytr)
        return roc_auc_score(yte, model.predict_proba(Xte)[:, 1])

    print("=== 1. Bitta daraxt, bagging, Random Forest ===")
    print(f"  bitta daraxt: "
          f"{auc(DecisionTreeClassifier(random_state=0)):.4f}")
    print(f"  bagging(300): "
          f"{auc(BaggingClassifier(DecisionTreeClassifier(random_state=0), n_estimators=300, random_state=0)):.4f}")
    print(f"  RF(300):      "
          f"{auc(RandomForestClassifier(n_estimators=300, random_state=0)):.4f}")

    print("\n=== 2. max_features bo'yicha ===")
    print(f"  {'max_features':>13} {'test AUC':>10} {'OOB':>9} "
          f"{'o_rt barglar':>14}")
    for mf in ["sqrt", "log2", 0.3, 0.5, 0.8, None]:
        o = RandomForestClassifier(n_estimators=300, max_features=mf,
                                   oob_score=True, random_state=0,
                                   n_jobs=1).fit(Xtr, ytr)
        a = roc_auc_score(yte, o.predict_proba(Xte)[:, 1])
        barglar = np.mean([e.get_n_leaves() for e in o.estimators_])
        nom = "None" if mf is None else str(mf)
        print(f"  {nom:>13} {a:>10.4f} {o.oob_score_:>9.4f} {barglar:>14.1f}")

    print("\n=== 3. Daraxtlar orasidagi kelishuv ===")
    for mf, nom in [("sqrt", "sqrt"), (None, "None (bagging)")]:
        o = RandomForestClassifier(n_estimators=50, max_features=mf,
                                   random_state=0, n_jobs=1).fit(Xtr, ytr)
        P = np.array([e.predict(Xte) for e in o.estimators_])
        juftlar = [(P[i] != P[j]).mean()
                   for i in range(20) for j in range(i + 1, 20)]
        print(f"  {nom:<16}: daraxtlar o'rtacha {np.mean(juftlar):.4f} "
              f"namunada farq qiladi")

    print("\n=== 4. Ildiz belgisining xilma-xilligi ===")
    for mf, nom in [("sqrt", "sqrt"), (None, "None (bagging)")]:
        o = RandomForestClassifier(n_estimators=200, max_features=mf,
                                   random_state=0, n_jobs=1).fit(Xtr, ytr)
        ildizlar = np.bincount([e.tree_.feature[0] for e in o.estimators_],
                               minlength=X.shape[1])
        noyob = (ildizlar > 0).sum()
        print(f"  {nom:<16}: {noyob} xil belgi ildizda, "
              f"eng ko'pi {ildizlar.max() / 200:.1%}")
    print("  ⭐ Tasodifiy belgi tanlash daraxtlarni xilma-xil qiladi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Bitta daraxt, bagging, Random Forest ===
  bitta daraxt: 0.6528
  bagging(300): 0.8439
  RF(300):      0.8382

=== 2. max_features bo'yicha ===
   max_features   test AUC       OOB   o_rt barglar
           sqrt     0.8382    0.7495          309.4
           log2     0.8382    0.7495          309.4
            0.3     0.8371    0.7652          277.8
            0.5     0.8410    0.7710          248.4
            0.8     0.8442    0.7757          228.8
           None     0.8443    0.7652          222.0

=== 3. Daraxtlar orasidagi kelishuv ===
  sqrt            : daraxtlar o'rtacha 0.4367 namunada farq qiladi
  None (bagging)  : daraxtlar o'rtacha 0.3694 namunada farq qiladi

=== 4. Ildiz belgisining xilma-xilligi ===
  sqrt            : 17 xil belgi ildizda, eng ko'pi 20.0%
  None (bagging)  : 5 xil belgi ildizda, eng ko'pi 85.5%
  ⭐ Tasodifiy belgi tanlash daraxtlarni xilma-xil qiladi

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

Misol 2 — Regressiyada max_features

python
"""Regressiyada standart qiymat nega yomon (real numpy/sklearn)."""

import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error, r2_score
from sklearn.model_selection import KFold, cross_val_score, train_test_split


def yarat(seed: int = 3, n: int = 3000, p: int = 25):
    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:12].sum(axis=1))
    return X, f + rng.normal(0, 1.2, 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. max_features bo'yicha (test) ===")
    print(f"  {'max_features':>13} {'R^2':>9} {'MAE':>9} {'OOB R^2':>10}")
    natijalar = {}
    for mf in [1.0, 0.8, 0.5, 0.3, "sqrt", "log2"]:
        o = RandomForestRegressor(n_estimators=150, max_features=mf,
                                  oob_score=True, random_state=0,
                                  n_jobs=1).fit(Xtr, ytr)
        pred = o.predict(Xte)
        natijalar[str(mf)] = r2_score(yte, pred)
        print(f"  {str(mf):>13} {r2_score(yte, pred):>9.4f} "
              f"{mean_absolute_error(yte, pred):>9.4f} {o.oob_score_:>10.4f}")
    eng = max(natijalar, key=natijalar.get)
    print(f"  eng yaxshi: {eng} ({natijalar[eng]:.4f}), "
          f"standart 1.0 ({natijalar['1.0']:.4f})")

    print("\n=== 2. CV bilan tasdiqlash ===")
    for mf in [1.0, 0.3, "sqrt"]:
        b = cross_val_score(RandomForestRegressor(n_estimators=100,
                                                  max_features=mf,
                                                  random_state=0),
                            Xtr, ytr, cv=cv, scoring="r2").mean()
        print(f"  max_features={str(mf):<6}: CV R^2 {b:.4f}")

    print("\n=== 3. Belgilar soni ortganda ===")
    print(f"  {'p':>4} {'1.0':>9} {'0.3':>9} {'sqrt':>9}")
    for p in [8, 20, 50]:
        Xp, yp, _ = yarat(n=1500, p=p)
        qator = []
        for mf in [1.0, 0.3, "sqrt"]:
            b = cross_val_score(RandomForestRegressor(n_estimators=80,
                                                      max_features=mf,
                                                      random_state=0),
                                Xp, yp, cv=KFold(3, shuffle=True,
                                                 random_state=0),
                                scoring="r2").mean()
            qator.append(b)
        print(f"  {p:>4} {qator[0]:>9.4f} {qator[1]:>9.4f} {qator[2]:>9.4f}")

    print("\n=== 4. Ekstrapolyatsiya cheklovi ===")
    o = RandomForestRegressor(n_estimators=150, max_features=0.3,
                              random_state=0).fit(Xtr, ytr)
    tash = np.zeros((4, X.shape[1]))
    tash[:, 0] = [3.0, 5.0, 8.0, 15.0]          # o'quv diapazonidan tashqari
    print(f"  x0 qiymatlari: {tash[:, 0]}")
    print(f"  RF bashorati:  {o.predict(tash).round(3)}")
    print(f"  (o'quvda x0 diapazoni: {Xtr[:, 0].min():.2f} .. "
          f"{Xtr[:, 0].max():.2f})")
    print("  ⭐ RF ham ekstrapolyatsiya qilmaydi 15.1-bob")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. max_features bo'yicha (test) ===
   max_features       R^2       MAE    OOB R^2
            1.0    0.6462    1.2862     0.6375
            0.8    0.6531    1.2700     0.6424
            0.5    0.6406    1.2958     0.6317
            0.3    0.6156    1.3282     0.5924
           sqrt    0.5843    1.3844     0.5675
           log2    0.5472    1.4467     0.5303
  eng yaxshi: 0.8 0.6531-bob, standart 1.0 0.6462-bob

=== 2. CV bilan tasdiqlash ===
  max_features=1.0   : CV R^2 0.6259
  max_features=0.3   : CV R^2 0.5855
  max_features=sqrt  : CV R^2 0.5505

=== 3. Belgilar soni ortganda ===
     p       1.0       0.3      sqrt
     8    0.6747    0.6406    0.6406
    20    0.6173    0.5732    0.5383
    50    0.5679    0.5309    0.4432

=== 4. Ekstrapolyatsiya cheklovi ===
  x0 qiymatlari: [ 3.  5.  8. 15.]
  RF bashorati:  [-1.024 -1.017 -1.017 -1.017]
  (o'quvda x0 diapazoni: -3.44 .. 3.51)
  ⭐ RF ham ekstrapolyatsiya qilmaydi (15.1)

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

Misol 3 — OOB va n_estimators

python
"""OOB baho, to'yinish va CV bilan solishtirish (real numpy/sklearn)."""

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


def yarat(seed: int = 9, n: int = 4000, p: int = 15, shovqin: float = 0.14):
    rng = np.random.default_rng(seed)
    X = rng.normal(0, 1, (n, p))
    qoida = (((X[:, 0] > 0.2) & (X[:, 1] < 0.3))
             | ((X[:, 2] > 0.4) & (X[:, 3] > -0.2))
             | (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. n_estimators va to'yinish ===")
    print(f"  {'n_est':>7} {'OOB':>9} {'test AUC':>10}")
    for ne in [50, 100, 200, 400, 800]:
        o = RandomForestClassifier(n_estimators=ne, oob_score=True,
                                   random_state=0, n_jobs=1).fit(Xtr, ytr)
        a = roc_auc_score(yte, o.predict_proba(Xte)[:, 1])
        print(f"  {ne:>7} {o.oob_score_:>9.4f} {a:>10.4f}")

    print("\n=== 2. OOB va CV ===")
    cv = StratifiedKFold(5, shuffle=True, random_state=0)
    o = RandomForestClassifier(n_estimators=300, oob_score=True,
                               random_state=0, n_jobs=1).fit(Xtr, ytr)
    cvb = cross_val_score(RandomForestClassifier(n_estimators=300,
                                                 random_state=0),
                          Xtr, ytr, cv=cv).mean()
    print(f"  OOB aniqligi:  {o.oob_score_:.4f}")
    print(f"  5-karra CV:    {cvb:.4f}")
    print(f"  test aniqligi: {o.score(Xte, yte):.4f}")

    print("\n=== 3. OOB ehtimolliklari bilan ROC AUC ===")
    oob_p = o.oob_decision_function_[:, 1]
    print(f"  OOB ROC AUC:  {roc_auc_score(ytr, oob_p):.4f}")
    print(f"  test ROC AUC: "
          f"{roc_auc_score(yte, o.predict_proba(Xte)[:, 1]):.4f}")
    print(f"  OOB ehtimolliklar diapazoni: {oob_p.min():.3f} .. "
          f"{oob_p.max():.3f}")

    print("\n=== 4. Cheklash foyda beradimi ===")
    print(f"  {'min_samples_leaf':>17} {'OOB':>9} {'test AUC':>10} "
          f"{'o_rt barglar':>14}")
    for msl in [1, 3, 10, 30, 100]:
        o = RandomForestClassifier(n_estimators=300, min_samples_leaf=msl,
                                   oob_score=True, random_state=0,
                                   n_jobs=1).fit(Xtr, ytr)
        a = roc_auc_score(yte, o.predict_proba(Xte)[:, 1])
        barglar = np.mean([e.get_n_leaves() for e in o.estimators_])
        print(f"  {msl:>17} {o.oob_score_:>9.4f} {a:>10.4f} {barglar:>14.1f}")
    print("  ⭐ RF da agressiv cheklash odatda kerak emas")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. n_estimators va to'yinish ===
    n_est       OOB   test AUC
       50    0.8336     0.8462
      100    0.8411     0.8464
      200    0.8486     0.8476
      400    0.8500     0.8484
      800    0.8507     0.8477

=== 2. OOB va CV ===
  OOB aniqligi:  0.8504
  5-karra CV:    0.8500
  test aniqligi: 0.8467

=== 3. OOB ehtimolliklari bilan ROC AUC ===
  OOB ROC AUC:  0.8554
  test ROC AUC: 0.8474
  OOB ehtimolliklar diapazoni: 0.029 .. 0.972

=== 4. Cheklash foyda beradimi ===
   min_samples_leaf       OOB   test AUC   o_rt barglar
                  1    0.8504     0.8474          366.9
                  3    0.8514     0.8500          257.8
                 10    0.8521     0.8508          121.1
                 30    0.8507     0.8535           45.6
                100    0.8479     0.8536           13.6
  ⭐ RF da agressiv cheklash odatda kerak emas

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

Misol 4 — To'liq oqim

python
"""Aralash belgilar, nomutanosiblik va sozlash (real pandas/sklearn)."""

import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import average_precision_score, roc_auc_score
from sklearn.model_selection import GridSearchCV, StratifiedKFold, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder


def yarat(seed: int = 4, n: int = 5000) -> pd.DataFrame:
    rng = np.random.default_rng(seed)
    hudud = rng.choice(["toshkent", "samarqand", "buxoro", "fargona"], n,
                       p=[0.4, 0.25, 0.2, 0.15])
    tur = rng.choice(["oddiy", "tezkor", "yirik"], n, p=[0.6, 0.3, 0.1])
    masofa = rng.gamma(3, 60, n)
    ogirlik = rng.gamma(2, 4, n)
    soat = rng.integers(0, 24, n).astype(float)
    hudud_qiyinligi = pd.Series(hudud).map(
        {"toshkent": 0.0, "samarqand": 0.4, "buxoro": 0.7, "fargona": 0.5}).to_numpy()
    tur_tezligi = pd.Series(tur).map(
        {"oddiy": 0.0, "tezkor": -0.8, "yirik": 0.9}).to_numpy()
    kuch = (-3.0 + 0.006 * masofa + 0.05 * ogirlik + hudud_qiyinligi
            + tur_tezligi + 0.9 * ((soat >= 7) & (soat <= 10)))
    kechikdi = (rng.random(n) < 1 / (1 + np.exp(-kuch))).astype(int)
    return pd.DataFrame({"hudud": hudud, "tur": tur, "masofa": masofa,
                         "ogirlik": ogirlik, "soat": soat,
                         "kechikdi": kechikdi})


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.3, random_state=0,
                                          stratify=y)
    cv = StratifiedKFold(5, shuffle=True, random_state=0)

    print("=== 1. Ma'lumot ===")
    print(f"  {len(df)} yetkazma, kechikish ulushi {y.mean():.2%}")
    print(f"  kategoriyali: hudud, tur; sonli: masofa, ogirlik, soat")

    kategoriya = ["hudud", "tur"]
    sonli = ["masofa", "ogirlik", "soat"]
    tayyor = ColumnTransformer([("k", OneHotEncoder(handle_unknown="ignore"),
                                 kategoriya)], remainder="passthrough")

    print("\n=== 2. Sozlanmagan RF ===")
    asos = Pipeline([("t", tayyor),
                     ("m", RandomForestClassifier(n_estimators=400,
                                                  random_state=0,
                                                  n_jobs=1))]).fit(Xtr, ytr)
    p = asos.predict_proba(Xte)[:, 1]
    print(f"  ROC AUC: {roc_auc_score(yte, p):.4f}")
    print(f"  PR AUC:  {average_precision_score(yte, p):.4f}")

    print("\n=== 3. max_features va min_samples_leaf sozlash ===")
    setka = {"m__max_features": ["sqrt", 0.3, 0.5, None],
             "m__min_samples_leaf": [1, 5, 20]}
    q = GridSearchCV(Pipeline([("t", tayyor),
                               ("m", RandomForestClassifier(n_estimators=200,
                                                            random_state=0))]),
                     setka, cv=cv, scoring="roc_auc", n_jobs=1).fit(Xtr, ytr)
    print(f"  konfiguratsiyalar: {len(q.cv_results_['params'])}")
    print(f"  eng yaxshi: {q.best_params_}")
    print(f"  CV ROC AUC: {q.best_score_:.4f}")
    pq = q.predict_proba(Xte)[:, 1]
    print(f"  test ROC AUC: {roc_auc_score(yte, pq):.4f}")
    print(f"  test PR AUC:  {average_precision_score(yte, pq):.4f}")

    print("\n=== 4. class_weight ehtimolliklarga ta'siri ===")
    for cw in [None, "balanced", "balanced_subsample"]:
        m = Pipeline([("t", tayyor),
                      ("m", RandomForestClassifier(n_estimators=300,
                                                   class_weight=cw,
                                                   random_state=0))]).fit(Xtr, ytr)
        pr = m.predict_proba(Xte)[:, 1]
        nom = "None" if cw is None else cw
        print(f"  {nom:<20}: AUC {roc_auc_score(yte, pr):.4f}, "
              f"o'rtacha p {pr.mean():.4f} (haqiqiy {yte.mean():.4f})")
    print("  ⭐ class_weight kalibrlashni buzadi 14.10-bob")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Ma'lumot ===
  5000 yetkazma, kechikish ulushi 25.24%
  kategoriyali: hudud, tur; sonli: masofa, ogirlik, soat

=== 2. Sozlanmagan RF ===
  ROC AUC: 0.6666
  PR AUC:  0.4300

=== 3. max_features va min_samples_leaf sozlash ===
  konfiguratsiyalar: 12
  eng yaxshi: {'m__max_features': 'sqrt', 'm__min_samples_leaf': 20}
  CV ROC AUC: 0.7179
  test ROC AUC: 0.7182
  test PR AUC:  0.4902

=== 4. class_weight ehtimolliklarga ta'siri ===
  None                : AUC 0.6668, o'rtacha p 0.2525 (haqiqiy 0.2527)
  balanced            : AUC 0.6675, o'rtacha p 0.3505 (haqiqiy 0.2527)
  balanced_subsample  : AUC 0.6680, o'rtacha p 0.2449 (haqiqiy 0.2527)
  ⭐ class_weight kalibrlashni buzadi (14.10)

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


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

Noto'g'ri fikr To'g'risi
"RF = ko'p daraxt" + tasodifiy belgi tanlash
"max_features ahamiyatsiz" Eng muhim parametr
"Standart qiymat har doim mos" Regressiyada ko'pincha yomon
"n_estimators ni sozlash kerak" Ko'p qo'ying, sozlamang
"RF ni cheklash kerak" Odatda kerak emas
"RF ekstrapolyatsiya qiladi" Yo'q
"RF masshtablash talab qiladi" Yo'q
"class_weight zararsiz" Kalibrlashni buzadi

6. Keng tarqalgan xatolar va yechimlari

1. Regressiyada standart max_features

python
RandomForestRegressor(n_estimators=500)          # max_features=1.0 # ⚠️
RandomForestRegressor(n_estimators=500, max_features=0.3)          # ✅

2. n_estimators ni sozlash

python
GridSearchCV(o, {"n_estimators": [100, 200, 500]})                 # ⚠️
GridSearchCV(o, {"max_features": ["sqrt", 0.3, 0.5, None]})        # ✅

3. n_jobs ni unutish

python
RandomForestClassifier(n_estimators=1000)                          # ⚠️
RandomForestClassifier(n_estimators=1000, n_jobs=-1)               # ✅

4. Agressiv cheklash

python
RandomForestClassifier(max_depth=3, min_samples_leaf=50)           # ⚠️
RandomForestClassifier(n_estimators=500)     # to'liq daraxtlar    # ✅

5. Kategoriyani butun son sifatida berish

python
X["hudud"] = X["hudud"].map({"toshkent": 0, "samarqand": 1})       # ⚠️
OneHotEncoder(handle_unknown="ignore")                             # ✅

6. Vaqt qatorida OOB

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

7. Ehtimollik kerak bo'lganda class_weight

python
RandomForestClassifier(class_weight="balanced")   # p buziladi     # ⚠️
# chegarani sozlang 14.9-bob yoki kalibrlang 14.10-bob                 # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 15.4-dars (o'tilgan): Bagging
  • 15.6-dars: Extra Trees
  • 15.8-dars: Gradient boosting bilan solishtirish
  • 15.11-dars: Belgi muhimligi
  • 15.14-dars: Amaliyot

8. Eng yaxshi amaliyotlar

  1. max_features ni sozlang.

  2. Regressiyada 0.3-0.5 sinang.

  3. n_estimators ni ko'p qo'ying.

  4. n_jobs=-1 ishlating.

  5. Cheklashdan saqlaning.

  6. OOB dan foydalaning.

  7. Kategoriyalarni to'g'ri kodlang.

  8. Ekstrapolyatsiyani tekshiring.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # RF bagging dan nimasi bilan farq qiladi?
2.  # eng muhim parametr?
3.  # klassifikatsiyada standart max_features?
4.  # regressiyada standart?
5.  # kichik max_features nima qiladi?
6.  # n_estimators ni sozlash kerakmi?
7.  # max_depth odatda?
8.  # oob_decision_function_ nima?
9.  # balanced_subsample nima?
10. # class_weight nimani buzadi?
11. # RF ekstrapolyatsiya qiladimi?
12. # masshtablash kerakmi?
Javoblar
  1. Har bo'linishda tasodifiy belgilar
  2. max_features
  3. "sqrt"
  4. 1.0 (barchasi)
  5. rho ni kamaytiradi, bias oshiradi
  6. Yo'q
  7. None
  8. OOB ehtimolliklar matritsasi
  9. Har bootstrapda muvozanatlash
  10. Kalibrlashni
  11. Yo'q
  12. Yo'q

Vazifa 2: Xatolarni tuzating

python
1.  RandomForestRegressor(n_estimators=500)

2.  GridSearchCV(o, {"n_estimators": [100, 300]})

3.  RandomForestClassifier(n_estimators=1000)

4.  RandomForestClassifier(max_depth=3)

5.  RandomForestClassifier(class_weight="balanced")  # p kerak
Javoblar
python
1.  RandomForestRegressor(n_estimators=500, max_features=0.3)

2.  GridSearchCV(o, {"max_features": ["sqrt", 0.3, 0.5]})

3.  RandomForestClassifier(n_estimators=1000, n_jobs=-1)

4.  RandomForestClassifier(n_estimators=500)

5.  # chegarani sozlang yoki kalibrlang

Vazifa 3: Bagging va RF

Modellang:

  1. Uch model
  2. max_features
  3. Kelishuv
  4. Ildiz xilma-xilligi

Vazifa 4: Regressiya

Modellang:

  1. max_features
  2. CV
  3. Belgilar soni
  4. Ekstrapolyatsiya

Vazifa 5: OOB

Modellang:

  1. To'yinish
  2. OOB va CV
  3. OOB AUC
  4. Cheklash

Vazifa 6: To'liq oqim

Modellang:

  1. Ma'lumot
  2. Sozlanmagan RF
  3. Grid
  4. class_weight

Vazifa 7: O'ylash

Random Forest "deyarli sozlashsiz ishlaydi" deyiladi, lekin gradient boosting 15.8-bob odatda undan yuqori natija beradi. Qaysi birini tanlash kerak?

Javob

Qisqa javob: boosting tepa natija beradi, Random Forest ishonchli natija beradi. Tanlov loyihaning bosqichiga va sizning vaqt byudjetingizga bog'liq: RF ni bazaviy model sifatida qo'ying, boosting ni esa oxirgi 2-5% uchun sozlang.

1. Solishtirish

Jihat Random Forest Gradient boosting
Sozlashsiz natija Yaxshi O'rtacha
To'liq sozlangan Yaxshi Eng yaxshi
Sozlash vaqti 5-10 konfiguratsiya 50-200
Overfitting xavfi Past Yuqori (n_estimators)
Parallellashtirish To'liq Cheklangan
OOB baho Bor Yo'q

2. Amaliy qoida

  1. Birinchi kun: RF bilan bazaviy natija oling
  2. Agar RF yetarli bo'lsa — to'xtang
  3. Aniqlik kritik bo'lsa: LightGBM/XGBoost ni sozlang (15.9)
  4. Ikkalasini ham yakuniy taqqoslang

3. RF qachon yaxshiroq

  • Ma'lumot juda shovqinli (boosting shovqinni yodlaydi)
  • Vaqt kam, sozlashga imkon yo'q
  • OOB baho kerak
  • Ko'p yadro bor, parallellik muhim
  • Ishlab chiqarishda barqarorlik kerak

4. Boosting qachon yaxshiroq

  • Jadval ma'lumotidagi musobaqalar
  • Aniqlikning har foizi qimmat
  • Sozlash uchun vaqt bor
  • Kategoriyali belgilar ko'p (CatBoost/LightGBM)

5. Xulosa

  1. RF — ishonchli boshlang'ich nuqta
  2. Boosting — sozlangandan keyingi tepa natija
  3. Farq odatda 1-5%
  4. Ikkalasini ham sinab ko'ring

Nimani mustahkamlaydi: 2.6, 2.7-bo'limlar.


Xulosa

Bu darsda Random Forest ni o'rgandik.

Eng muhim uch fikr:

  1. RF = bagging + tasodifiy belgilar. Farq bitta qatorda: har bo'linishda belgilarning tasodifiy qismi ko'riladi. Bu kuchli belgining har daraxtda ildizda bo'lishiga yo'l qo'ymaydi, daraxtlarni xilma-xil qiladi va rho ni kamaytirib ansambl dispersiyasini bagging dan pastroqqa tushiradi (15.3 formulasi).

  2. max_features — eng muhim parametr. Kichik qiymat korrelyatsiyani kamaytiradi, lekin har daraxtning biasini oshiradi — optimum o'rtada. Regressiyada sklearn standarti (1.0) ko'pincha yomon: 0.3, 0.5 yoki "sqrt" ni albatta sinab ko'ring. Bu — RF da eng ko'p foyda beradigan yagona sozlash.

  3. Ko'p daraxt, kam cheklov. n_estimators overfitting bermaydi — imkon qadar ko'p qo'ying va uni CV bilan sozlamang. Daraxtlarni odatda cheklamang (max_depth=None): ansambl uchun dispersiya kerak. oob_score_ va oob_decision_function_ esa CV siz, bepul validatsiya beradi (vaqt qatorlaridan tashqari).

Keyingi darsda Extra Trees va OOB tahlilini o'rganamiz: yanada ko'proq tasodifiylik qo'shilganda nima o'zgaradi.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
15.5-dars: Random Forest — IlmHamroh