Asosiy qismga o'tish

Feature engineering va selection

23-bob 15 kod bloki 3900 so'z

Bu bobdagi kod shu fayllar bilan ishlaydio'z kompyuteringizda ishga tushiring

Sahna: "yangi xususiyat qo'shing" — qanday?

10-bobdagi qaror jadvalida birinchi qator shunday edi:

Xatolar bitta guruhda to'plangan -> yangi xususiyat qo'shing

Yaxshi. Lekin qanday xususiyat? Qaysi biri yordam beradi?

Va 0-bobda men bitta urinish qilganman: maydon_har_xona qo'shdim va natija +0.0056 o'zgardi — ya'ni deyarli hech narsa.

Bu bob shu savolga javob beradi, va javobning yarmi ko'ngilsiz: xususiyat muhandisligi ko'pincha ishlamaydi. Lekin ishlaganda — eng katta foyda beradi.

Beshta usul

python33 qator
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression

df = pd.read_csv(DATA / "uy_ijara.csv")
son = ["xonalar", "maydon_m2", "qavat", "qavatlar_soni", "metro_km", "mebel", "qurilgan_yil"]
matn = ["tuman"]
X, y = df[son + matn], df["ijaraga_berildi_30k"]

def quvur(son_list, matn_list=matn, model=None):
    return Pipeline([
        ("t", ColumnTransformer([
            ("son", Pipeline([("i", SimpleImputer(strategy="median")), ("sc", StandardScaler())]), son_list),
            ("matn", OneHotEncoder(handle_unknown="ignore"), matn_list),
        ])),
        ("m", model or LogisticRegression(max_iter=3000)),
    ])

baza_ball = cross_val_score(quvur(son), X, y, cv=5, scoring="f1")
print(f"BOSHLANG'ICH (7 xususiyat): F1 = {baza_ball.mean():.4f} ±{baza_ball.std():.4f}")
print()
show(pd.DataFrame([
    {"Usul": "1. Nisbat va ayirma", "Misol": "narx/maydon, maydon/xonalar"},
    {"Usul": "2. Sana parchalash", "Misol": "yil, oy, hafta kuni, bayram kunimi"},
    {"Usul": "3. Guruhlash (binning)", "Misol": "yosh -> 'yosh/o`rta/katta'"},
    {"Usul": "4. O'zaro ta'sir", "Misol": "mebel VA metroga yaqin bo'lsa"},
    {"Usul": "5. Guruh statistikasi", "Misol": "tumanning o'rtacha narxi"},
]))
Chiqish
BOSHLANG'ICH (7 xususiyat): F1 = 0.7273 ±0.0118
UsulMisol
1. Nisbat va ayirmanarx/maydon, maydon/xonalar
2. Sana parchalashyil, oy, hafta kuni, bayram kunimi
3. Guruhlash (binning)yosh -> 'yosh/o`rta/katta'
4. O'zaro ta'sirmebel VA metroga yaqin bo'lsa
5. Guruh statistikasitumanning o'rtacha narxi

1-usul: nisbat va ayirma

Eng ko'p ishlatiladigan usul. Domen bilimi kerak.

python12 qator
def nisbatlar(d):
    d = d.copy()
    d["maydon_har_xona"] = d.maydon_m2 / d.xonalar
    d["qavat_ulushi"] = d.qavat / d.qavatlar_soni
    d["yoshi"] = 2026 - d.qurilgan_yil
    return d

yangi1 = son + ["maydon_har_xona", "qavat_ulushi", "yoshi"]
b1 = cross_val_score(quvur(yangi1), nisbatlar(X), y, cv=5, scoring="f1")
print(f"Boshlang'ich : {baza_ball.mean():.4f} ±{baza_ball.std():.4f}")
print(f"+ 3 nisbat   : {b1.mean():.4f} ±{b1.std():.4f}")
print(f"O'zgarish    : {b1.mean()-baza_ball.mean():+.4f}  (tarqalish ±{max(b1.std(), baza_ball.std()):.4f})")
Chiqish
Boshlang'ich : 0.7273 ±0.0118
+ 3 nisbat   : 0.7278 ±0.0115
O'zgarish    : +0.0004  (tarqalish ±0.0118)

