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

15.11-dars: Belgi muhimligi

15-QISM — DARAXTLAR VA ANSAMBLLAR · 11-dars


1. Kirish va motivatsiya

model.feature_importances_ — ansambl bilan ishlashda eng ko'p ishlatiladigan va eng ko'p noto'g'ri talqin qilinadigan atribut. U chiroyli diagramma beradi, hisobotga oson kiradi va ko'pincha aldaydi.

Uch muammo bor: (1) u kardinallikka moyil — ko'p noyob qiymatli belgilar sun'iy yuqori ball oladi; (2) u korrelyatsiyali belgilar orasida muhimlikni tasodifiy taqsimlaydi; (3) u o'quv ma'lumotida hisoblanadi, ya'ni overfitting ni aks ettiradi.

Bu darsda: nopoklikka asoslangan muhimlik (MDI) va uning tuzoqlari, permutation importance, drop-column usuli, SHAP qiymatlari, korrelyatsiyali belgilar bilan ishlash va muhimlikni sababiylik bilan adashtirmaslik.

Real vaziyat. Kredit modelida feature_importances_ bo'yicha eng muhim belgi "mijoz ID raqami" chiqdi. ID tasodifiy son edi va hech qanday ma'no tashimasdi — lekin u noyob bo'lgani uchun daraxt undan cheksiz bo'linish topa olardi. Permutation importance shu belgining muhimligini 0 ko'rsatdi.

Bu darsda belgi muhimligini o'rganamiz.

Bu darsda:

  • MDI va uning tuzoqlari
  • Permutation importance
  • Drop-column
  • SHAP qiymatlari
  • Korrelyatsiyali belgilar
  • Sababiylik emas
  • Tuzoqlar
  • Amaliy: to'liq tahlil

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


2. Nazariya — chuqur tushuntirish

2.1. MDI va uning tuzoqlari

