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

15.3-dars: Daraxt beqarorligi

15-QISM — DARAXTLAR VA ANSAMBLLAR · 3-dars


1. Kirish va motivatsiya

Qaror daraxtining eng jiddiy kamchiligi — beqarorlik (variance). O'quv ma'lumotining 5% ini almashtirsangiz, daraxt tuzilmasi butunlay boshqacha bo'lishi mumkin: ildizdagi belgi o'zgaradi, shoxlar boshqa tartibda quriladi, "muhim" deb topilgan belgilar ro'yxati almashadi.

Bu tasodifiy emas — bu daraxt algoritmining tuzilmaviy xususiyati: ildizdagi bitta o'zgarish butun pastki daraxtlarni qayta quradi. Va aynan shu kamchilik ansambllarning tug'ilishiga sabab bo'lgan: agar model dispersiyasi yuqori bo'lsa, ko'p modelni o'rtachalashtirib dispersiyani kamaytirish mumkin (12.5 — bias-variance).

Bu darsda: beqarorlikni o'lchash, bootstrap namunalarda daraxt tuzilmasining o'zgarishi, bashoratlar dispersiyasi, beqarorlikning sabablari va o'rtachalashtirish g'oyasi.

Real vaziyat. Bank kredit qoidalarini daraxtdan chiqarib, ichki hujjatga kiritdi: "ildiz belgi — kechikishlar soni". Keyingi chorakda model yangi ma'lumotda qayta o'qitilganda ildizda daromad paydo bo'ldi va hujjat eskirdi. Tekshiruv shuni ko'rsatdi: ikki belgining sifati deyarli teng edi va tanlov amalda tasodifiy bo'lgan.

Bu darsda daraxt beqarorligini o'rganamiz.

Bu darsda:

  • Beqarorlik nima
  • Tuzilma va bashorat beqarorligi
  • Sabablari
  • O'lchash usullari
  • O'rtachalashtirish g'oyasi
  • Bias-variance bog'liqligi
  • Tuzoqlar
  • Amaliy: bootstrap tahlili

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


2. Nazariya — chuqur tushuntirish

2.1. Beqarorlik nima

text
BEQAROR model — o'quv ma'lumotining kichik o'zgarishi natijani KATTA o'zgartiradi

Daraxt: juda beqaror
  ildizdagi bo'linish o'zgarsa -> BUTUN daraxt boshqacha
Chiziqli model: barqaror
  koeffitsiyentlar biroz siljiydi, tuzilma o'zgarmaydi
KNN (katta k): barqaror

Beqarorlik = YUQORI DISPERSIYA (variance, 12.5)

Beqarorlik — dispersiyaning boshqa nomi. Daraxt past bias va yuqori dispersiyaga ega model: u ma'lumotdagi har qanday naqshni topa oladi, lekin shovqinni ham naqsh deb qabul qiladi.

2.2. Tuzilma va bashorat beqarorligi

text
Ikki xil beqarorlik:

1. TUZILMA beqarorligi — ildiz belgisi, bo'linishlar tartibi o'zgaradi
   Talqin uchun halokatli
   Deyarli HAR DOIM mavjud

2. BASHORAT beqarorligi — bir xil namuna uchun har xil javob
   Aniqlik uchun muhim
   Tuzilma o'zgarsa ham bashorat o'xshash bo'lishi MUMKIN

Muhim nozik jihat: tuzilma butunlay o'zgarsa ham bashoratlar o'xshash bo'lishi mumkin — ikki xil savol ketma-ketligi bir xil fazoni taxminan bir xil bo'lishi mumkin. Shuning uchun "daraxt har safar boshqacha" degan kuzatuv modelning yaroqsizligini bildirmaydi; u talqinning ishonchsizligini bildiradi.

2.3. Sabablari

text
1. IERARXIK tuzilma — ildizdagi xato pastga tarqaladi
2. OCHKO'Z tanlov — teng sifatli bo'linishdan biri tanlanadi (tasodifiy)
3. DISKRET chegara — bitta namuna chegarani siljitadi
4. KORRELYATSIYALI belgilar — qaysi biri tanlanishi deyarli tasodif

Eng kuchli sabab: korrelyatsiyali belgilar + teng sifatli bo'linishlar

Korrelyatsiyali belgilar beqarorlikning asosiy manbai: ikki belgi 0.95 korrelyatsiyaga ega bo'lsa, ular deyarli bir xil ma'lumot beradi va qaysi biri ildizda bo'lishi amalda tanga tashlashga teng. Bu feature_importances_ ni ham buzadi 15.11-bob.

2.4. O'lchash usullari

text
1. Bootstrap: B ta namuna, har birida daraxt qurib, taqqoslash
   - ildiz belgisining taqsimoti
   - barglar sonining tarqalishi
   - bashoratlar bo'yicha kelishmovchilik ulushi

2. Bashorat dispersiyasi:
   var(x) = B ta daraxtning x uchun bashoratlari dispersiyasi

3. Kelishuv (agreement): ikki daraxt bir xil javob beradigan namunalar ulushi

4. random_state ni o'zgartirish — faqat teng bo'linishlar ta'siri