Mavjud ustunlardan hisoblangan nisbat kam foyda beradi

maydon_har_xona = maydon_m2 / xonalar — model allaqachon ikkisini ham ko'rgan. Nisbat ularning yangi kombinatsiyasi, lekin yangi ma'lumot emas.

Chiziqli model nisbatni o'zi hisoblolmaydi (u faqat qo'shish va ko'paytirishni biladi), shuning uchun ba'zan yordam beradi. Daraxt esa nisbatni taqriban o'zi topadi — shuning uchun daraxtlarga bunday xususiyat deyarli foyda bermaydi.

Haqiqiy foyda yangi manba dan keladi: e'lon qancha vaqt saytda turgani, rasmlar soni, egasining javob tezligi.

2-usul: sanadan xususiyat

Bizning faylda sana yo'q, shuning uchun 43-bobdagi savdo ma'lumotini olamiz.

python13 qator
sv = pd.read_csv(DATA / "iflos_savdo.csv")
sana = pd.to_datetime(sv.order_date, format="mixed", dayfirst=True, errors="coerce")
tmp = pd.DataFrame({"sana": sana}).dropna()
tmp["yil"] = tmp.sana.dt.year
tmp["oy"] = tmp.sana.dt.month
tmp["hafta_kuni"] = tmp.sana.dt.dayofweek
tmp["chorak"] = tmp.sana.dt.quarter
tmp["oy_kuni"] = tmp.sana.dt.day
tmp["dam_olish_kuni"] = (tmp.sana.dt.dayofweek >= 5).astype(int)
tmp["oy_boshi"] = (tmp.sana.dt.day <= 5).astype(int)
show(tmp.head(6))
print()
print("Bitta `sana` ustunidan 7 ta xususiyat chiqdi.")
Chiqish
Bitta `sana` ustunidan 7 ta xususiyat chiqdi.
sanayiloyhafta_kunichorakoy_kunidam_olish_kunioy_boshi
2025-05-26 00:00:002 0255022600
2025-02-26 00:00:002 0252212600
2025-03-01 00:00:002 025351111
2025-01-03 00:00:002 025141301
2025-02-11 00:00:002 0252111100
2025-01-08 00:00:002 025121800

Sanani SON sifatida bermang

sana.astype(int) — bu timestamp beradi (1970 dan beri sekundlar). Model uni shunchaki o'sib boruvchi son deb ko'radi.

Natijada model "vaqt o'tgani sari natija oshadi" degan chiziqli bog'lanishni o'rganadi — va kelajakda ekstrapolyatsiya qilib yiqiladi.

Sanani parchalang: oy, hafta kuni, bayram. Bu davriy naqshlarni ushlaydi.

python8 qator
print("Hafta kuni bo'yicha bekor qilish ulushi — davriy naqsh bormi:")
sv2 = sv.assign(sana=sana, bekor=(sv.status == "cancelled").astype(int)).dropna(subset=["sana"])
sv2["hafta_kuni"] = sv2.sana.dt.dayofweek
kunlar = ["Dush", "Sesh", "Chor", "Pay", "Juma", "Shan", "Yak"]
g = sv2.groupby("hafta_kuni").bekor.agg(["size", "mean"])
g.index = [kunlar[i] for i in g.index]
g["mean"] = g["mean"].round(4)
show(g.reset_index().rename(columns={"index": "kun", "size": "buyurtmalar", "mean": "bekor_ulushi"}))
Chiqish
Hafta kuni bo'yicha bekor qilish ulushi — davriy naqsh bormi:
kunbuyurtmalarbekor_ulushi
Dush8850.042
Sesh7930.034
Chor8420.038
Pay8080.027
Juma9610.032
Shan1 0570.043
Yak8340.024