text
MDI (Mean Decrease in Impurity) = feature_importances_

  har belgi uchun: u bergan nopoklik kamayishlarining
  og'irlikli yig'indisi (barcha daraxtlar bo'yicha)

UCH TUZOQ:
  1. KARDINALLIK moyilligi — ko'p noyob qiymatli belgi ustun
     (ID, vaqt belgisi, uzluksiz belgi > kategoriya)
  2. O'QUV ma'lumotida hisoblanadi — overfitting aks etadi
  3. KORRELYATSIYALI belgilar orasida tasodifiy taqsimlanadi

sklearn hujjati ham ogohlantiradi: permutation importance ni tavsiya qiladi

Kardinallik moyilligi eng xavfli tuzoq: tasodifiy uzluksiz belgi (yoki ID) daraxtda ko'p bo'linish imkonini beradi va shuning uchun MDI yuqori chiqadi — garchi u hech qanday bashorat kuchiga ega bo'lmasa ham.

2.2. Permutation importance

text
G'oya: belgini ARALASHTIRSAK, sifat qanchaga tushadi?

  1. Asosiy ball hisoblanadi (validatsiya/test to'plamida)
  2. Bitta belgi ustuni tasodifiy aralashtiriladi
  3. Ball qayta hisoblanadi
  4. muhimlik = asosiy - aralashtirilgan
  5. n_repeats marta takrorlanadi -> o'rtacha va std

sklearn:
  from sklearn.inspection import permutation_importance
  r = permutation_importance(model, Xte, yte, n_repeats=20,
                             scoring="roc_auc", random_state=0)
  r.importances_mean, r.importances_std

Permutation importance ni albatta test yoki validatsiya to'plamida hisoblang. O'quv to'plamida u MDI bilan bir xil muammoga uchraydi: model o'quv ma'lumotini yodlagan bo'lsa, har belgi "muhim" ko'rinadi.

2.3. Drop-column

text
Eng halol, lekin eng qimmat usul:

  har belgi uchun: uni OLIB TASHLAB, modelni QAYTA o'qitish
  muhimlik = to'liq model balli - belgisiz model balli

  + haqiqiy hissani o'lchaydi
  - p ta qayta o'qitish kerak
  - korrelyatsiyali belgilarda ikkalasi ham "muhimsiz" chiqadi

Amalda: faqat kam belgili yoki muhim qarorlarda

Korrelyatsiyali belgilarda barcha uch usul ham muammoga uchraydi: drop-column da bir belgi olib tashlansa, ikkinchisi uning o'rnini bosadi va ball tushmaydi — ya'ni ikkalasi ham "muhimsiz" ko'rinadi.

2.4. SHAP qiymatlari

text
SHAP (SHapley Additive exPlanations) — o'yin nazariyasidan

  har BASHORAT uchun har belgining hissasi:
    f(x) = asosiy_qiymat + sum(shap_qiymat_i)

  + lokal (bitta bashorat) va global (o'rtacha |SHAP|) tushuntirish
  + daraxtlar uchun aniq va tez algoritm (TreeSHAP)
  + yo'nalish ko'rinadi (musbat/manfiy ta'sir)
  - alohida kutubxona (shap)
  - korrelyatsiyali belgilarda talqin murakkab

sklearn muqobili: partial_dependence, PartialDependenceDisplay

SHAP ning asosiy afzalligi — lokal tushuntirish: "nega aynan bu mijozga rad javobi berildi?" degan savolga son bilan javob beradi. Bu moliyaviy va tibbiy qo'llanmalarda ko'pincha huquqiy talab.

2.5. Korrelyatsiyali belgilar

text
Muammo: a va b korrelyatsiyasi 0.95
  MDI: muhimlik ikkiga bo'linadi (ikkalasi ham "o'rtacha")
  Permutation: a ni aralashtirsak, model b dan foydalanadi
               -> ikkalasi ham "muhimsiz" chiqadi

YECHIMLAR:
  1. Ierarxik klasterlash bilan guruhlash, guruhni birga aralashtirish
  2. Korrelyatsiyali guruhdan bittasini qoldirish
  3. Guruh darajasida muhimlik hisoblash
  4. Conditional permutation importance

sklearn misoli: scipy.cluster.hierarchy bilan Spearman asosida

Guruh bo'yicha aralashtirish — eng amaliy yechim: korrelyatsiyali belgilarni klasterlarga ajratib, klasterni birgalikda aralashtirasiz. Shunda guruhning haqiqiy hissasi ko'rinadi.

2.6. Sababiylik emas

text
Muhimlik BASHORAT uchun foydalilikni o'lchaydi, SABABNI emas

Misol: "kasalxonada yotgan kunlar soni" o'lim ehtimolini yaxshi bashorat qiladi
  -> lekin kunlarni kamaytirish o'limni kamaytirmaydi

Sababiy xulosa uchun kerak:
  - eksperiment (A/B test)
  - sababiy modellar (DAG, instrumental o'zgaruvchilar)
  - domen bilimi

"Bu belgi muhim -> uni o'zgartiraylik" - ENG KENG TARQALGAN XATO

Bu — eng muhim ogohlantirish: muhimlik diagrammasi asosida biznes qarori qabul qilish (masalan "bu ko'rsatkichni oshiramiz") sababiylikni nazarda tutadi, model esa uni bermaydi.

2.7. Tuzoqlar

Asosiy tuzoqlar: feature_importances_ ni hisobotga to'g'ridan-to'g'ri qo'yish; permutation ni o'quv to'plamida hisoblash; n_repeats ni juda kichik qo'yish; korrelyatsiyali belgilarni tekshirmaslik; muhimlikni sababiy talqin qilish; ID/vaqt belgilarini modelda qoldirish; muhimlikka qarab belgi tanlashda (feature selection) leakage qilish; turli usullar bir xil javob berishini kutish.

2.8. Qaysi usulni qachon

feature_importances_ (MDI) tez, lekin kardinallikka moyil, o'quv ma'lumotida hisoblanadi va korrelyatsiyada chalg'itadi. Permutation importance ni test to'plamida hisoblang — u ancha ishonchli. Drop-column eng halol, lekin qimmat. SHAP lokal tushuntirish beradi. Korrelyatsiyali belgilarni guruhlab aralashtiring. Va eng muhimi: muhimlik — bashorat foydaliligi, sababiylik emas. Keyingi dars — ansambllarni solishtirish.


3. Tez ma'lumotnoma

python
from sklearn.inspection import permutation_importance, partial_dependence

model.feature_importances_             # MDI - ehtiyot bo'ling

r = permutation_importance(model, Xte, yte, n_repeats=20,
                           scoring="roc_auc", random_state=0, n_jobs=-1)
tartib = np.argsort(-r.importances_mean)
for i in tartib[:10]:
    print(nomlar[i], r.importances_mean[i], r.importances_std[i])

# korrelyatsiyali guruhlar
from scipy.cluster.hierarchy import fcluster, linkage
from scipy.stats import spearmanr
korr = spearmanr(X).correlation
guruh = fcluster(linkage(1 - np.abs(korr), "average"), 0.3, "distance")
QOIDA: permutation ni TEST da · guruhlab aralashtir ·
       sababiy talqin qilma

Muhimlik xulosasi

MDI: tez, kardinallikka moyil, o'quvda, korrelyatsiyada chalg'itadi
Permutation: test da hisobla, n_repeats >= 10
Drop-column: eng halol, p ta qayta o'qitish
SHAP: lokal + global, yo'nalish ko'rinadi
Muhimlik != sababiylik

4. Batafsil misollar

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

Misol 1 — MDI ning kardinallik tuzog'i

python
"""Tasodifiy ID nega "eng muhim" chiqadi (real numpy/pandas/sklearn)."""

import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.inspection import permutation_importance
from sklearn.model_selection import train_test_split


def yarat(seed: int = 5, n: int = 4000) -> pd.DataFrame:
    rng = np.random.default_rng(seed)
    haqiqiy1 = rng.normal(0, 1, n)
    haqiqiy2 = rng.normal(0, 1, n)
    ikkilik = rng.integers(0, 2, n).astype(float)        # 2 daraja
    uch_daraja = rng.integers(0, 3, n).astype(float)     # 3 daraja
    tasodifiy_id = rng.permutation(n).astype(float)      # n daraja, ma'nosiz
    tasodifiy_son = rng.normal(0, 1, n)                  # uzluksiz, ma'nosiz
    kuch = 1.5 * haqiqiy1 - 1.2 * haqiqiy2 + 0.8 * ikkilik
    y = (rng.random(n) < 1 / (1 + np.exp(-kuch))).astype(int)
    return pd.DataFrame({"haqiqiy1": haqiqiy1, "haqiqiy2": haqiqiy2,
                         "ikkilik": ikkilik, "uch_daraja": uch_daraja,
                         "tasodifiy_id": tasodifiy_id,
                         "tasodifiy_son": tasodifiy_son, "y": y})


def main() -> None:
    df = yarat()
    nomlar = [c for c in df.columns if c != "y"]
    X, y = df[nomlar], df["y"]
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=0,
                                          stratify=y)
    o = RandomForestClassifier(n_estimators=300, random_state=0,
                               n_jobs=1).fit(Xtr, ytr)

    print("=== 1. Belgilarning noyob qiymatlari ===")
    for nom in nomlar:
        print(f"  {nom:<15}: {X[nom].nunique():>5} noyob qiymat")

    print("\n=== 2. MDI (feature_importances_) ===")
    mdi = o.feature_importances_
    for i in np.argsort(-mdi):
        print(f"  {nomlar[i]:<15}: {mdi[i]:.4f}")
    print(f"  (haqiqiy signal faqat: haqiqiy1, haqiqiy2, ikkilik)")

    print("\n=== 3. Permutation importance (test to'plamida) ===")
    r = permutation_importance(o, Xte, yte, n_repeats=20, scoring="roc_auc",
                               random_state=0, n_jobs=1)
    for i in np.argsort(-r.importances_mean):
        print(f"  {nomlar[i]:<15}: {r.importances_mean[i]:>+8.4f} "
              f"(std {r.importances_std[i]:.4f})")

    print("\n=== 4. Permutation: o'quv va test farqi ===")
    r_tr = permutation_importance(o, Xtr, ytr, n_repeats=10,
                                  scoring="roc_auc", random_state=0, n_jobs=1)
    print(f"  {'belgi':<15} {'MDI':>8} {'perm(o_quv)':>13} "
          f"{'perm(test)':>12}")
    for i in range(len(nomlar)):
        print(f"  {nomlar[i]:<15} {mdi[i]:>8.4f} "
              f"{r_tr.importances_mean[i]:>+13.4f} "
              f"{r.importances_mean[i]:>+12.4f}")
    print("  ⭐ MDI ma'nosiz belgini yuqori baholaydi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Belgilarning noyob qiymatlari ===
  haqiqiy1       :  4000 noyob qiymat
  haqiqiy2       :  4000 noyob qiymat
  ikkilik        :     2 noyob qiymat
  uch_daraja     :     3 noyob qiymat
  tasodifiy_id   :  4000 noyob qiymat
  tasodifiy_son  :  4000 noyob qiymat

=== 2. MDI (feature_importances_) ===
  haqiqiy1       : 0.3624
  haqiqiy2       : 0.2930
  tasodifiy_id   : 0.1498
  tasodifiy_son  : 0.1460
  uch_daraja     : 0.0302
  ikkilik        : 0.0186
  (haqiqiy signal faqat: haqiqiy1, haqiqiy2, ikkilik)

=== 3. Permutation importance (test to'plamida) ===
  haqiqiy1       :  +0.2055 (std 0.0146)
  haqiqiy2       :  +0.1301 (std 0.0105)
  ikkilik        :  +0.0092 (std 0.0028)
  tasodifiy_son  :  +0.0030 (std 0.0022)
  uch_daraja     :  +0.0005 (std 0.0018)
  tasodifiy_id   :  -0.0021 (std 0.0028)

=== 4. Permutation: o'quv va test farqi ===
  belgi                MDI   perm(o_quv)   perm(test)
  haqiqiy1          0.3624       +0.2792      +0.2055
  haqiqiy2          0.2930       +0.2110      +0.1301
  ikkilik           0.0186       +0.0291      +0.0092
  uch_daraja        0.0302       +0.0048      +0.0005
  tasodifiy_id      0.1498       +0.0285      -0.0021
  tasodifiy_son     0.1460       +0.0231      +0.0030
  ⭐ MDI ma'nosiz belgini yuqori baholaydi

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

Misol 2 — Korrelyatsiyali belgilar

python
"""Muhimlik nega "yo'qoladi" va uni qanday tiklash (real numpy/scipy/sklearn)."""

import numpy as np
from scipy.cluster.hierarchy import fcluster, linkage
from scipy.spatial.distance import squareform
from scipy.stats import spearmanr
from sklearn.ensemble import RandomForestClassifier
from sklearn.inspection import permutation_importance
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split


def yarat(seed: int = 8, n: int = 4000):
    rng = np.random.default_rng(seed)
    asos = rng.normal(0, 1, n)
    # uchta korrelyatsiyali nusxa
    a1 = asos + rng.normal(0, 0.25, n)
    a2 = asos + rng.normal(0, 0.25, n)
    a3 = asos + rng.normal(0, 0.25, n)
    mustaqil = rng.normal(0, 1, n)
    shovqin = rng.normal(0, 1, (n, 3))
    X = np.column_stack([a1, a2, a3, mustaqil, shovqin])
    kuch = 1.6 * asos + 1.2 * mustaqil
    y = (rng.random(n) < 1 / (1 + np.exp(-kuch))).astype(int)
    nomlar = ["nusxa1", "nusxa2", "nusxa3", "mustaqil", "shovqin1",
              "shovqin2", "shovqin3"]
    return X, y, nomlar


def main() -> None:
    X, y, nomlar = yarat()
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=0,
                                          stratify=y)
    o = RandomForestClassifier(n_estimators=300, random_state=0,
                               n_jobs=1).fit(Xtr, ytr)

    print("=== 1. Korrelyatsiya ===")
    print(f"  nusxa1 - nusxa2: {np.corrcoef(X[:, 0], X[:, 1])[0, 1]:.4f}")
    print(f"  nusxa1 - mustaqil: {np.corrcoef(X[:, 0], X[:, 3])[0, 1]:.4f}")

    print("\n=== 2. MDI va permutation ===")
    mdi = o.feature_importances_
    r = permutation_importance(o, Xte, yte, n_repeats=20, scoring="roc_auc",
                               random_state=0, n_jobs=1)
    print(f"  {'belgi':<12} {'MDI':>8} {'permutation':>13}")
    for i in range(len(nomlar)):
        print(f"  {nomlar[i]:<12} {mdi[i]:>8.4f} "
              f"{r.importances_mean[i]:>+13.4f}")
    print("  (uchta nusxa birgalikda mustaqildan kuchli, lekin alohida past)")

    print("\n=== 3. Ierarxik klasterlash ===")
    korr = spearmanr(X).correlation
    masofa = 1 - np.abs(korr)
    np.fill_diagonal(masofa, 0.0)
    masofa = (masofa + masofa.T) / 2
    Z = linkage(squareform(masofa, checks=False), "average")
    guruhlar = fcluster(Z, 0.3, criterion="distance")
    for g in np.unique(guruhlar):
        azolar = [nomlar[i] for i in range(len(nomlar)) if guruhlar[i] == g]
        print(f"  guruh {g}: {azolar}")

    print("\n=== 4. Guruh bo'yicha aralashtirish ===")
    asosiy = roc_auc_score(yte, o.predict_proba(Xte)[:, 1])
    rng = np.random.default_rng(0)
    print(f"  asosiy AUC: {asosiy:.4f}")
    print(f"  {'guruh':<28} {'muhimlik':>10}")
    for g in np.unique(guruhlar):
        indekslar = [i for i in range(len(nomlar)) if guruhlar[i] == g]
        ballar = []
        for _ in range(15):
            Xa = Xte.copy()
            aralash = rng.permutation(len(Xa))
            Xa[:, indekslar] = Xa[aralash][:, indekslar]   # BIRGA aralashtirish
            ballar.append(roc_auc_score(yte, o.predict_proba(Xa)[:, 1]))
        nom = ",".join(nomlar[i] for i in indekslar)
        print(f"  {nom:<28} {asosiy - np.mean(ballar):>+10.4f}")
    print("  ⭐ Guruhlab aralashtirish haqiqiy hissani ko'rsatadi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Korrelyatsiya ===
  nusxa1 - nusxa2: 0.9445
  nusxa1 - mustaqil: -0.0070

=== 2. MDI va permutation ===
  belgi             MDI   permutation
  nusxa1         0.1753       +0.0476
  nusxa2         0.1575       +0.0224
  nusxa3         0.1739       +0.0233
  mustaqil       0.2170       +0.1210
  shovqin1       0.0938       +0.0000
  shovqin2       0.0924       -0.0010
  shovqin3       0.0901       -0.0008
  (uchta nusxa birgalikda mustaqildan kuchli, lekin alohida past)

=== 3. Ierarxik klasterlash ===
  guruh 1: ['nusxa1', 'nusxa2', 'nusxa3']
  guruh 2: ['shovqin1']
  guruh 3: ['mustaqil']
  guruh 4: ['shovqin3']
  guruh 5: ['shovqin2']

=== 4. Guruh bo'yicha aralashtirish ===
  asosiy AUC: 0.8442
  guruh                          muhimlik
  nusxa1,nusxa2,nusxa3            +0.2476
  shovqin1                        -0.0005
  mustaqil                        +0.1217
  shovqin3                        -0.0004
  shovqin2                        -0.0027
  ⭐ Guruhlab aralashtirish haqiqiy hissani ko'rsatadi

Nima ko'rsatdi: 2.5-bo'lim.

Misol 3 — Drop-column va partial dependence

python
"""Eng halol usul va ta'sir yo'nalishi (real numpy/sklearn)."""

import numpy as np
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.inspection import partial_dependence, permutation_importance
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split


def yarat(seed: int = 13, n: int = 5000):
    rng = np.random.default_rng(seed)
    X = rng.normal(0, 1, (n, 6))
    kuch = (1.5 * X[:, 0] - 1.2 * X[:, 1]
            + 1.0 * ((X[:, 2] > 0.5) & (X[:, 3] > 0))
            + 0.4 * X[:, 4])
    y = (rng.random(n) < 1 / (1 + np.exp(-kuch))).astype(int)
    nomlar = ["kuchli+", "kuchli-", "ozaro_a", "ozaro_b", "zaif", "shovqin"]
    return X, y, nomlar


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

    def oqit(Xa, Xb):
        m = HistGradientBoostingClassifier(learning_rate=0.1, max_iter=300,
                                           early_stopping=True,
                                           validation_fraction=0.15,
                                           n_iter_no_change=20,
                                           random_state=0).fit(Xa, ytr)
        return m, roc_auc_score(yte, m.predict_proba(Xb)[:, 1])

    print("=== 1. To'liq model ===")
    model, toliq = oqit(Xtr, Xte)
    print(f"  test AUC: {toliq:.4f}")

    print("\n=== 2. Drop-column muhimligi ===")
    print(f"  {'olib tashlangan':<18} {'AUC':>9} {'yo_qotish':>11}")
    drop = {}
    for i, nom in enumerate(nomlar):
        qolgan = [j for j in range(len(nomlar)) if j != i]
        _, a = oqit(Xtr[:, qolgan], Xte[:, qolgan])
        drop[nom] = toliq - a
        print(f"  {nom:<18} {a:>9.4f} {toliq - a:>+11.4f}")

    print("\n=== 3. Uch usul yonma-yon ===")
    r = permutation_importance(model, Xte, yte, n_repeats=20,
                               scoring="roc_auc", random_state=0, n_jobs=1)
    print(f"  {'belgi':<12} {'permutation':>13} {'drop-column':>13}")
    for i, nom in enumerate(nomlar):
        print(f"  {nom:<12} {r.importances_mean[i]:>+13.4f} "
              f"{drop[nom]:>+13.4f}")

    print("\n=== 4. Ta'sir yo'nalishi (partial dependence) ===")
    for i in [0, 1, 4]:
        pd_natija = partial_dependence(model, Xte, [i], grid_resolution=5,
                                       kind="average")
        qiymatlar = pd_natija["grid_values"][0]
        ortacha = pd_natija["average"][0]
        print(f"  {nomlar[i]:<10}: x = {np.round(qiymatlar, 2).tolist()}")
        print(f"  {'':<10}  f = {np.round(ortacha, 3).tolist()}")
    print("  ⭐ Muhimlik kattaligini, PD yo'nalishini ko'rsatadi")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. To'liq model ===
  test AUC: 0.8300

=== 2. Drop-column muhimligi ===
  olib tashlangan          AUC   yo_qotish
  kuchli+               0.6880     +0.1420
  kuchli-               0.7632     +0.0668
  ozaro_a               0.8287     +0.0013
  ozaro_b               0.8208     +0.0092
  zaif                  0.8211     +0.0089
  shovqin               0.8349     -0.0049

=== 3. Uch usul yonma-yon ===
  belgi          permutation   drop-column
  kuchli+            +0.1986       +0.1420
  kuchli-            +0.1228       +0.0668
  ozaro_a            +0.0073       +0.0013
  ozaro_b            +0.0108       +0.0092
  zaif               +0.0146       +0.0089
  shovqin            -0.0001       -0.0049

=== 4. Ta'sir yo'nalishi (partial dependence) ===
  kuchli+   : x = [-1.65, -0.82, 0.01, 0.84, 1.67]
              f = [-2.309, -1.149, 0.066, 1.621, 1.819]
  kuchli-   : x = [-1.75, -0.92, -0.09, 0.74, 1.57]
              f = [1.906, 1.247, 0.097, -0.694, -2.284]
  zaif      : x = [-1.62, -0.8, 0.01, 0.83, 1.65]
              f = [-0.358, -0.175, 0.094, 0.486, 0.586]
  ⭐ Muhimlik kattaligini, PD yo'nalishini ko'rsatadi

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

Misol 4 — Muhimlik sababiylik emas

python
"""Bashorat kuchi va sababiy ta'sir farqi (real numpy/sklearn)."""

import numpy as np
from sklearn.ensemble import RandomForestRegressor
from sklearn.inspection import permutation_importance
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
from sklearn.model_selection import train_test_split


def yarat(seed: int = 17, n: int = 5000):
    """Sababiy tuzilma: davolash -> tuzalish; kunlar <- og'irlik -> tuzalish."""
    rng = np.random.default_rng(seed)
    ogirlik = rng.normal(0, 1, n)                 # kasallik og'irligi (yashirin)
    davolash = (rng.random(n) < 0.5).astype(float)
    # kunlar og'irlikning NATIJASI, sababi emas
    kunlar = 5 + 3 * ogirlik - 1.0 * davolash + rng.normal(0, 0.8, n)
    tuzalish = (10 - 2.5 * ogirlik + 3.0 * davolash + rng.normal(0, 1.0, n))
    X = np.column_stack([davolash, kunlar, rng.normal(0, 1, (n, 2))])
    nomlar = ["davolash", "kunlar", "shovqin1", "shovqin2"]
    return X, tuzalish, nomlar, ogirlik


def main() -> None:
    X, y, nomlar, ogirlik = yarat()
    Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=0)
    o = RandomForestRegressor(n_estimators=300, max_features=0.5,
                              random_state=0, n_jobs=1).fit(Xtr, ytr)

    print("=== 1. Model sifati ===")
    print(f"  test R^2: {r2_score(yte, o.predict(Xte)):.4f}")

    print("\n=== 2. Muhimlik ===")
    r = permutation_importance(o, Xte, yte, n_repeats=20, scoring="r2",
                               random_state=0, n_jobs=1)
    print(f"  {'belgi':<12} {'MDI':>8} {'permutation':>13}")
    for i in np.argsort(-r.importances_mean):
        print(f"  {nomlar[i]:<12} {o.feature_importances_[i]:>8.4f} "
              f"{r.importances_mean[i]:>+13.4f}")
    print("  (kunlar eng muhim ko'rinadi)")

    print("\n=== 3. Sababiy haqiqat ===")
    print("  Haqiqiy tuzilma:")
    print("    og'irlik -> kunlar      (og'irlik kunlarni oshiradi)")
    print("    og'irlik -> tuzalish    (og'irlik tuzalishni kamaytiradi)")
    print("    davolash -> tuzalish    (+3.0)")
    print("    davolash -> kunlar      (-1.0)")
    print("  Ya'ni kunlar tuzalishga TA'SIR QILMAYDI - ikkalasi ham")
    print("  og'irlikning natijasi (umumiy sabab)")

    print("\n=== 4. Aralashuv (intervention) simulyatsiyasi ===")
    # kunlarni sun'iy kamaytirish tuzalishni o'zgartiradimi?
    Xa = Xte.copy()
    Xa[:, 1] -= 2.0                     # "kunlarni 2 ga kamaytiramiz"
    print(f"  model bashorati (kunlar -2): "
          f"{o.predict(Xa).mean():.4f} (asl {o.predict(Xte).mean():.4f})")
    print(f"  model o'zgarish kutmoqda: "
          f"{o.predict(Xa).mean() - o.predict(Xte).mean():+.4f}")
    print("  Lekin haqiqiy mexanizmda kunlar tuzalishga ta'sir qilmaydi:")
    print("  haqiqiy o'zgarish = 0.0000")
    # to'g'ri sababiy baho: og'irlikni nazoratga olish
    Xc = np.column_stack([X[:, 0], ogirlik])
    ch = LinearRegression().fit(Xc, y)
    print(f"  davolashning sababiy ta'siri (og'irlik nazoratda): "
          f"{ch.coef_[0]:+.4f} (haqiqiy +3.0000)")
    chs = LinearRegression().fit(X[:, [0]], y)
    print(f"  og'irliksiz baho: {chs.coef_[0]:+.4f}")
    print("  ⭐ Muhimlik bashorat uchun, sababiylik uchun emas")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Model sifati ===
  test R^2: 0.8349

=== 2. Muhimlik ===
  belgi             MDI   permutation
  kunlar         0.7140       +1.2293
  davolash       0.1749       +0.2539
  shovqin2       0.0559       -0.0006
  shovqin1       0.0552       -0.0038
  (kunlar eng muhim ko'rinadi)

=== 3. Sababiy haqiqat ===
  Haqiqiy tuzilma:
    og'irlik -> kunlar      (og'irlik kunlarni oshiradi)
    og'irlik -> tuzalish    (og'irlik tuzalishni kamaytiradi)
    davolash -> tuzalish    (+3.0)
    davolash -> kunlar      (-1.0)
  Ya'ni kunlar tuzalishga TA'SIR QILMAYDI - ikkalasi ham
  og'irlikning natijasi (umumiy sabab)

=== 4. Aralashuv (intervention) simulyatsiyasi ===
  model bashorati (kunlar -2): 13.0663 (asl 11.5513)
  model o'zgarish kutmoqda: +1.5150
  Lekin haqiqiy mexanizmda kunlar tuzalishga ta'sir qilmaydi:
  haqiqiy o'zgarish = 0.0000
  davolashning sababiy ta'siri (og'irlik nazoratda): +3.0096 (haqiqiy +3.0000)
  og'irliksiz baho: +3.0667
  ⭐ Muhimlik bashorat uchun, sababiylik uchun emas

Nima ko'rsatdi: 2.6-bo'lim.


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

Noto'g'ri fikr To'g'risi
"feature_importances_ ishonchli" Kardinallikka moyil
"MDI va permutation bir xil" Ko'pincha farq qiladi
"Permutation ni o'quvda hisoblash mumkin" Test da
"Korrelyatsiya muhimlikka ta'sir qilmaydi" Kuchli ta'sir
"Muhim belgi — sabab" Faqat bashorat
"Drop-column har doim to'g'ri" Korrelyatsiyada emas
"SHAP sababiylikni beradi" Yo'q
"n_repeats=1 yetarli" 10-30 kerak

6. Keng tarqalgan xatolar va yechimlari

1. MDI ni hisobotga qo'yish

python
plt.barh(nomlar, model.feature_importances_)                      # ⚠️
r = permutation_importance(model, Xte, yte, n_repeats=20)         # ✅

2. O'quvda permutation

python
permutation_importance(model, Xtr, ytr)                           # ⚠️
permutation_importance(model, Xte, yte)                           # ✅

3. Korrelyatsiyani tekshirmaslik

python
# to'g'ridan-to'g'ri muhimlik ro'yxati                            # ⚠️
# avval spearmanr + klasterlash, keyin guruh bo'yicha             # ✅

4. Sababiy talqin

python
# "kunlarni kamaytiramiz - natija yaxshilanadi"                   # ⚠️
# eksperiment yoki sababiy model kerak                            # ✅

5. ID ni modelda qoldirish

python
X = df.drop(columns="target")           # id ham qoldi            # ⚠️
X = df.drop(columns=["target", "mijoz_id"])                       # ✅

6. Kam takrorlash

python
permutation_importance(model, Xte, yte, n_repeats=2)              # ⚠️
permutation_importance(model, Xte, yte, n_repeats=20)             # ✅

7. Muhimlik bo'yicha belgi tanlashda leakage

python
# butun ma'lumotda muhimlik -> belgi tanlash -> CV                # ⚠️
# belgi tanlashni Pipeline ichiga qo'ying 12.9-bob                  # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 15.5-dars (o'tilgan): Random Forest
  • 15.3-dars (o'tilgan): Beqarorlik
  • 13.3-dars (o'tilgan): Koeffitsiyentlarni talqin
  • 15.12-dars: Ansambllarni solishtirish
  • 15.13-dars: Ishlab chiqarish

8. Eng yaxshi amaliyotlar

  1. Permutation ni test da hisoblang.

  2. n_repeats >= 10 qo'ying.

  3. Korrelyatsiyani guruhlang.

  4. MDI ni faqat ichki ko'rikda ishlating.

  5. ID va vaqt belgilarini olib tashlang.

  6. Yo'nalishni PD/SHAP bilan ko'ring.

  7. Sababiy xulosa qilmang.

  8. Bir necha usulni taqqoslang.


9. Amaliy topshiriq

Vazifa 1: Bashorat qiling

python
1.  # MDI to'liq nomi?
2.  # MDI ning birinchi tuzog'i?
3.  # ikkinchisi?
4.  # uchinchisi?
5.  # permutation qanday ishlaydi?
6.  # qaysi to'plamda?
7.  # n_repeats odatiy?
8.  # drop-column kamchiligi?
9.  # SHAP nimadan kelib chiqqan?
10. # korrelyatsiyada yechim?
11. # muhimlik sababiylikmi?
12. # ID ni nima qilish kerak?
Javoblar
  1. Mean Decrease in Impurity
  2. Kardinallik moyilligi
  3. O'quv ma'lumotida
  4. Korrelyatsiyada tasodifiy taqsimlanish
  5. Belgini aralashtirib ball tushishini o'lchaydi
  6. Test / validatsiya
  7. 10-30
  8. p ta qayta o'qitish
  9. O'yin nazariyasi (Shapley)
  10. Guruhlab aralashtirish
  11. Yo'q
  12. Olib tashlash

Vazifa 2: Xatolarni tuzating

python
1.  plt.barh(nomlar, model.feature_importances_)

2.  permutation_importance(model, Xtr, ytr)

3.  permutation_importance(model, Xte, yte, n_repeats=2)

4.  X = df.drop(columns="target")   # mijoz_id qoldi

5.  # "eng muhim belgini o'zgartirsak natija yaxshilanadi"
Javoblar
python
1.  r = permutation_importance(model, Xte, yte, n_repeats=20)

2.  permutation_importance(model, Xte, yte)

3.  permutation_importance(model, Xte, yte, n_repeats=20)

4.  X = df.drop(columns=["target", "mijoz_id"])

5.  # eksperiment yoki sababiy model kerak

Vazifa 3: Kardinallik

Modellang:

  1. Noyob qiymatlar
  2. MDI
  3. Permutation
  4. O'quv va test

Vazifa 4: Korrelyatsiya

Modellang:

  1. Korrelyatsiya
  2. Ikki usul
  3. Klasterlash
  4. Guruh bo'yicha

Vazifa 5: Drop-column

Modellang:

  1. To'liq model
  2. Drop-column
  3. Uch usul
  4. Partial dependence

Vazifa 6: Sababiylik

Modellang:

  1. Model sifati
  2. Muhimlik
  3. Haqiqiy tuzilma
  4. Aralashuv

Vazifa 7: O'ylash

Belgi muhimligi bo'yicha belgilarni tanlash (feature selection) keng tarqalgan amaliyot. Bu qanchalik to'g'ri?

Javob

Qisqa javob: ishlaydi, lekin ikki shart bilan: (1) tanlov CV ichida qilinishi kerak, aks holda leakage bo'ladi; (2) korrelyatsiyali belgilarni guruhlab ko'rish kerak, aks holda muhim guruh butunlay yo'qotiladi.

1. Leakage xavfi

NOTO'G'RI: butun ma'lumotda muhimlik -> 20 ta belgi tanlash -> CV
           CV bahosi OPTIMISTIK (tanlov butun ma'lumotni ko'rgan)

TO'G'RI:   Pipeline([("tanlov", SelectFromModel(...)), ("model", ...)])
           har foldda tanlov QAYTA qilinadi

2. Korrelyatsiya muammosi

  • Uch korrelyatsiyali nusxa: har birining muhimligi past
  • Chegara bo'yicha kesilsa — uchalasi ham olib tashlanadi
  • Natijada muhim signal yo'qoladi
  • Yechim: klasterlash, har guruhdan bittasini qoldirish

3. Qachon belgi tanlash foydali

Maqsad Foyda
Tezlik / xotira Katta
Talqin qilish Katta
Ma'lumot yig'ish narxi Katta
Aniqlik Odatda kichik yoki manfiy

Daraxtlar allaqachon ichki belgi tanlashni bajaradi — shuning uchun ansambl aniqligi kamdan-kam oshadi.

4. Amaliy tartib

  1. Aniq keraksizlarni olib tashlang (ID, konstanta, duplikat)
  2. Korrelyatsiyali guruhlarni aniqlang
  3. Har guruhdan vakil qoldiring
  4. Qolganini SelectFromModel bilan Pipeline ichida
  5. Natijani to'liq model bilan taqqoslang

5. Xulosa

  1. Tanlovni Pipeline ichiga qo'ying
  2. Korrelyatsiyani guruhlab ko'ring
  3. Aniqlik uchun emas, tezlik va talqin uchun
  4. Har doim to'liq model bilan taqqoslang

Nimani mustahkamlaydi: 2.2, 2.5-bo'limlar.


Xulosa

Bu darsda belgi muhimligini o'rgandik.

Eng muhim uch fikr:

  1. feature_importances_ (MDI) aldaydi. U kardinallikka moyil (ID va uzluksiz belgilar sun'iy yuqori ball oladi), o'quv ma'lumotida hisoblanadi va korrelyatsiyali belgilar orasida muhimlikni tasodifiy taqsimlaydi. Uni faqat tezkor ichki ko'rik uchun ishlating, hisobotga qo'ymang.

  2. Permutation importance — test to'plamida. Belgini aralashtirib, sifat qanchaga tushishini o'lchaydi. n_repeats ni 10-30 qo'ying va albatta test yoki validatsiya to'plamida hisoblang. Korrelyatsiyali belgilarni Spearman + ierarxik klasterlash bilan guruhlab, guruhni birgalikda aralashtiring.

  3. Muhimlik sababiylik emas. "Kasalxonada yotgan kunlar" o'limni yaxshi bashorat qiladi, lekin kunlarni kamaytirish o'limni kamaytirmaydi — ikkalasi ham kasallik og'irligining natijasi. Muhimlik diagrammasi asosida "bu ko'rsatkichni o'zgartiramiz" degan qaror qabul qilish — eng keng tarqalgan xato. Sababiy xulosa uchun eksperiment yoki sababiy model kerak.

Keyingi darsda ansambllarni solishtirishni o'rganamiz: voting, stacking va qaysi ansamblni qachon tanlash.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
15.11-dars: Belgi muhimligi — IlmHamroh