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

15.1-dars: Qaror daraxti

15-QISM — DARAXTLAR VA ANSAMBLLAR · 1-dars


1. Kirish va motivatsiya

Qaror daraxti — ML dagi eng tushunarli model: u ketma-ket savollar beradi ("daromad 5 mln dan kattami?", "kechikish bo'lganmi?") va javoblarga qarab bashoratga keladi. Bu — insonning tabiiy qaror qabul qilish usuli, shuning uchun daraxtni har qanday mutaxassisga tushuntirish mumkin.

Lekin daraxtlarning asosiy qiymati boshqa joyda: ular ansambllar (Random Forest, gradient boosting) uchun qurilish bloki bo'lib, jadval ma'lumotidagi eng kuchli modellarni hosil qiladi. Bitta daraxt kuchsiz, yuzlab daraxt esa deyarli har doim eng yaxshi natijani beradi.

Bu darsda: daraxt tuzilishi va bashorat jarayoni, bo'linish qanday tanlanadi (Gini, entropiya), nopoklik kamayishi (impurity decrease), daraxtning induktiv siljishi (o'qlarga parallel chegaralar — 14.7), regressiya daraxti va sklearn amaliyoti.

Real vaziyat. Sug'urta kompaniyasida da'volarni tekshirish qoidalari 15 yil davomida qo'lda yozilgan: 200 dan ortiq shart. Ma'lumotdan o'qitilgan 6 darajali daraxt shu qoidalarning 80% ini takrorladi va 12 ta yangi naqsh topdi. Eng muhimi: daraxt chizib ko'rsatildi va tekshiruvchilar uni tasdiqladi — qora quti bo'lganda bu imkonsiz edi.

Bu darsda qaror daraxtini o'rganamiz.

Bu darsda:

  • Daraxt tuzilishi
  • Bo'linishni tanlash: Gini va entropiya
  • Nopoklik kamayishi
  • Regressiya daraxti
  • Daraxtning induktiv siljishi
  • sklearn amaliyoti
  • Tuzoqlar
  • Amaliy: daraxtni o'qish

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


2. Nazariya — chuqur tushuntirish

2.1. Daraxt tuzilishi

text
ILDIZ (root)     — birinchi savol, butun ma'lumot
TUGUN (node)     — savol: belgi <= chegara?
BARG (leaf)      — bashorat (sinf yoki son)

Bashorat: ildizdan boshlab savollarga javob berib, bargga yetish
  barg bashorati = shu bargdagi o'quv namunalarining ko'pchilik sinfi
                   (regressiyada — o'rtachasi)

Chuqurlik (depth) — ildizdan bargga eng uzun yo'l
Barglar soni — model murakkabligining o'lchovi

Daraxt — bo'lakli doimiy funksiya: u belgilar fazosini to'rtburchaklarga bo'ladi va har to'rtburchakda doimiy bashorat beradi. Har bashorat uchun aniq yo'l mavjud — shuning uchun daraxt "nega bunday qaror qildi?" degan savolga to'liq javob beradi.

2.2. Bo'linishni tanlash

text
Har tugunda: barcha belgi va chegaralarni sinab, ENG YAXSHI bo'linish tanlanadi

NOPOKLIK (impurity) — tugundagi sinflar aralashganlik darajasi:
  Gini:      1 - sum(p_k^2)           0 (toza) .. 0.5 (ikki sinf teng)
  Entropiya: -sum(p_k * log2(p_k))    0 (toza) .. 1.0 (ikki sinf teng)

Bo'linish sifati = NOPOKLIK KAMAYISHI:
  kamayish = nopoklik(ota) - [n_chap/n * nopoklik(chap) + n_ong/n * nopoklik(ong)]

Eng katta kamayish beradigan bo'linish tanlanadi (ochko'z algoritm)

Daraxt ochko'z (greedy) quriladi: har qadamda mahalliy eng yaxshi bo'linish tanlanadi, global optimal daraxt izlanmaydi (bu NP-qiyin masala). Shuning uchun daraxt "eng yaxshi" emas, "yetarlicha yaxshi" bo'ladi — va bu ansambllar uchun aynan kerak.

2.3. Gini va entropiya farqi

text
Gini      = 1 - sum(p^2)         — tezroq (logarifm yo'q), sklearn standarti
Entropiya = -sum(p * log2(p))    — informatsiya nazariyasidan

Amalda natija DEYARLI BIR XIL (daraxtlar 1-2% farq qiladi)
  Gini biroz ko'proq "sof" bo'linishlarni afzal ko'radi
  Entropiya biroz muvozanatli bo'linishlarni

log_loss (sklearn 1.1+) — entropiya bilan bir xil

criterion tanlovi kamdan-kam ahamiyatli: uni sozlashga vaqt sarflamang. Muhimroq giperparametrlar — chuqurlik va bargdagi minimal namunalar 15.2-bob. Bu — yangi boshlanuvchilar ko'p vaqt yo'qotadigan joy.

2.4. Regressiya daraxti

text
Nopoklik o'rniga: MSE yoki MAE

  MSE bo'linishi: sum((y - o'rtacha)^2) ni minimallashtirish
  barg bashorati: shu bargdagi o'rtacha (MAE da — mediana)