3-usul: guruhlash (binning)

python12 qator
def guruhlar(d):
    d = d.copy()
    d["maydon_guruh"] = pd.cut(d.maydon_m2, bins=[0, 40, 60, 90, 1000],
                               labels=[0, 1, 2, 3]).astype(float)
    d["metro_guruh"] = pd.cut(d.metro_km, bins=[0, 1, 2.5, 5, 100],
                              labels=[0, 1, 2, 3]).astype(float)
    return d

yangi3 = son + ["maydon_guruh", "metro_guruh"]
b3 = cross_val_score(quvur(yangi3), guruhlar(X), y, cv=5, scoring="f1")
print(f"Boshlang'ich : {baza_ball.mean():.4f}")
print(f"+ 2 guruh    : {b3.mean():.4f}  ({b3.mean()-baza_ball.mean():+.4f})")
Chiqish
Boshlang'ich : 0.7273
+ 2 guruh    : 0.7273  (-0.0000)

Binning chiziqli modelga chiziqsiz chegara beradi: "40 m2 dan kichik" alohida toifa bo'ladi.

Lekin narxi bor: ma'lumot yo'qoladi. 39 m2 va 41 m2 har xil guruhga tushadi, 41 va 59 esa bir guruhda.

4-usul: o'zaro ta'sir (interaction)

python12 qator
def ozaro(d):
    d = d.copy()
    d["mebel_x_metro"] = d.mebel * (d.metro_km < 2).astype(int)
    d["katta_va_markaz"] = ((d.maydon_m2 > 70) & (d.metro_km < 2)).astype(int)
    return d

yangi4 = son + ["mebel_x_metro", "katta_va_markaz"]
b4 = cross_val_score(quvur(yangi4), ozaro(X), y, cv=5, scoring="f1")
print(f"Boshlang'ich   : {baza_ball.mean():.4f}")
print(f"+ 2 o'zaro ta'sir: {b4.mean():.4f}  ({b4.mean()-baza_ball.mean():+.4f})")
print()
print("Daraxt bunday kombinatsiyani O'ZI topadi (17-bob), chiziqli model esa TOPMAYDI.")
Chiqish
Boshlang'ich   : 0.7273
+ 2 o'zaro ta'sir: 0.7265  (-0.0008)

Daraxt bunday kombinatsiyani O'ZI topadi (17-bob), chiziqli model esa TOPMAYDI.

5-usul: guruh statistikasi — va uning tuzog'i

Eng kuchli usul: "bu kvartira o'z tumanidagi o'rtachaga nisbatan qanday?"

Lekin bu — leakage uchun eng xavfli joy.

python23 qator
# Target encoding: KARDINALLIK hamma narsani hal qiladi
def te_ball(X_qoshimcha):
    q = Pipeline([("i", SimpleImputer(strategy="median")), ("sc", StandardScaler()),
                  ("m", LogisticRegression(max_iter=3000))])
    return cross_val_score(q, X_qoshimcha, y, cv=5, scoring="f1").mean()

r2 = np.random.default_rng(0)
faqat_son = df[son]

# 1) past kardinallik: tuman — 8 guruh
te_8 = faqat_son.assign(te=df.tuman.map(df.groupby("tuman").ijaraga_berildi_30k.mean()))
# 2) yuqori kardinallik: 400 sun'iy guruh
guruh_400 = r2.integers(0, 400, len(df))
te_400 = faqat_son.assign(te=pd.Series(y.values).groupby(guruh_400).transform("mean").values)
# 3) chegara holat: har qator o'z guruhida
te_1200 = faqat_son.assign(te=y.values.astype(float))