random_state ni o'zgartirish beqarorlikning eng kichik qismini ko'rsatadi (faqat teng sifatli bo'linishlardagi tanlov). Haqiqiy beqarorlik uchun ma'lumotni o'zgartirish kerak — bootstrap yoki turli CV bo'linishlari.

2.5. O'rtachalashtirish g'oyasi

text
Agar B ta mustaqil model dispersiyasi sigma^2 bo'lsa:
  o'rtacha dispersiyasi = sigma^2 / B

Lekin daraxtlar bir xil ma'lumotdan o'qitilsa — MUSTAQIL EMAS:
  var(o'rtacha) = rho * sigma^2 + (1 - rho) * sigma^2 / B
  rho — daraxtlar orasidagi korrelyatsiya

B -> cheksiz:  var -> rho * sigma^2

XULOSA: dispersiyani kamaytirish uchun KORRELYATSIYANI kamaytirish kerak
  bootstrap 15.4-bob + tasodifiy belgi tanlash (15.5)

Bu formula butun ansambl nazariyasining o'zagi: daraxtlar sonini oshirish faqat (1-rho)*sigma^2/B qismini kamaytiradi, rho*sigma^2 qismi qoladi. Shuning uchun Random Forest da max_features (korrelyatsiyani kamaytirish) n_estimators dan muhimroq.

2.6. Bias-variance bog'liqligi

text
Chuqur daraxt:  past bias, YUQORI dispersiya  -> bagging yordam beradi
Sayoz daraxt:   yuqori bias, past dispersiya  -> boosting yordam beradi

Bagging 15.4-bob:  dispersiyani kamaytiradi, bias ni deyarli o'zgartirmaydi
Boosting 15.7-bob: bias ni kamaytiradi, dispersiyani oshirishi mumkin

Ikki ansambl oilasi turli muammoni hal qiladi: bagging yuqori dispersiyali modellar uchun, boosting yuqori biasli modellar uchun. Shuning uchun Random Forest da daraxtlar to'liq o'stiriladi, gradient boosting da esa sayoz (3-6 daraja).

2.7. Tuzoqlar

Asosiy tuzoqlar: daraxt tuzilmasini "topilgan bilim" sifatida e'lon qilish; random_state ni o'zgartirib beqarorlikni "o'lchadim" deb hisoblash; beqarorlikni faqat kamchilik deb ko'rish (u ansambl uchun foydali); korrelyatsiyali belgilarni tozalamay feature_importances_ ga ishonish; bitta bo'linish farqini jiddiy talqin qilish; beqarorlikni ko'p ma'lumot bilan to'liq yo'qotish mumkin deb o'ylash.

2.8. Kamchilik — ansamblga yo'l

Daraxt beqaror: o'quv ma'lumotining kichik o'zgarishi tuzilmani butunlay o'zgartiradi (ierarxik tuzilma, ochko'z tanlov, korrelyatsiyali belgilar). Bu — yuqori dispersiya. Tuzilma beqarorligi talqinni ishonchsiz qiladi, bashorat beqarorligi esa aniqlikni pasaytiradi. Yechim — ko'p daraxtni o'rtachalashtirish, lekin faqat ular korrelyatsiyasiz bo'lgandagina foyda beradi. Keyingi dars — bagging.


3. Tez ma'lumotnoma

python
import numpy as np
from sklearn.tree import DecisionTreeClassifier

# bootstrap bilan beqarorlikni o'lchash
rng = np.random.default_rng(0)
ildizlar, bashoratlar = [], []
for _ in range(50):
    idx = rng.integers(0, len(X), len(X))
    d = DecisionTreeClassifier(max_depth=5, random_state=0).fit(X[idx], y[idx])
    ildizlar.append(d.tree_.feature[0])
    bashoratlar.append(d.predict(Xte))
np.bincount(ildizlar)                       # ildiz belgisining taqsimoti
np.mean(np.std(bashoratlar, axis=0))        # bashorat dispersiyasi
QOIDA: ma'lumotni o'zgartir (random_state emas) · korrelyatsiyali belgilarga
       ehtiyot bo'l · beqarorlik -> ansambl

Beqarorlik xulosasi

Beqarorlik = yuqori dispersiya; daraxtda juda kuchli
Sabablar: ierarxiya, ochko'z tanlov, korrelyatsiyali belgilar
Tuzilma beqarorligi talqinni, bashorat beqarorligi aniqlikni buzadi
var(o'rtacha) = rho*sigma^2 + (1-rho)*sigma^2/B  -> korrelyatsiyani kamaytir

4. Batafsil misollar

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

Misol 1 — Tuzilma beqarorligi

python
"""Bootstrap namunalarda daraxt tuzilmasi qanday o'zgaradi (real numpy/sklearn)."""

import numpy as np
from sklearn.tree import DecisionTreeClassifier, export_text


def yarat(seed: int = 12, n: int = 1500):
    """daromad va xarajat - bir yashirin omilning ikki o'lchovi."""
    rng = np.random.default_rng(seed)
    holat = rng.normal(0, 1, n)                     # yashirin moliyaviy holat
    daromad = holat + rng.normal(0, 0.35, n)
    xarajat = holat + rng.normal(0, 0.35, n)
    kechikish = rng.poisson(0.6, n).astype(float)
    yosh = rng.integers(21, 65, n).astype(float)
    kuch = -1.6 * holat + 1.0 * (kechikish >= 1)
    y = (rng.random(n) < 1 / (1 + np.exp(-kuch))).astype(int)
    X = np.column_stack([daromad, xarajat, kechikish, yosh])
    return X, y, ["daromad", "xarajat", "kechikish", "yosh"]


def main() -> None:
    X, y, nomlar = yarat()
    rng = np.random.default_rng(0)

    print("=== 1. Belgilar korrelyatsiyasi ===")
    K = np.corrcoef(X.T)
    print(f"  daromad - xarajat: {K[0, 1]:.4f}")
    print(f"  daromad - kechikish: {K[0, 2]:.4f}")
    print("  (ikkalasi ham bir yashirin omilning o'lchovi)")

    print("\n=== 2. 100 bootstrap namunada ildiz belgisi ===")
    ildizlar, chuqurliklar, barglar = [], [], []
    for _ in range(100):
        idx = rng.integers(0, len(X), len(X))
        d = DecisionTreeClassifier(max_depth=4, min_samples_leaf=20,
                                   random_state=0).fit(X[idx], y[idx])
        ildizlar.append(int(d.tree_.feature[0]))
        chuqurliklar.append(d.get_depth())
        barglar.append(d.get_n_leaves())
    sanoq = np.bincount(ildizlar, minlength=len(nomlar))
    for i, nom in enumerate(nomlar):
        print(f"  {nom:<10}: {sanoq[i]:>3} marta ildizda")
    print("  (tanlov amalda tanga tashlashga yaqin)")

    print("\n=== 3. Daraxt o'lchami tarqalishi ===")
    print(f"  barglar: min {min(barglar)}, mediana "
          f"{int(np.median(barglar))}, max {max(barglar)}")
    print(f"  chuqurlik: min {min(chuqurliklar)}, max {max(chuqurliklar)}")

    print("\n=== 4. Ikki bootstrap daraxtining tuzilmasi ===")
    for nechanchi in [0, 1]:
        r2 = np.random.default_rng(100 + nechanchi)
        idx = r2.integers(0, len(X), len(X))
        d = DecisionTreeClassifier(max_depth=2, min_samples_leaf=50,
                                   random_state=0).fit(X[idx], y[idx])
        print(f"  --- namuna {nechanchi + 1}: ildiz = "
              f"{nomlar[int(d.tree_.feature[0])]} ---")
        for qator in export_text(d, feature_names=nomlar,
                                 decimals=2).splitlines():
            print("    " + qator)
    print("  ⭐ Bir xil taqsimot, boshqa tuzilma")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Belgilar korrelyatsiyasi ===
  daromad - xarajat: 0.8891
  daromad - kechikish: -0.0070
  (ikkalasi ham bir yashirin omilning o'lchovi)

=== 2. 100 bootstrap namunada ildiz belgisi ===
  daromad   :  33 marta ildizda
  xarajat   :  67 marta ildizda
  kechikish :   0 marta ildizda
  yosh      :   0 marta ildizda
  (tanlov amalda tanga tashlashga yaqin)

=== 3. Daraxt o'lchami tarqalishi ===
  barglar: min 11, mediana 15, max 16
  chuqurlik: min 4, max 4

=== 4. Ikki bootstrap daraxtining tuzilmasi ===
  --- namuna 1: ildiz = xarajat ---
    |--- xarajat <= -0.02
    |   |--- xarajat <= -0.72
    |   |   |--- class: 1
    |   |--- xarajat >  -0.72
    |   |   |--- class: 1
    |--- xarajat >  -0.02
    |   |--- daromad <= 1.07
    |   |   |--- class: 0
    |   |--- daromad >  1.07
    |   |   |--- class: 0
  --- namuna 2: ildiz = daromad ---
    |--- daromad <= 0.38
    |   |--- xarajat <= -0.54
    |   |   |--- class: 1
    |   |--- xarajat >  -0.54
    |   |   |--- class: 1
    |--- daromad >  0.38
    |   |--- daromad <= 1.07
    |   |   |--- class: 0
    |   |--- daromad >  1.07
    |   |   |--- class: 0
  ⭐ Bir xil taqsimot, boshqa tuzilma

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

Misol 2 — Bashorat beqarorligi

python
"""Bir xil namuna uchun har xil javoblar (real numpy/sklearn)."""

import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeClassifier


def yarat(seed: int = 8, n: int = 2500, shovqin: float = 0.12):
    """Qoidaga asoslangan ma'lumot: daraxt uchun tabiiy vazifa."""
    rng = np.random.default_rng(seed)
    X = rng.normal(0, 1, (n, 8))
    qoida = (((X[:, 0] > 0.4) & (X[:, 1] < 0.0))
             | ((X[:, 2] > 0.0) & (X[:, 3] > 0.5))
             | (X[:, 4] < -1.2))
    y = qoida.astype(int)
    alm = rng.random(n) < shovqin
    y[alm] = 1 - y[alm]
    return X, y


def modellar():
    return {
        "daraxt(to'liq)": DecisionTreeClassifier(random_state=0),
        "daraxt(4)": DecisionTreeClassifier(max_depth=4, random_state=0),
        "LogReg": Pipeline([("sc", StandardScaler()),
                            ("m", LogisticRegression(max_iter=2000))]),
        "KNN(25)": Pipeline([("sc", StandardScaler()),
                             ("m", KNeighborsClassifier(25))]),
    }


def main() -> None:
    X, y = yarat()
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=0,
                                          stratify=y)
    rng = np.random.default_rng(1)

    print("=== 1. 40 bootstrapda bashoratlar tarqalishi ===")
    natijalar = {nom: [] for nom in modellar()}
    for _ in range(40):
        idx = rng.integers(0, len(Xtr), len(Xtr))
        for nom, m in modellar().items():
            m.fit(Xtr[idx], ytr[idx])
            natijalar[nom].append(m.predict_proba(Xte)[:, 1])

    print(f"  {'model':<15} {'o_rtacha std':>14} {'aniqlik o_rt':>14} "
          f"{'aniqlik std':>13}")
    for nom, qatorlar in natijalar.items():
        P = np.array(qatorlar)
        aniqliklar = [((p > 0.5).astype(int) == yte).mean() for p in P]
        print(f"  {nom:<15} {P.std(axis=0).mean():>14.4f} "
              f"{np.mean(aniqliklar):>14.4f} {np.std(aniqliklar):>13.4f}")

    print("\n=== 2. Bitta namuna uchun 40 ta bashorat ===")
    for nom in ["daraxt(to'liq)", "LogReg"]:
        P = np.array(natijalar[nom])[:, 0]
        print(f"  {nom:<15}: min {P.min():.3f}, mediana {np.median(P):.3f}, "
              f"max {P.max():.3f}")

    print("\n=== 3. Ikki daraxt qancha namunada kelishmaydi ===")
    P = np.array(natijalar["daraxt(to'liq)"]) > 0.5
    kelishmovchilik = [(P[i] != P[j]).mean()
                       for i in range(10) for j in range(i + 1, 10)]
    Pl = np.array(natijalar["LogReg"]) > 0.5
    kl = [(Pl[i] != Pl[j]).mean() for i in range(10) for j in range(i + 1, 10)]
    print(f"  daraxt: o'rtacha {np.mean(kelishmovchilik):.4f} namunada farq")
    print(f"  LogReg: o'rtacha {np.mean(kl):.4f} namunada farq")

    print("\n=== 4. 40 daraxtni o'rtachalashtirish ===")
    Pd = np.array(natijalar["daraxt(to'liq)"])
    for nechta in [1, 5, 10, 20, 40]:
        ortacha = Pd[:nechta].mean(axis=0)
        print(f"  {nechta:>2} daraxt: aniqlik "
              f"{((ortacha > 0.5).astype(int) == yte).mean():.4f}")
    print("  ⭐ O'rtachalashtirish dispersiyani kamaytiradi 15.4-bob")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. 40 bootstrapda bashoratlar tarqalishi ===
  model             o_rtacha std   aniqlik o_rt   aniqlik std
  daraxt(to'liq)          0.2803         0.7730        0.0151
  daraxt(4)               0.0848         0.8396        0.0139
  LogReg                  0.0284         0.6921        0.0074
  KNN(25)                 0.0886         0.7293        0.0094

=== 2. Bitta namuna uchun 40 ta bashorat ===
  daraxt(to'liq) : min 0.000, mediana 1.000, max 1.000
  LogReg         : min 0.798, mediana 0.849, max 0.885

=== 3. Ikki daraxt qancha namunada kelishmaydi ===
  daraxt: o'rtacha 0.2138 namunada farq
  LogReg: o'rtacha 0.0402 namunada farq

=== 4. 40 daraxtni o'rtachalashtirish ===
   1 daraxt: aniqlik 0.7613
   5 daraxt: aniqlik 0.8227
  10 daraxt: aniqlik 0.8387
  20 daraxt: aniqlik 0.8560
  40 daraxt: aniqlik 0.8613
  ⭐ O'rtachalashtirish dispersiyani kamaytiradi (15.4)

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

Misol 3 — Beqarorlik sabablari

python
"""Korrelyatsiyali belgilar va teng sifatli bo'linishlar (real numpy/sklearn)."""

import numpy as np
from sklearn.tree import DecisionTreeClassifier


def yarat(korrelyatsiya: float, seed: int = 3, n: int = 1500):
    """y faqat `a` ga bog'liq; `b` - uning korrelyatsiyali nusxasi."""
    rng = np.random.default_rng(seed)
    a = rng.normal(0, 1, n)
    b = korrelyatsiya * a + np.sqrt(1 - korrelyatsiya ** 2) * rng.normal(0, 1, n)
    shovqin = rng.normal(0, 1, (n, 3))
    X = np.column_stack([a, b, shovqin])
    y = (rng.random(n) < 1 / (1 + np.exp(-1.8 * a))).astype(int)
    return X, y


def ildiz_taqsimoti(korrelyatsiya: float, n: int = 1500, chuqurlik: int = 3,
                    toplamlar: int = 10, bootstraplar: int = 10):
    """Bir necha o'quv to'plami va ularning bootstrap namunalari bo'yicha."""
    sanoq = np.zeros(5, dtype=int)
    for s in range(toplamlar):
        X, y = yarat(korrelyatsiya, seed=s, n=n)
        rng = np.random.default_rng(s)
        for _ in range(bootstraplar):
            idx = rng.integers(0, len(X), len(X))
            d = DecisionTreeClassifier(max_depth=chuqurlik, min_samples_leaf=30,
                                       random_state=0).fit(X[idx], y[idx])
            sanoq[int(d.tree_.feature[0])] += 1
    return sanoq


def main() -> None:
    print("=== 1. Korrelyatsiya va ildiz tanlovi ===")
    print(f"  {'korr':>6} {'belgi_a':>9} {'belgi_b':>9} {'shovqin':>9} "
          f"{'eng ko_p':>10}")
    for k in [0.0, 0.5, 0.9, 0.99, 0.999]:
        s = ildiz_taqsimoti(k)
        print(f"  {k:>6.3f} {s[0]:>9} {s[1]:>9} {s[2:].sum():>9} "
              f"{s.max() / s.sum():>9.1%}")
    print("  (y faqat `a` ga bog'liq, lekin `b` uni almashtira oladi)")

    print("\n=== 2. random_state ta'siri (ma'lumot o'zgarmaydi) ===")
    X, y = yarat(0.99, seed=0)
    ildizlar = [int(DecisionTreeClassifier(max_depth=3, min_samples_leaf=30,
                                           random_state=s).fit(X, y)
                    .tree_.feature[0]) for s in range(40)]
    s = np.bincount(ildizlar, minlength=5)
    print(f"  40 ta random_state: belgi_a {s[0]}, belgi_b {s[1]}")
    print("  (ma'lumot o'zgarmasa daraxt ham o'zgarmaydi -")
    print("   demak random_state beqarorlikni O'LCHAMAYDI)")

    print("\n=== 3. Ma'lumot hajmi ta'siri (korr = 0.99) ===")
    print(f"  {'n':>6} {'eng ko_p ildiz':>16} {'bashorat std':>14}")
    for n in [200, 800, 3000, 10000]:
        s = ildiz_taqsimoti(0.99, n=n, chuqurlik=4, toplamlar=8, bootstraplar=6)
        X, y = yarat(0.99, seed=0, n=n)
        rng = np.random.default_rng(0)
        P = []
        for _ in range(30):
            idx = rng.integers(0, len(X), len(X))
            d = DecisionTreeClassifier(max_depth=4, min_samples_leaf=20,
                                       random_state=0).fit(X[idx], y[idx])
            P.append(d.predict_proba(X[:200])[:, 1])
        print(f"  {n:>6} {s.max() / s.sum():>15.1%} "
              f"{np.array(P).std(axis=0).mean():>14.4f}")
    print("  (ko'proq ma'lumot kamaytiradi, lekin yo'qotmaydi)")

    print("\n=== 4. Chuqurlik va beqarorlik ===")
    X, y = yarat(0.5, n=1500)
    rng = np.random.default_rng(0)
    print(f"  {'max_depth':>10} {'bashorat std':>14}")
    for chuqurlik in [2, 3, 5, 8, None]:
        P = []
        for _ in range(30):
            idx = rng.integers(0, len(X), len(X))
            d = DecisionTreeClassifier(max_depth=chuqurlik,
                                       random_state=0).fit(X[idx], y[idx])
            P.append(d.predict_proba(X)[:, 1])
        nom = "None" if chuqurlik is None else str(chuqurlik)
        print(f"  {nom:>10} {np.array(P).std(axis=0).mean():>14.4f}")
    print("  ⭐ Chuqurroq daraxt - beqarorroq")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Korrelyatsiya va ildiz tanlovi ===
    korr   belgi_a   belgi_b   shovqin   eng ko_p
   0.000       100         0         0    100.0%
   0.500       100         0         0    100.0%
   0.900       100         0         0    100.0%
   0.990        69        31         0     69.0%
   0.999        44        56         0     56.0%
  (y faqat `a` ga bog'liq, lekin `b` uni almashtira oladi)

=== 2. random_state ta'siri (ma'lumot o'zgarmaydi) ===
  40 ta random_state: belgi_a 40, belgi_b 0
  (ma'lumot o'zgarmasa daraxt ham o'zgarmaydi -
   demak random_state beqarorlikni O'LCHAMAYDI)

=== 3. Ma'lumot hajmi ta'siri (korr = 0.99) ===
       n   eng ko_p ildiz   bashorat std
     200           68.8%         0.1478
     800           72.9%         0.1324
    3000           89.6%         0.0779
   10000           95.8%         0.0488
  (ko'proq ma'lumot kamaytiradi, lekin yo'qotmaydi)

=== 4. Chuqurlik va beqarorlik ===
   max_depth   bashorat std
           2         0.0643
           3         0.0821
           5         0.1313
           8         0.2108
        None         0.2705
  ⭐ Chuqurroq daraxt - beqarorroq

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

Misol 4 — O'rtachalashtirish formulasi

python
"""var(o'rtacha) = rho*s^2 + (1-rho)*s^2/B ni tekshirish (real numpy/sklearn)."""

import numpy as np
from sklearn.tree import DecisionTreeRegressor


def yarat(seed: int, n: int = 600):
    rng = np.random.default_rng(seed)
    X = rng.uniform(-3, 3, (n, 4))
    f = np.sin(X[:, 0]) + 0.5 * X[:, 1] - 0.3 * X[:, 2] ** 2
    return X, f + rng.normal(0, 1.0, n), f


def toplam(Xte, M: int = 20, B: int = 10, max_features=None, n: int = 600):
    """M ta MUSTAQIL o'quv to'plami, har birida B ta bootstrap daraxti."""
    P = []
    for m in range(M):
        Xtr, ytr, _ = yarat(m + 1, n)
        rng = np.random.default_rng(1000 + m)
        qator = []
        for _ in range(B):
            idx = rng.integers(0, len(Xtr), len(Xtr))
            d = DecisionTreeRegressor(max_features=max_features,
                                      random_state=int(rng.integers(1_000_000)))
            d.fit(Xtr[idx], ytr[idx])
            qator.append(d.predict(Xte))
        P.append(qator)
    return np.array(P)                      # (M, B, test)


def main() -> None:
    Xte, yte, fte = yarat(999, 400)

    print("=== 1. Bitta daraxt va o'rtachalashtirilgan daraxtlar ===")
    P = toplam(Xte, M=20, B=16)
    M, B, _ = P.shape
    bitta = float(((P.reshape(M * B, -1) - fte) ** 2).mean())
    print(f"  bitta daraxt MSE: {bitta:.4f}")
    for b in [1, 2, 4, 8, 16]:
        ansambl = P[:, :b].mean(axis=1)
        print(f"  {b:>2} daraxt o'rtachasi MSE: "
              f"{((ansambl - fte) ** 2).mean():.4f}")

    print("\n=== 2. Dispersiya va korrelyatsiya ===")
    sigma2 = float(P.reshape(M * B, -1).var(axis=0, ddof=1).mean())
    vB = float(P.mean(axis=1).var(axis=0, ddof=1).mean())
    rho = (vB / sigma2 - 1 / B) / (1 - 1 / B)       # formuladan yechilgan
    print(f"  bitta daraxt dispersiyasi (s^2): {sigma2:.4f}")
    print(f"  {B} ta daraxt o'rtachasining dispersiyasi: {vB:.4f}")
    print(f"  daraxtlar korrelyatsiyasi (rho): {rho:.4f}")

    print("\n=== 3. Formula bashorati va haqiqat ===")
    print(f"  {'B':>4} {'formula':>10} {'haqiqiy':>10}")
    for b in [1, 2, 4, 8, 16]:
        formula = rho * sigma2 + (1 - rho) * sigma2 / b
        haqiqiy = float(P[:, :b].mean(axis=1).var(axis=0, ddof=1).mean())
        print(f"  {b:>4} {formula:>10.4f} {haqiqiy:>10.4f}")
    print(f"  chegara qiymati (B -> cheksiz): {rho * sigma2:.4f}")

    print("\n=== 4. Korrelyatsiyani kamaytirish ta'siri ===")
    print(f"  {'max_features':>13} {'rho':>8} {'bias^2':>9} {'dispersiya':>12} "
          f"{'MSE':>9}")
    for mf in [4, 3, 2, 1]:
        P2 = toplam(Xte, M=20, B=10, max_features=mf)
        M2, B2, _ = P2.shape
        ansambl = P2.mean(axis=1)
        s2 = float(P2.reshape(M2 * B2, -1).var(axis=0, ddof=1).mean())
        v2 = float(ansambl.var(axis=0, ddof=1).mean())
        rho2 = (v2 / s2 - 1 / B2) / (1 - 1 / B2)
        bias2 = float(((ansambl.mean(axis=0) - fte) ** 2).mean())
        mse = float(((ansambl - fte) ** 2).mean())
        print(f"  {mf:>13} {rho2:>8.4f} {bias2:>9.4f} {v2:>12.4f} {mse:>9.4f}")
    print("  ⭐ rho kamayadi, lekin bias oshadi - o'rtada optimum bor 15.5-bob")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Bitta daraxt va o'rtachalashtirilgan daraxtlar ===
  bitta daraxt MSE: 1.3409
   1 daraxt o'rtachasi MSE: 1.3242
   2 daraxt o'rtachasi MSE: 0.7830
   4 daraxt o'rtachasi MSE: 0.4822
   8 daraxt o'rtachasi MSE: 0.3507
  16 daraxt o'rtachasi MSE: 0.2773

=== 2. Dispersiya va korrelyatsiya ===
  bitta daraxt dispersiyasi (s^2): 1.3100
  16 ta daraxt o'rtachasining dispersiyasi: 0.2550
  daraxtlar korrelyatsiyasi (rho): 0.1409

=== 3. Formula bashorati va haqiqat ===
     B    formula    haqiqiy
     1     1.3100     1.3033
     2     0.7473     0.7571
     4     0.4660     0.4612
     8     0.3253     0.3281
    16     0.2550     0.2550
  chegara qiymati (B -> cheksiz): 0.1846

=== 4. Korrelyatsiyani kamaytirish ta'siri ===
   max_features      rho    bias^2   dispersiya       MSE
              4   0.1478    0.0373       0.3067    0.3287
              3   0.1312    0.0434       0.2901    0.3190
              2   0.0967    0.0600       0.2670    0.3136
              1   0.0604    0.1358       0.2627    0.3854
  ⭐ rho kamayadi, lekin bias oshadi - o'rtada optimum bor (15.5)

Nima ko'rsatdi: 2.5-bo'lim.


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

Noto'g'ri fikr To'g'risi
"Daraxt tuzilmasi — topilgan bilim" Beqaror, takrorlanmaydi
"random_state beqarorlikni o'lchaydi" Faqat kichik qismini
"Tuzilma o'zgarsa bashorat ham o'zgaradi" Shart emas
"Beqarorlik faqat kamchilik" Ansambl uchun foydali
"Ko'p ma'lumot beqarorlikni yo'qotadi" Kamaytiradi, yo'qotmaydi
"Korrelyatsiya ahamiyatsiz" Asosiy sabab
"B oshsa dispersiya 0 ga boradi" rho*sigma^2 qoladi
"Sayoz daraxt ham beqaror" Ancha barqarorroq

6. Keng tarqalgan xatolar va yechimlari

1. Tuzilmani hujjatga kiritish

python
# "ildiz belgi — kechikish" deb qoidaga yozish                     # ⚠️
# bootstrapda ildiz taqsimotini tekshiring                         # ✅

2. random_state bilan o'lchash

python
for s in range(10): DecisionTreeClassifier(random_state=s)         # ⚠️
for _ in range(100): idx = rng.integers(0, n, n)   # bootstrap     # ✅

3. Korrelyatsiyali belgilarni e'tiborsiz qoldirish

python
d.feature_importances_                   # korrelyatsiya buzadi    # ⚠️
# avval korrelyatsiya matritsasini ko'ring 15.11-bob                 # ✅

4. Bitta daraxtga tayanish

python
model = DecisionTreeClassifier(max_depth=8).fit(X, y)              # ⚠️
RandomForestClassifier(n_estimators=300)                           # ✅

5. Chuqur daraxtdan barqarorlik kutish

python
DecisionTreeClassifier()                 # eng beqaror variant     # ⚠️
DecisionTreeClassifier(max_depth=3)      # talqin uchun barqarorroq # ✅

6. n_estimators ni cheksiz oshirish

python
RandomForestClassifier(n_estimators=10000)   # rho*sigma^2 qoladi  # ⚠️
RandomForestClassifier(n_estimators=500, max_features="sqrt")      # ✅

7. Beqarorlikni xato deb hisoblash

python
# "daraxt har safar boshqacha — algoritm buzuq"                    # ⚠️
# bu tuzilmaviy xususiyat; ansambl aynan shundan foydalanadi       # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 12.5-dars (o'tilgan): Bias-variance
  • 15.4-dars: Bagging
  • 15.5-dars: Random Forest va max_features
  • 15.11-dars: Belgi muhimligi
  • 15.7-dars: Boosting (boshqa yondashuv)

8. Eng yaxshi amaliyotlar

  1. Beqarorlikni bootstrap bilan o'lchang.

  2. Tuzilmani bilim deb e'lon qilmang.

  3. Korrelyatsiyali belgilarni tekshiring.

  4. Talqin uchun sayoz daraxt.

  5. Aniqlik uchun ansambl.

  6. Korrelyatsiyani kamaytiring.

  7. n_estimators ni oqilona tanlang.

  8. Bashorat va tuzilma beqarorligini ajrating.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # beqarorlik = qaysi tushuncha?
2.  # daraxt beqarormi?
3.  # ikki xil beqarorlik?
4.  # asosiy sabab?
5.  # random_state yetarlimi?
6.  # o'rtachalashtirish formulasi?
7.  # B -> cheksiz da nima qoladi?
8.  # nimani kamaytirish kerak?
9.  # bagging nimani kamaytiradi?
10. # boosting nimani kamaytiradi?
11. # chuqurroq daraxt qanday?
12. # ko'p ma'lumot yordam beradimi?
Javoblar
  1. Dispersiya (variance)
  2. Ha, juda
  3. Tuzilma va bashorat
  4. Korrelyatsiyali belgilar
  5. Yo'q
  6. rho*s^2 + (1-rho)*s^2/B
  7. rho*sigma^2
  8. Korrelyatsiyani (rho)
  9. Dispersiyani
  10. Bias ni
  11. Beqarorroq
  12. Kamaytiradi, yo'qotmaydi

Vazifa 2: Xatolarni tuzating

python
1.  # "ildiz belgi = kechikish" deb qoidaga yozish

2.  for s in range(10): DecisionTreeClassifier(random_state=s)

3.  d.feature_importances_   # korrelyatsiya tekshirilmagan

4.  model = DecisionTreeClassifier(max_depth=12).fit(X, y)

5.  RandomForestClassifier(n_estimators=10000)
Javoblar
python
1.  # bootstrapda ildiz taqsimotini ko'ring

2.  for _ in range(100): idx = rng.integers(0, n, n)

3.  # avval np.corrcoef(X.T) ni ko'ring

4.  RandomForestClassifier(n_estimators=300)

5.  RandomForestClassifier(n_estimators=500, max_features="sqrt")

Vazifa 3: Tuzilma

Modellang:

  1. Korrelyatsiya
  2. Ildiz taqsimoti
  3. O'lcham tarqalishi
  4. Ikki daraxt

Vazifa 4: Bashorat

Modellang:

  1. Tarqalish
  2. Bitta namuna
  3. Kelishmovchilik
  4. O'rtachalashtirish

Vazifa 5: Sabablar

Modellang:

  1. Korrelyatsiya ta'siri
  2. random_state
  3. Ma'lumot hajmi
  4. Chuqurlik

Vazifa 6: Formula

Modellang:

  1. O'rtachalashtirish
  2. rho va sigma^2
  3. Formula
  4. max_features

Vazifa 7: O'ylash

Agar daraxt shunchalik beqaror bo'lsa, nega uni ansambl asosi sifatida tanlashgan? Barqaror modeldan (masalan chiziqli regressiya) ansambl qurish mantiqiyroq emasmi?

Javob

Qisqa javob: aynan beqarorlik daraxtni ideal ansambl a'zosi qiladi. O'rtachalashtirish dispersiyani kamaytiradi, biasni kamaytirmaydi — shuning uchun ansambl uchun past biasli, yuqori dispersiyali model kerak. Chiziqli modellarning bagging i deyarli hech narsa bermaydi, chunki ularda kamaytiriladigan dispersiya yo'q.

1. Nima o'rtachalashtiriladi

Model Bias Dispersiya Bagging foydasi
Chuqur daraxt Past Yuqori Katta
Chiziqli regressiya Yuqori Past Deyarli yo'q
KNN (k katta) O'rta Past Kichik

Bagging o'rtacha modelning biasini o'zgartirmaydi: E[o'rtacha] = E[bitta model]. Faqat dispersiya rho*sigma^2 gacha tushadi.

2. Chiziqli modellar uchun

  • Bootstrap namunalarda koeffitsiyentlar biroz farq qiladi
  • Ularning o'rtachasi ~ butun ma'lumotdagi koeffitsiyentlar
  • Natija: bagging deyarli bir xil modelni qaytaradi
  • Agar model noto'g'ri (yuqori bias) bo'lsa, 1000 ta ham to'g'rilamaydi

3. Daraxtning yana ikki afzalligi

  1. Tez — bo'linish qidiruvi sodda, minglab daraxt quriladi
  2. Moslashuvchan — har qanday shakl, o'zaro ta'sir, masshtablash shart emas

4. Lekin boosting boshqacha

Boosting (15.7) biasni kamaytiradi, shuning uchun u yuqori biasli bazaviy modelni talab qiladi — sayoz daraxt (stump yoki 3-6 daraja). Bu yerda chuqur daraxt zarar keltiradi.

5. Xulosa

  1. Bagging dispersiyani kamaytiradi -> beqaror model kerak
  2. Boosting biasni kamaytiradi -> sodda model kerak
  3. Daraxt ikkala rejimda ham sozlanadi
  4. Chiziqli model hech qaysisiga mos emas

Nimani mustahkamlaydi: 2.5, 2.6-bo'limlar.


Xulosa

Bu darsda daraxt beqarorligini o'rgandik.

Eng muhim uch fikr:

  1. Daraxt juda beqaror. O'quv ma'lumotining kichik o'zgarishi tuzilmani butunlay o'zgartiradi. Sabablari: ierarxik tuzilma (ildizdagi o'zgarish pastga tarqaladi), ochko'z tanlov (teng sifatli bo'linishdan biri tasodifiy tanlanadi) va eng muhimi — korrelyatsiyali belgilar.

  2. Ikki xil beqarorlik. Tuzilma beqarorligi talqinni ishonchsiz qiladi (daraxtdan chiqarilgan qoidani hujjatga yozish xavfli), bashorat beqarorligi esa aniqlikni pasaytiradi. Ular bog'liq emas: tuzilma butunlay o'zgarsa ham bashoratlar o'xshash bo'lishi mumkin. Beqarorlikni random_state bilan emas, bootstrap bilan o'lchang.

  3. O'rtachalashtirish — yechim, lekin shartli. var(o'rtacha) = rho*sigma^2 + (1-rho)*sigma^2/B formulasiga ko'ra daraxtlar sonini oshirish faqat ikkinchi hadni kamaytiradi; rho*sigma^2 qoladi. Shuning uchun ansambl qurishda asosiy vazifa — daraxtlar orasidagi korrelyatsiyani kamaytirish (bootstrap + tasodifiy belgi tanlash).

Keyingi darsda baggingni o'rganamiz: bootstrap agregatsiyasi, OOB baho va nima uchun u dispersiyani kamaytiradi.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
15.3-dars: Daraxt beqarorligi — IlmHamroh