criterion="squared_error" (standart), "absolute_error", "friedman_mse", "poisson"

Natija: bo'lakli DOIMIY funksiya — daraxt ekstrapolyatsiya QILMAYDI
  o'quv diapazonidan tashqarida eng chekka bargning qiymatini qaytaradi

Daraxt ekstrapolyatsiya qilmaydi — bu chiziqli modeldan 13.1-bob asosiy farq va jiddiy cheklov: trend bo'lgan vaqt qatorlarida daraxt kelajakni bashorat qila olmaydi. Yechim: trendni alohida modellab, qoldiqni daraxt bilan (yoki belgi sifatida "vaqt" o'rniga "o'zgarish" berish).

2.5. Induktiv siljish

text
Daraxt chegarasi — O'QLARGA PARALLEL to'rtburchaklar 14.7-bob

Oson: "daromad > X VA yosh < Y" kabi shartlar, o'zaro ta'sirlar
Qiyin: diagonal chegara (zinapoya bilan taqriblanadi — ko'p bo'linish kerak)
       silliq egri chiziqlar

Shuning uchun: daraxt MASSHTABLASHNI TALAB QILMAYDI
  (har belgi alohida ko'riladi, masofa hisoblanmaydi)

Masshtablash kerak emasligi — daraxtlarning katta amaliy afzalligi (KNN va SVM dan farqli — 14.2, 14.5). Shuningdek, ular monoton transformatsiyalarga befarq: log(x) qo'shish daraxt natijasini umuman o'zgartirmaydi (bo'linish tartibi bir xil qoladi).

2.6. sklearn amaliyoti

python
from sklearn.tree import DecisionTreeClassifier, export_text, plot_tree

daraxt = DecisionTreeClassifier(max_depth=4, min_samples_leaf=20,
                                random_state=0).fit(X, y)
print(export_text(daraxt, feature_names=nomlar))

daraxt.tree_.node_count, daraxt.get_depth(), daraxt.get_n_leaves()
daraxt.feature_importances_          # nopoklik kamayishi (15.11 — ehtiyot)
daraxt.decision_path(X[:1])          # bitta namunaning yo'li

export_text — daraxtni matn sifatida ko'rish: hisobot va tekshiruv uchun eng qulay. random_state majburiy: teng sifatli bo'linishlarda tanlov tasodifiy bo'ladi, shuning uchun usiz natija takrorlanmaydi.

2.7. Tuzoqlar

Asosiy tuzoqlar: chuqurlikni cheklamaslik (daraxt o'quvni yodlaydi — 15.2); random_state ni qo'ymaslik; criterion ni sozlashga vaqt sarflash; daraxtdan ekstrapolyatsiya kutish; feature_importances_ ni sababiy talqin qilish 15.11-bob; bitta daraxtga barqaror deb qarash (ma'lumot biroz o'zgarsa tuzilma butunlay o'zgaradi); masshtablash qilish (keraksiz, lekin zararsiz); chuqur daraxtni "talqin qilinadigan" deb hisoblash.

2.8. Sodda, tushunarli, kuchsiz

Qaror daraxti ma'lumotni ketma-ket savollar bilan bo'laklarga ajratadi; har tugunda nopoklik kamayishi (Gini yoki entropiya) eng katta bo'lgan bo'linish ochko'z tanlanadi. Chegara — o'qlarga parallel to'rtburchaklar, shuning uchun masshtablash kerak emas va monoton transformatsiyalar natijani o'zgartirmaydi. Regressiyada barg o'rtachani qaytaradi va daraxt ekstrapolyatsiya qilmaydi. Bitta daraxt kuchsiz va beqaror — lekin u ansambllarning qurilish bloki 15.4-bob. Keyingi dars — daraxt o'sishi va to'xtash shartlari.


3. Tez ma'lumotnoma

python
import numpy as np
from sklearn.tree import (DecisionTreeClassifier, DecisionTreeRegressor,
                          export_text, plot_tree)

d = DecisionTreeClassifier(criterion="gini", max_depth=4, min_samples_leaf=20,
                           random_state=0).fit(X, y)
print(export_text(d, feature_names=list(nomlar)))
d.get_depth(), d.get_n_leaves(), d.tree_.node_count

# tugun ma'lumotlari
d.tree_.feature, d.tree_.threshold, d.tree_.impurity, d.tree_.value

# regressiya
DecisionTreeRegressor(max_depth=5, min_samples_leaf=10, random_state=0)
QOIDA: chuqurlikni chekla · random_state qo'y · masshtablash shart emas ·
       ekstrapolyatsiya yo'q

Daraxt xulosasi

Tugun = savol, barg = bashorat; bashorat = ildizdan bargga yo'l
Gini = 1 - sum(p^2), entropiya = -sum(p log2 p); farqi kichik
Bo'linish = nopoklik kamayishi eng katta bo'lgan joy (ochko'z)
Chegara o'qlarga parallel; masshtablash keraksiz; ekstrapolyatsiya yo'q

4. Batafsil misollar

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

Misol 1 — Bo'linishni qo'lda hisoblash

python
"""Gini, entropiya va nopoklik kamayishi (real numpy/sklearn)."""

import numpy as np
from sklearn.tree import DecisionTreeClassifier


def gini(y) -> float:
    if len(y) == 0:
        return 0.0
    p = np.bincount(y, minlength=2) / len(y)
    return float(1 - (p ** 2).sum())


def entropiya(y) -> float:
    if len(y) == 0:
        return 0.0
    p = np.bincount(y, minlength=2) / len(y)
    p = p[p > 0]
    return float(-(p * np.log2(p)).sum() + 0.0)   # -0.0 ni 0.0 ga


def main() -> None:
    rng = np.random.default_rng(3)
    n = 400
    x = rng.uniform(0, 10, n)
    y = ((x > 6.2) ^ (rng.random(n) < 0.08)).astype(int)   # 8% shovqin

    print("=== 1. Nopoklik o'lchovlari ===")
    for nom, taqsimot in [("toza (0/100)", np.zeros(100, dtype=int)),
                          ("90/10", np.array([0] * 90 + [1] * 10)),
                          ("70/30", np.array([0] * 70 + [1] * 30)),
                          ("50/50", np.array([0] * 50 + [1] * 50))]:
        print(f"  {nom:<14}: Gini {gini(taqsimot):.4f}, "
              f"entropiya {entropiya(taqsimot):.4f}")

    print("\n=== 2. Chegara bo'yicha nopoklik kamayishi ===")
    asosiy = gini(y)
    print(f"  ildiz Gini = {asosiy:.4f} (musbat sinf {y.mean():.2%})")
    print(f"  {'chegara':>8} {'chap n':>7} {'ong n':>7} {'kamayish':>10}")
    eng_kamayish, eng_chegara = -1.0, None
    for chegara in [2.0, 4.0, 5.0, 6.0, 6.2, 7.0, 8.0]:
        chap, ong = y[x <= chegara], y[x > chegara]
        kamayish = asosiy - (len(chap) / n * gini(chap)
                             + len(ong) / n * gini(ong))
        if kamayish > eng_kamayish:
            eng_kamayish, eng_chegara = kamayish, chegara
        print(f"  {chegara:>8.1f} {len(chap):>7} {len(ong):>7} {kamayish:>10.4f}")
    print(f"  eng yaxshi chegara: {eng_chegara} (kamayish {eng_kamayish:.4f})")

    print("\n=== 3. sklearn bilan tekshirish ===")
    d = DecisionTreeClassifier(max_depth=1, random_state=0).fit(x.reshape(-1, 1), y)
    print(f"  sklearn tanlagan chegara: {d.tree_.threshold[0]:.4f}")
    print(f"  ildiz nopokligi: {d.tree_.impurity[0]:.4f}")
    print(f"  bolalar nopokligi: {d.tree_.impurity[1]:.4f} va "
          f"{d.tree_.impurity[2]:.4f}")
    print(f"  haqiqiy chegara: 6.2")

    print("\n=== 4. Gini va entropiya bir xil natija beradimi ===")
    for kriteriy in ["gini", "entropy"]:
        d = DecisionTreeClassifier(criterion=kriteriy, max_depth=3,
                                   random_state=0).fit(x.reshape(-1, 1), y)
        chegaralar = sorted(d.tree_.threshold[d.tree_.feature >= 0]
                            .round(3).tolist())
        print(f"  {kriteriy:<8}: {d.get_n_leaves()} barg, "
              f"chegaralar {chegaralar}")
    print("  ⭐ Bo'linish — nopoklik kamayishini maksimallashtirish")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Nopoklik o'lchovlari ===
  toza (0/100)  : Gini 0.0000, entropiya 0.0000
  90/10         : Gini 0.1800, entropiya 0.4690
  70/30         : Gini 0.4200, entropiya 0.8813
  50/50         : Gini 0.5000, entropiya 1.0000

=== 2. Chegara bo'yicha nopoklik kamayishi ===
  ildiz Gini = 0.4916 (musbat sinf 43.50%)
   chegara  chap n   ong n   kamayish
       2.0      73     327     0.0556
       4.0     152     248     0.1129
       5.0     191     209     0.1931
       6.0     235     165     0.2842
       6.2     244     156     0.3046
       7.0     282     118     0.1930
       8.0     326      74     0.1123
  eng yaxshi chegara: 6.2 (kamayish 0.3046)

=== 3. sklearn bilan tekshirish ===
  sklearn tanlagan chegara: 6.1556
  ildiz nopokligi: 0.4916
  bolalar nopokligi: 0.2046 va 0.1404
  haqiqiy chegara: 6.2

=== 4. Gini va entropiya bir xil natija beradimi ===
  gini    : 7 barg, chegaralar [1.034, 1.685, 1.714, 6.156, 8.892, 8.98]
  entropy : 7 barg, chegaralar [1.034, 1.685, 1.714, 6.156, 8.892, 8.98]
  ⭐ Bo'linish — nopoklik kamayishini maksimallashtirish

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

Misol 2 — Daraxtni o'qish

python
"""export_text va qaror yo'li (real pandas/sklearn)."""

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


def yarat(seed: int = 7, n: int = 4000) -> pd.DataFrame:
    """Kredit: qoidalar aniq (daraxt ularni topishi kerak)."""
    rng = np.random.default_rng(seed)
    daromad = rng.lognormal(14.6, 0.5, n)
    kechikish = rng.poisson(0.5, n).astype(float)
    muddat = rng.integers(3, 48, n).astype(float)
    yosh = rng.integers(21, 65, n).astype(float)
    # haqiqiy qoida: past daromad VA kechikish -> xavfli
    xavf = ((daromad < 2.5e6) & (kechikish >= 1)) | (kechikish >= 3)
    y = np.where(rng.random(n) < np.where(xavf, 0.75, 0.10), 1, 0)
    return pd.DataFrame({"daromad": daromad, "kechikish": kechikish,
                         "muddat": muddat, "yosh": yosh, "qaytarmadi": y})


def main() -> None:
    df = yarat()
    nomlar = ["daromad", "kechikish", "muddat", "yosh"]
    X, y = df[nomlar], df["qaytarmadi"]

    print("=== 1. Ma'lumot ===")
    print(f"  {len(df)} ariza, xavfli ulush {y.mean():.2%}")

    print("\n=== 2. Kichik daraxt (max_depth=3) ===")
    d = DecisionTreeClassifier(max_depth=3, min_samples_leaf=50,
                               random_state=0).fit(X, y)
    matn = export_text(d, feature_names=nomlar, decimals=0)
    for qator in matn.splitlines():
        print("  " + qator)

    print("\n=== 3. Daraxt o'lchami ===")
    print(f"  chuqurlik {d.get_depth()}, barglar {d.get_n_leaves()}, "
          f"tugunlar {d.tree_.node_count}")
    print(f"  o'quv aniqligi {d.score(X, y):.4f}")

    print("\n=== 4. Bitta arizaning yo'li ===")
    ariza = X.iloc[[0]]
    yol = d.decision_path(ariza).indices
    for tugun in yol:
        if d.tree_.feature[tugun] >= 0:
            belgi = nomlar[d.tree_.feature[tugun]]
            chegara = d.tree_.threshold[tugun]
            qiymat = float(ariza.iloc[0][belgi])
            yonalish = "chap (<=)" if qiymat <= chegara else "o'ng (>)"
            print(f"  tugun {tugun}: {belgi} = {qiymat:.0f} vs "
                  f"{chegara:.0f} -> {yonalish}")
        else:
            sanoq = d.tree_.value[tugun][0]
            print(f"  barg {tugun}: sinf ulushlari {sanoq.round(3)}, "
                  f"bashorat {int(np.argmax(sanoq))}")
    print("  ⭐ Har bashorat uchun to'liq tushuntirish mavjud")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Ma'lumot ===
  4000 ariza, xavfli ulush 27.45%

=== 2. Kichik daraxt (max_depth=3) ===
  |--- kechikish <= 0
  |   |--- yosh <= 40
  |   |   |--- muddat <= 8
  |   |   |   |--- class: 0
  |   |   |--- muddat >  8
  |   |   |   |--- class: 0
  |   |--- yosh >  40
  |   |   |--- muddat <= 40
  |   |   |   |--- class: 0
  |   |   |--- muddat >  40
  |   |   |   |--- class: 0
  |--- kechikish >  0
  |   |--- daromad <= 2510131
  |   |   |--- daromad <= 1669333
  |   |   |   |--- class: 1
  |   |   |--- daromad >  1669333
  |   |   |   |--- class: 1
  |   |--- daromad >  2510131
  |   |   |--- kechikish <= 2
  |   |   |   |--- class: 0
  |   |   |--- kechikish >  2
  |   |   |   |--- class: 0

=== 3. Daraxt o'lchami ===
  chuqurlik 3, barglar 8, tugunlar 15
  o'quv aniqligi 0.8598

=== 4. Bitta arizaning yo'li ===
  tugun 0: kechikish = 0 vs 0 -> chap (<=)
  tugun 1: yosh = 44 vs 40 -> o'ng (>)
  tugun 5: muddat = 18 vs 40 -> chap (<=)
  barg 6: sinf ulushlari [0.927 0.073], bashorat 0
  ⭐ Har bashorat uchun to'liq tushuntirish mavjud

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

Misol 3 — Induktiv siljish: o'qlarga parallel chegaralar

python
"""Daraxt qanday shakllarni oson, qaysilarini qiyin topadi (real numpy/sklearn)."""

import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeClassifier


def yarat(tur: str, seed: int = 5, n: int = 2000):
    rng = np.random.default_rng(seed)
    X = rng.uniform(-3, 3, (n, 2))
    if tur == "oq bo'yicha":
        y = ((X[:, 0] > 0.5) & (X[:, 1] < 1.0)).astype(int)
    elif tur == "diagonal":
        y = (X[:, 0] + X[:, 1] > 0).astype(int)
    else:                                    # "doira"
        y = (X[:, 0] ** 2 + X[:, 1] ** 2 < 4.0).astype(int)
    alm = rng.random(n) < 0.03
    y[alm] = 1 - y[alm]
    return X, y


def main() -> None:
    cv = StratifiedKFold(5, shuffle=True, random_state=0)

    print("=== 1. Uch shakl uchun CV aniqligi ===")
    print(f"  {'shakl':<13} {'daraxt(4)':>11} {'daraxt(10)':>12} {'LogReg':>9}")
    for tur in ["oq bo'yicha", "diagonal", "doira"]:
        X, y = yarat(tur)
        d4 = cross_val_score(DecisionTreeClassifier(max_depth=4, random_state=0),
                             X, y, cv=cv).mean()
        d10 = cross_val_score(DecisionTreeClassifier(max_depth=10,
                                                     min_samples_leaf=10,
                                                     random_state=0),
                              X, y, cv=cv).mean()
        lr = cross_val_score(Pipeline([("sc", StandardScaler()),
                                       ("m", LogisticRegression(max_iter=2000))]),
                             X, y, cv=cv).mean()
        print(f"  {tur:<13} {d4:>11.4f} {d10:>12.4f} {lr:>9.4f}")

    print("\n=== 2. Diagonal chegara uchun nechta barg kerak ===")
    X, y = yarat("diagonal")
    for chuqurlik in [2, 4, 6, 8, 12]:
        d = DecisionTreeClassifier(max_depth=chuqurlik, random_state=0).fit(X, y)
        b = cross_val_score(DecisionTreeClassifier(max_depth=chuqurlik,
                                                   random_state=0),
                            X, y, cv=cv).mean()
        print(f"  chuqurlik {chuqurlik:>2}: {d.get_n_leaves():>4} barg, "
              f"CV {b:.4f}")
    print("  (diagonal chiziq zinapoya bilan taqriblanadi)")

    print("\n=== 3. Masshtablash daraxtga ta'sir qiladimi ===")
    X, y = yarat("oq bo'yicha")
    X2 = X.copy()
    X2[:, 0] *= 1000
    d1 = DecisionTreeClassifier(max_depth=5, random_state=0).fit(X, y)
    d2 = DecisionTreeClassifier(max_depth=5, random_state=0).fit(X2, y)
    print(f"  asl:        {d1.get_n_leaves()} barg, o'quv aniqligi "
          f"{d1.score(X, y):.4f}")
    print(f"  1000x:      {d2.get_n_leaves()} barg, o'quv aniqligi "
          f"{d2.score(X2, y):.4f}")
    print(f"  bashoratlar bir xil: {np.array_equal(d1.predict(X), d2.predict(X2))}")

    print("\n=== 4. Monoton transformatsiya ===")
    X3 = X.copy()
    X3[:, 0] = np.exp(X3[:, 0])                 # monoton o'suvchi
    d3 = DecisionTreeClassifier(max_depth=5, random_state=0).fit(X3, y)
    print(f"  exp(x1) bilan: {d3.get_n_leaves()} barg, "
          f"bashoratlar bir xil: {np.array_equal(d1.predict(X), d3.predict(X3))}")
    print("  ⭐ Daraxt tartibga qaraydi, qiymatga emas")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Uch shakl uchun CV aniqligi ===
  shakl           daraxt(4)   daraxt(10)    LogReg
  oq bo'yicha        0.9655       0.9665    0.8830
  diagonal           0.9160       0.9345    0.9655
  doira              0.9040       0.9340    0.6380

=== 2. Diagonal chegara uchun nechta barg kerak ===
  chuqurlik  2:    4 barg, CV 0.8320
  chuqurlik  4:   16 barg, CV 0.9160
  chuqurlik  6:   56 barg, CV 0.9360
  chuqurlik  8:  108 barg, CV 0.9315
  chuqurlik 12:  143 barg, CV 0.9250
  (diagonal chiziq zinapoya bilan taqriblanadi)

=== 3. Masshtablash daraxtga ta'sir qiladimi ===
  asl:        22 barg, o'quv aniqligi 0.9735
  1000x:      22 barg, o'quv aniqligi 0.9735
  bashoratlar bir xil: True

=== 4. Monoton transformatsiya ===
  exp(x1) bilan: 22 barg, bashoratlar bir xil: True
  ⭐ Daraxt tartibga qaraydi, qiymatga emas

Nima ko'rsatdi: 2.5-bo'lim.

Misol 4 — Regressiya daraxti va ekstrapolyatsiya

python
"""Bo'lakli doimiy bashorat va uning cheklovi (real numpy/sklearn)."""

import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error
from sklearn.tree import DecisionTreeRegressor


def main() -> None:
    rng = np.random.default_rng(9)
    n = 600
    x = rng.uniform(0, 10, n)
    y = 3 + 1.8 * x + 4 * np.sin(x) + rng.normal(0, 1.0, n)
    X = x.reshape(-1, 1)

    print("=== 1. Daraxt va chiziqli model (o'quv diapazoni) ===")
    ichki_x = np.linspace(0.5, 9.5, 300).reshape(-1, 1)
    ichki_y = 3 + 1.8 * ichki_x[:, 0] + 4 * np.sin(ichki_x[:, 0])
    modellar = {
        "daraxt(3)": DecisionTreeRegressor(max_depth=3, random_state=0),
        "daraxt(6)": DecisionTreeRegressor(max_depth=6, random_state=0),
        "chiziqli": LinearRegression(),
    }
    for nom, m in modellar.items():
        m.fit(X, y)
        print(f"  {nom:<10}: ichki MAE "
              f"{mean_absolute_error(ichki_y, m.predict(ichki_x)):.3f}")

    print("\n=== 2. Bo'lakli doimiy bashorat ===")
    d = DecisionTreeRegressor(max_depth=3, random_state=0).fit(X, y)
    sinov = np.array([[1.0], [1.5], [2.0], [2.5], [3.0]])
    print(f"  x qiymatlari: {sinov[:, 0]}")
    print(f"  bashoratlar:  {d.predict(sinov).round(3)}")
    print(f"  (bir bargdagi nuqtalar BIR XIL bashorat oladi)")
    print(f"  barglar soni: {d.get_n_leaves()}, "
          f"noyob bashoratlar: {len(np.unique(d.predict(X)))}")

    print("\n=== 3. Ekstrapolyatsiya ===")
    tash = np.array([[10.5], [12.0], [15.0], [30.0]])
    haqiqiy = 3 + 1.8 * tash[:, 0] + 4 * np.sin(tash[:, 0])
    for nom, m in modellar.items():
        print(f"  {nom:<10}: {m.predict(tash).round(1)}")
    print(f"  haqiqiy:    {haqiqiy.round(1)}")
    print("  (daraxt eng chekka bargning qiymatida QOTIB QOLADI)")

    print("\n=== 4. Trend bo'lsa nima qilish kerak ===")
    # trendni chiziqli model bilan, qoldiqni daraxt bilan
    chiziqli = LinearRegression().fit(X, y)
    qoldiq = y - chiziqli.predict(X)
    qoldiq_daraxt = DecisionTreeRegressor(max_depth=4,
                                          random_state=0).fit(X, qoldiq)
    birlashgan_tash = chiziqli.predict(tash) + qoldiq_daraxt.predict(tash)
    print(f"  chiziqli + daraxt(qoldiq): {birlashgan_tash.round(1)}")
    print(f"  haqiqiy:                   {haqiqiy.round(1)}")
    ichki_birlashgan = chiziqli.predict(ichki_x) + qoldiq_daraxt.predict(ichki_x)
    print(f"  ichki MAE: {mean_absolute_error(ichki_y, ichki_birlashgan):.3f}")
    print("  ⭐ Trend chiziqli modelga, qoldiq daraxtga")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Daraxt va chiziqli model (o'quv diapazoni) ===
  daraxt(3) : ichki MAE 0.839
  daraxt(6) : ichki MAE 0.339
  chiziqli  : ichki MAE 2.426

=== 2. Bo'lakli doimiy bashorat ===
  x qiymatlari: [1.  1.5 2.  2.5 3. ]
  bashoratlar:  [8.53 8.53 8.53 8.53 8.53]
  (bir bargdagi nuqtalar BIR XIL bashorat oladi)
  barglar soni: 8, noyob bashoratlar: 8

=== 3. Ekstrapolyatsiya ===
  daraxt(3) : [19.6 19.6 19.6 19.6]
  daraxt(6) : [19.7 19.7 19.7 19.7]
  chiziqli  : [22.8 25.5 30.9 58. ]
  haqiqiy:    [18.4 22.5 32.6 53. ]
  (daraxt eng chekka bargning qiymatida QOTIB QOLADI)

=== 4. Trend bo'lsa nima qilish kerak ===
  chiziqli + daraxt(qoldiq): [20.1 22.9 28.3 55.4]
  haqiqiy:                   [18.4 22.5 32.6 53. ]
  ichki MAE: 0.467
  ⭐ Trend chiziqli modelga, qoldiq daraxtga

Nima ko'rsatdi: 2.4-bo'lim.


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

Noto'g'ri fikr To'g'risi
"Daraxt eng yaxshi bo'linishni topadi" Ochko'z, mahalliy optimal
"Gini va entropiya katta farq qiladi" Farq 1-2%
"Daraxtni masshtablash kerak" Kerak emas
"log(x) daraxtga yordam beradi" Natija o'zgarmaydi
"Daraxt ekstrapolyatsiya qiladi" Yo'q, qotib qoladi
"Chuqur daraxt tushunarli" 50 barg — tushunarsiz
"Daraxt barqaror" Ma'lumot o'zgarsa tuzilma o'zgaradi
"Bitta daraxt yetarli" Ansambl ancha kuchli

6. Keng tarqalgan xatolar va yechimlari

1. Chuqurlikni cheklamaslik

python
DecisionTreeClassifier().fit(X, y)     # o'quvda 100%             # ⚠️
DecisionTreeClassifier(max_depth=5, min_samples_leaf=20)          # ✅

2. random_state yo'q

python
DecisionTreeClassifier(max_depth=4)    # takrorlanmaydi           # ⚠️
DecisionTreeClassifier(max_depth=4, random_state=0)               # ✅

3. criterion ni sozlashga vaqt sarflash

python
GridSearchCV(d, {"criterion": ["gini", "entropy"]})               # ⚠️
GridSearchCV(d, {"max_depth": [3, 5, 8], "min_samples_leaf": [5, 20]}) # ✅

4. Daraxtdan ekstrapolyatsiya kutish

python
daraxt.predict([[kelajakdagi_sana]])                              # ⚠️
# trendni chiziqli model bilan, qoldiqni daraxt bilan             # ✅

5. Chuqur daraxtni "talqin qilinadigan" deb hisoblash

python
# 200 bargli daraxtni hisobotga qo'yish                           # ⚠️
# max_depth=3-4 (talqin uchun) yoki ansambl + SHAP (aniqlik uchun) # ✅

6. Bitta daraxtga tayanish

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

7. Keraksiz masshtablash

python
Pipeline([("sc", StandardScaler()), ("m", DecisionTreeClassifier())]) # ⚠️
DecisionTreeClassifier(max_depth=5, random_state=0)               # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 14.7-dars (o'tilgan): Qaror chegaralari
  • 15.2-dars: O'sish va to'xtash shartlari
  • 15.4-15.5-darslar: Bagging va Random Forest
  • 15.8-dars: Gradient boosting
  • 15.11-dars: Belgi muhimligi

8. Eng yaxshi amaliyotlar

  1. Chuqurlikni cheklang.

  2. random_state qo'ying.

  3. criterion ni sozlamang.

  4. Masshtablamang (keraksiz).

  5. Talqin uchun kichik daraxt oling.

  6. Aniqlik uchun ansamblga o'ting.

  7. Ekstrapolyatsiyani tekshiring.

  8. export_text bilan ko'rib chiqing.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # daraxt tuzilishi elementlari?
2.  # barg bashorati qanday?
3.  # Gini formulasi?
4.  # entropiya formulasi?
5.  # bo'linish qanday tanlanadi?
6.  # ochko'z nima degani?
7.  # Gini va entropiya farqi?
8.  # regressiyada barg nima qaytaradi?
9.  # daraxt ekstrapolyatsiya qiladimi?
10. # chegara shakli?
11. # masshtablash kerakmi?
12. # log(x) natijani o'zgartiradimi?
Javoblar
  1. Ildiz, tugun, barg
  2. Ko'pchilik sinf (yoki o'rtacha)
  3. 1 - sum(p^2)
  4. -sum(p*log2 p)
  5. Nopoklik kamayishi eng katta
  6. Mahalliy eng yaxshi, global emas
  7. Deyarli yo'q (1-2%)
  8. O'rtacha (yoki mediana)
  9. Yo'q
  10. O'qlarga parallel to'rtburchak
  11. Yo'q
  12. Yo'q (monoton)

Vazifa 2: Xatolarni tuzating

python
1.  DecisionTreeClassifier().fit(X, y)

2.  DecisionTreeClassifier(max_depth=4)   # takrorlanmaydi

3.  GridSearchCV(d, {"criterion": ["gini", "entropy"]})

4.  Pipeline([("sc", StandardScaler()), ("m", DecisionTreeClassifier())])

5.  daraxt.predict([[2027]])   # o'quvda 2020-2024
Javoblar
python
1.  DecisionTreeClassifier(max_depth=5, min_samples_leaf=20, random_state=0)

2.  DecisionTreeClassifier(max_depth=4, random_state=0)

3.  GridSearchCV(d, {"max_depth": [3, 5, 8]})

4.  DecisionTreeClassifier(max_depth=5, random_state=0)

5.  # trendni chiziqli model bilan modellang

Vazifa 3: Bo'linish

Modellang:

  1. Gini va entropiya
  2. Chegaralar bo'yicha kamayish
  3. sklearn bilan tekshirish
  4. Ikki kriteriy

Vazifa 4: Daraxtni o'qish

Modellang:

  1. Kichik daraxt
  2. export_text
  3. Bitta yo'l
  4. Xulosa

Vazifa 5: Induktiv siljish

Modellang:

  1. Uch shakl
  2. Diagonal chegara
  3. Masshtab
  4. Monoton transformatsiya

Vazifa 6: Regressiya daraxti

Modellang:

  1. Bo'lakli doimiy
  2. Ekstrapolyatsiya
  3. Trend muammosi
  4. Gibrid yechim

Vazifa 7: O'ylash

Qaror daraxti "talqin qilinadigan model" sifatida targ'ib qilinadi va shu sababli tibbiyot va moliyada afzal ko'riladi. Lekin bu da'vo qanchalik asosli?

Javob

Qisqa javob: kichik daraxt (3-4 daraja) haqiqatan tushunarli, lekin u kamdan-kam aniq. Aniq bo'lgan daraxt (20+ daraja, yuzlab barg) esa amalda qora quti — undan ma'no chiqarish chiziqli model koeffitsiyentlaridan ham qiyin.

1. Talqin qilinishning ikki darajasi

Daraja Daraxt
Bitta bashorat (lokal) Yaxshi — aniq yo'l bor
Butun model (global) Faqat kichik daraxtda

2. Yashirin muammo: beqarorlik

  • Ma'lumotning 5% i o'zgarsa, daraxt tuzilmasi butunlay o'zgarishi mumkin
  • Ikki teng sifatli bo'linishdan biri tasodifiy tanlanadi
  • "Bu qoida muhim" degan xulosa takrorlanmaydi
  • Shuning uchun daraxt tuzilmasini bilim sifatida e'lon qilish xavfli

3. Amaliy yondashuv

  1. Talqin uchun: max_depth=3-4, min_samples_leaf katta
  2. Barqarorlikni tekshirish: bir nechta bootstrap namunada daraxt qurib, tuzilmani solishtirish
  3. Aniqlik uchun: ansambl + SHAP/permutation (15.11)
  4. Qoidalar kerak bo'lsa: daraxtdan qoida chiqarib, ularni alohida tasdiqlash

4. Muqobil talqin vositalari

  • Chiziqli model koeffitsiyentlari 13.3-bob — barqarorroq
  • Monotonlik cheklovlari bilan boosting
  • Qoidalar ro'yxati (RuleFit, skope-rules)

5. Xulosa

  1. Talqin qilinish — daraxt chuqurligiga bog'liq
  2. Kichik daraxt tushunarli, lekin kuchsiz
  3. Beqarorlik talqinni shubha ostiga qo'yadi
  4. Lokal tushuntirish (yo'l) — eng ishonchli qism

Nimani mustahkamlaydi: 2.1, 2.7-bo'limlar.


Xulosa

Bu darsda qaror daraxtini o'rgandik.

Eng muhim uch fikr:

  1. Bo'linish — nopoklik kamayishi. Har tugunda barcha belgi va chegaralar sinaladi va eng katta nopoklik kamayishi beradigani tanlanadi (Gini = 1 - sum(p^2) yoki entropiya = -sum(p*log2 p) — farqi 1-2%). Algoritm ochko'z: mahalliy eng yaxshi bo'linish tanlanadi, global optimal daraxt izlanmaydi.

  2. Chegara o'qlarga parallel. Bu induktiv siljish ikki muhim oqibatga ega: masshtablash kerak emas va monoton transformatsiyalar (log, exp) natijani umuman o'zgartirmaydi — daraxt qiymatga emas, tartibga qaraydi. Diagonal chegaralarni esa u zinapoya bilan taqriblaydi (ko'p barg talab qiladi).

  3. Ekstrapolyatsiya yo'q. Regressiya daraxti barglarda o'rtachani qaytaradi, shuning uchun o'quv diapazonidan tashqarida eng chekka bargning qiymatida qotib qoladi — trendli ma'lumotda bu jiddiy cheklov (yechim: trendni chiziqli model bilan, qoldiqni daraxt bilan). Bitta daraxt kuchsiz va beqaror; uning asosiy qiymati — ansambllar uchun qurilish bloki bo'lishi.

Keyingi darsda daraxt o'sishi va to'xtash shartlarini o'rganamiz: chuqurlik, minimal namunalar, pruning va overfitting nazorati.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
15.1-dars: Qaror daraxti — IlmHamroh