print(f"{'holat':<34} {'guruhda qator':>14} {'CV F1':>9}")
print("-" * 60)
print(f"{'baza (target encoding YO`Q)':<34} {'-':>14} {te_ball(faqat_son):>9.4f}")
print(f"{'8 guruh (tuman)':<34} {len(df)//8:>14} {te_ball(te_8):>9.4f}")
print(f"{'400 guruh':<34} {len(df)//400:>14} {te_ball(te_400):>9.4f}")
print(f"{'1200 guruh (har qator o`zi)':<34} {1:>14} {te_ball(te_1200):>9.4f}")
Chiqish
holat                               guruhda qator     CV F1
------------------------------------------------------------
baza (target encoding YO`Q)                     -    0.7219
8 guruh (tuman)                               150    0.7251
400 guruh                                       3    0.8032
1200 guruh (har qator o`zi)                     1    1.0000

Mana bu jadval target encoding ni to'g'ri tushuntiradi.

Men bu bo'limni "target encoding butun ma'lumotda hisoblansa natija shubhali yaxshilanadi" deb yozgan edim va tuman ni misol qilgandim. O'lchadim — yaxshilanish bo'lmadi (0.7219 va 0.7251, farq ahamiyatsiz).

Sabab kardinallikda. tuman da 8 guruh bor, har birida ~150 qator. Bitta qatorning javobi 150 qatorli o'rtachaga deyarli ta'sir qilmaydi — shuning uchun leakage kuchsiz.

Guruhlar ko'payib, har birida qator kamayganda esa:

  • 400 guruh (~3 qator) -> F1 0.8032 ga ko'tarildi. Mana leakage.
  • 1200 guruh (1 qator) -> F1 1.0000. Har qator o'z javobini xususiyat sifatida ko'rdi.

Target encoding xavfi kardinallikka proporsional

Qoida: guruhda qator kamaysa, leakage kuchayadi.

  • Guruhda yuzlab qator (tuman, viloyat) -> leakage kuchsiz, lekin baribir Pipeline ichida hisoblang
  • Guruhda bir necha qator (mahsulot kodi, foydalanuvchi ID) -> xavfli
  • Guruhda bitta qator -> bu target ning o'zi, xususiyat emas

Shuning uchun yuqori kardinallikdagi ustunlar uchun out-of-fold target encoding ishlatiladi: har qatorning kodlangan qiymati uni o'z ichiga olmagan fold lardan hisoblanadi.

Va eng muhimi: men bu yerda adashdim, chunki bitta holatni (8 guruh) sinab, undan umumiy xulosa chiqarmoqchi edim. Bitta o'lchov qoida bermaydi — parametrni o'zgartirib bir necha nuqtada o'lchang.

python34 qator
from sklearn.base import BaseEstimator, TransformerMixin

class GuruhStatistikasi(BaseEstimator, TransformerMixin):
    """Guruh o'rtachasini FAQAT fit() ko'rgan ma'lumotdan hisoblaydi."""
    def __init__(self, guruh_ustun="tuman", maqsad_ustun="narx_usd"):
        self.guruh_ustun = guruh_ustun
        self.maqsad_ustun = maqsad_ustun

    def fit(self, X, y=None):
        self.xarita_ = X.groupby(self.guruh_ustun)[self.maqsad_ustun].mean()
        self.umumiy_ = X[self.maqsad_ustun].mean()
        return self

    def transform(self, X):
        d = X.copy()
        d["guruh_ortacha"] = d[self.guruh_ustun].map(self.xarita_).fillna(self.umumiy_)
        d["guruhdan_farq"] = d[self.maqsad_ustun] - d["guruh_ortacha"]
        return d

q_toza = Pipeline([
    ("stat", GuruhStatistikasi()),
    ("t", ColumnTransformer([
        ("son", Pipeline([("i", SimpleImputer(strategy="median")), ("sc", StandardScaler())]),
         son + ["guruh_ortacha", "guruhdan_farq"]),
        ("matn", OneHotEncoder(handle_unknown="ignore"), matn),
    ])),
    ("m", LogisticRegression(max_iter=3000)),
])
X_narx = df[son + matn + ["narx_usd"]]
b5_toza = cross_val_score(q_toza, X_narx, y, cv=5, scoring="f1")
print(f"Boshlang'ich                 : {baza_ball.mean():.4f}")
print(f"+ guruh stat (Pipeline ichida): {b5_toza.mean():.4f} ±{b5_toza.std():.4f}")
print()
print("Bu raqamga ISHONISH mumkin — statistika har fold da qaytadan hisoblanadi.")
Chiqish
Boshlang'ich                 : 0.7273
+ guruh stat (Pipeline ichida): 0.7400 ±0.0191

Bu raqamga ISHONISH mumkin — statistika har fold da qaytadan hisoblanadi.

Hammasi birga: halol hisobot

python18 qator
natijalar = [
    ("Boshlang'ich (7 xususiyat)", baza_ball),
    ("+ nisbatlar", b1),
    ("+ guruhlash (binning)", b3),
    ("+ o'zaro ta'sir", b4),
    ("+ guruh stat (Pipeline ichida)", b5_toza),
]
qatorlar = []
for nom, b in natijalar:
    qatorlar.append({"Variant": nom, "CV F1": round(b.mean(), 4), "±": round(b.std(), 4),
                     "boshlang'ichdan": round(b.mean() - baza_ball.mean(), 4)})
show(pd.DataFrame(qatorlar))
print()
tarqalish = max(b.std() for _, b in natijalar)
eng = max(natijalar, key=lambda x: x[1].mean())
print(f"Eng baland: {eng[0]} ({eng[1].mean():.4f})")
print(f"Eng katta tarqalish: ±{tarqalish:.4f}")
print(f"Hukm: {'farq tarqalishdan KATTA' if eng[1].mean()-baza_ball.mean() > tarqalish else 'farq tarqalish ICHIDA — xususiyatlar sezilarli foyda bermadi'}")
Chiqish
Eng baland: + guruh stat (Pipeline ichida) (0.7400)
Eng katta tarqalish: ±0.0191
Hukm: farq tarqalish ICHIDA — xususiyatlar sezilarli foyda bermadi
VariantCV F1±boshlang'ichdan
Boshlang'ich (7 xususiyat)0.7270.0120
+ nisbatlar0.7280.0110
+ guruhlash (binning)0.7270.01-0
+ o'zaro ta'sir0.7270.013-0.001
+ guruh stat (Pipeline ichida)0.740.0190.013

Xususiyat muhandisligi — ko'pincha ishlamaydi

Yuqoridagi jadval halol natija. Bizning ma'lumotda qo'shilgan xususiyatlar sezilarli foyda bermadi.

Bu normal. Kaggle da yetakchilar ham o'nlab xususiyat sinab, bir-ikkitasini qoldiradi.

Shuning uchun tartib muhim: 1. Bitta xususiyat qo'shing 2. CV bilan o'lchang 3. Tarqalish bilan solishtiring (9-bob) 4. Foyda bermasa tashlang — "balki keyin kerak bo'lar" deb qoldirmang

Har bir keraksiz ustun o'qitishni sekinlashtiradi va overfitting xavfini oshiradi.

Xususiyat tanlash: uch oila

Ko'p xususiyat bo'lsa, keraksizini qanday topamiz?

python14 qator
r = np.random.default_rng(42)
sh = pd.DataFrame(r.normal(size=(len(X), 40)),
                  columns=[f"shovqin_{i}" for i in range(40)], index=X.index)
X_kop = pd.concat([X[son], sh], axis=1)
print(f"Xususiyatlar: {len(son)} haqiqiy + 40 shovqin = {X_kop.shape[1]}")
print()
show(pd.DataFrame([
    {"Oila": "Filter", "Qanday ishlaydi": "Statistika bilan baholaydi, modelsiz",
     "sklearn": "SelectKBest, VarianceThreshold", "Tezlik": "Juda tez"},
    {"Oila": "Wrapper", "Qanday ishlaydi": "Modelni qayta-qayta o'qitib sinaydi",
     "sklearn": "RFE, RFECV", "Tezlik": "Sekin"},
    {"Oila": "Embedded", "Qanday ishlaydi": "Model o'qitish paytida o'zi tanlaydi",
     "sklearn": "Lasso, daraxt muhimligi", "Tezlik": "Tez (bepul)"},
]))
Chiqish
Xususiyatlar: 7 haqiqiy + 40 shovqin = 47
OilaQanday ishlaydisklearnTezlik
FilterStatistika bilan baholaydi, modelsizSelectKBest, VarianceThresholdJuda tez
WrapperModelni qayta-qayta o'qitib sinaydiRFE, RFECVSekin
EmbeddedModel o'qitish paytida o'zi tanlaydiLasso, daraxt muhimligiTez (bepul)
python23 qator
from sklearn.feature_selection import SelectKBest, f_classif, RFE
from sklearn.ensemble import RandomForestClassifier
import time

def oddiy_quvur(sel=None, model=None):
    # DIQQAT: imputer BIRINCHI bo'lishi kerak — SelectKBest NaN qabul qilmaydi
    qadamlar = [("i", SimpleImputer(strategy="median")), ("sc", StandardScaler())]
    if sel is not None:
        qadamlar.append(("sel", sel))
    qadamlar.append(("m", model or LogisticRegression(max_iter=3000)))
    return Pipeline(qadamlar)

print(f"{'usul':<34} {'CV F1':>9} {'±':>8} {'vaqt':>8}")
print("-" * 62)
for nom, sel in [
    ("Tanlovsiz (47 xususiyat)", None),
    ("Filter: SelectKBest(k=7)", SelectKBest(f_classif, k=7)),
    ("Wrapper: RFE(n=7)", RFE(LogisticRegression(max_iter=2000), n_features_to_select=7)),
]:
    t0 = time.perf_counter()
    b = cross_val_score(oddiy_quvur(sel), X_kop, y, cv=5, scoring="f1")
    dt = time.perf_counter() - t0
    print(f"{nom:<34} {b.mean():>9.4f} {b.std():>8.4f} {dt:>7.1f}s")
Chiqish
usul                                   CV F1        ±     vaqt
--------------------------------------------------------------
Tanlovsiz (47 xususiyat)              0.7021   0.0156     0.0s
Filter: SelectKBest(k=7)              0.7272   0.0140     0.0s
Wrapper: RFE(n=7)                     0.7130   0.0129     0.3s
python13 qator
# tanlov HAQIQIY xususiyatlarni topdimi?
Xk_toza = SimpleImputer(strategy="median").fit_transform(X_kop)
sel = SelectKBest(f_classif, k=7).fit(StandardScaler().fit_transform(Xk_toza), y)
tanlangan = X_kop.columns[sel.get_support()].tolist()
haqiqiy = [t for t in tanlangan if not t.startswith("shovqin")]
print(f"SelectKBest 7 ta tanladi: {tanlangan}")
print(f"  shundan haqiqiy: {len(haqiqiy)} / 7")
print()
rfe = RFE(LogisticRegression(max_iter=2000), n_features_to_select=7).fit(
    StandardScaler().fit_transform(Xk_toza), y)
t_rfe = X_kop.columns[rfe.get_support()].tolist()
print(f"RFE 7 ta tanladi: {t_rfe}")
print(f"  shundan haqiqiy: {len([t for t in t_rfe if not t.startswith('shovqin')])} / 7")
Chiqish
SelectKBest 7 ta tanladi: ['xonalar', 'maydon_m2', 'qurilgan_yil', 'shovqin_5', 'shovqin_8', 'shovqin_26', 'shovqin_28']
  shundan haqiqiy: 3 / 7

RFE 7 ta tanladi: ['xonalar', 'maydon_m2', 'qavat', 'qavatlar_soni', 'shovqin_8', 'shovqin_13', 'shovqin_26']
  shundan haqiqiy: 4 / 7

Xususiyat tanlash Pipeline ICHIDA bo'lishi kerak

Eng ko'p uchraydigan leakage shakli:

python3 qator
sel = SelectKBest(k=10).fit(X, y)      # BUTUN ma'lumotda — y ni ko'rdi!
X_tanlangan = sel.transform(X)
cross_val_score(model, X_tanlangan, y, cv=5)   # natija YOLG'ON

Tanlov y ni ko'rib ustun tanladi, keyin CV o'sha tanlovni sinaydi. Natija optimistik.

To'g'ri yo'l — yuqoridagi kodda: Pipeline([("sel", SelectKBest(...)), ("m", model)]). Shunda tanlov har fold da qaytadan bajariladi.

Pipeline da QADAMLAR TARTIBI muhim

Bu blokni birinchi yozganimda SimpleImputer ni qo'ymagandim, va build shunday xato bilan to'xtadi:

yaml2 qator
ValueError: Input X contains NaN.
SelectKBest does not accept missing values encoded as NaN natively.

Sababi: qurilgan_yil ustunida 8 ta bo'sh qiymat bor (0-bob), va SelectKBest ularni qabul qilmaydi.

To'g'ri tartib: to'ldirish -> shkalalash -> tanlash -> model. Har bir qadam o'zidan oldingisining chiqishini kutadi.

Qoida: yangi qadam qo'shganda o'zingizdan so'rang — "bu qadam NaN ni eplaydimi?" Daraxtlar eplaydi, qolgan ko'pchilik eplamaydi.

Bugun nima o'rgandik

python10 qator
show(pd.DataFrame([
    {"Usul": "Nisbat va ayirma", "Kimga foydali": "Chiziqli modelga", "Diqqat": "Daraxt o'zi topadi"},
    {"Usul": "Sanani parchalash", "Kimga foydali": "Hammaga", "Diqqat": "Sanani son qilib bermang"},
    {"Usul": "Binning", "Kimga foydali": "Chiziqli modelga", "Diqqat": "Ma'lumot yo'qoladi"},
    {"Usul": "O'zaro ta'sir", "Kimga foydali": "Chiziqli modelga", "Diqqat": "Daraxt o'zi topadi"},
    {"Usul": "Guruh statistikasi", "Kimga foydali": "Hammaga — eng kuchli", "Diqqat": "LEAKAGE xavfi eng yuqori"},
    {"Usul": "Filter tanlov", "Kimga foydali": "Tez skrining", "Diqqat": "Modelni hisobga olmaydi"},
    {"Usul": "Wrapper (RFE)", "Kimga foydali": "Aniq tanlov", "Diqqat": "Sekin"},
    {"Usul": "Embedded (Lasso)", "Kimga foydali": "Bepul (16-bob)", "Diqqat": "alpha ni topish kerak"},
]))
UsulKimga foydaliDiqqat
Nisbat va ayirmaChiziqli modelgaDaraxt o'zi topadi
Sanani parchalashHammagaSanani son qilib bermang
BinningChiziqli modelgaMa'lumot yo'qoladi
O'zaro ta'sirChiziqli modelgaDaraxt o'zi topadi
Guruh statistikasiHammaga — eng kuchliLEAKAGE xavfi eng yuqori
Filter tanlovTez skriningModelni hisobga olmaydi
Wrapper (RFE)Aniq tanlovSekin
Embedded (Lasso)Bepul (16-bob)alpha ni topish kerak

Asosiy qoida: bitta o'zgarish, o'lchash, tarqalish bilan solishtirish. Va foyda bermasa — tashlash.

Keyingi bobda: modelning sozlamalarini qanday tanlaymiz?

Bu bobni bepul o'qidingiz.

Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.

Telegramda yozish Narxlar