Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. To'liq oqim
- 2.2. Bosqichma-bosqich baholash
- 2.3. Qachon to'xtash
- 2.4. Yakuniy audit
- 2.5. Hujjatlashtirish
- 2.6. Ishlab chiqarishga tayyorlash
- 2.7. Tuzoqlar
- 2.8. Tartib va to'xtash qoidasi
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Audit va validatsiya strategiyasi
- Misol 2 — Belgilar guruhlarini bosqichma-bosqich qo'shish
- Misol 3 — Tanlash, sozlash va yakuniy baho
- Misol 4 — Yakuniy audit va paket
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
17.10-dars: Amaliyot — to'liq belgi muhandisligi
17-QISM — FEATURE ENGINEERING · 10-dars
1. Kirish va motivatsiya
Bu qismda belgi turlaridan boshlab Pipeline gacha bo'lgan yo'lni bosib o'tdik. Endi hammasini bitta loyihada birlashtiramiz: xom, aralash turdagi ma'lumotdan boshlab, leakage dan tozalangan va ishlab chiqarishga tayyor quvurgacha.
Feature engineering loyihasining asosiy qiyinligi — tartib: belgilarni tasodifiy qo'shish oson, lekin qaysi guruh qancha foyda berganini bilish qiyin. Yechim — bosqichma-bosqich qo'shish va har bosqichda CV bilan o'lchash.
Ikkinchi qiyinlik — to'xtash: yangi belgi o'ylab topish har doim mumkin, lekin qaysi nuqtada to'xtash kerak? Javob — CV standart og'ishi va narx-foyda.
Bu darsda: to'liq oqim (audit → bazaviy → belgilar guruhlari → tanlash → sozlash → yakuniy baho → saqlash), har bosqichda qaror qabul qilish va natijani hujjatlashtirish.
Real vaziyat. Loyihada 3 hafta belgi muhandisligi qilindi va 180 ta belgi yaratildi. Yakuniy audit ko'rsatdiki: 12 ta belgi AUC ning 95% ini beradi, qolganlari esa shovqin. Model 180 dan 12 ga tushirildi — aniqlik bir xil, tezlik 14 barobar, va risk bo'limi uni tasdiqladi.
Bu darsda to'liq belgi muhandisligi loyihasini quramiz.
Bu darsda:
- To'liq oqim
- Bosqichma-bosqich baholash
- Qachon to'xtash
- Yakuniy audit
- Hujjatlashtirish
- Ishlab chiqarishga tayyorlash
- Tuzoqlar
- Amaliy: yakuniy loyiha
ℹ Misollar real numpy/pandas/sklearn bilan (Python 3.14).
2. Nazariya — chuqur tushuntirish
2.1. To'liq oqim
1. AUDIT: ustunlar, turlar, yo'qolgan qiymatlar, duplikatlar
2. LEAKAGE TEKSHIRUVI: "bu qiymat qachon yoziladi?" har ustun uchun
3. VALIDATSIYA STRATEGIYASI: vaqt? guruh? oddiy CV?
4. BAZAVIY: eng sodda belgilar + sodda model
5. BELGILAR GURUHLARI: bosqichma-bosqich qo'shish va o'lchash
6. TANLASH: keraksizlarini olib tashlash
7. SOZLASH: tayyorlash + model parametrlari birga
8. YAKUNIY BAHO: alohida test to'plamida BIR MARTA
9. AUDIT: leakage, barqarorlik, ishlab chiqarishda mavjudlik
10. SAQLASH: Pipeline + metama'lumot + hujjat3-qadam (validatsiya strategiyasi) eng erta qabul qilinadigan va eng muhim qaror: noto'g'ri CV bilan qolgan to'qqiz qadamning hammasi ma'nosiz bo'ladi.
2.2. Bosqichma-bosqich baholash
Belgilarni GURUH bo'lib qo'shing:
bazaviy xom sonli belgilar
+ kategoriya kodlangan kategoriyali belgilar
+ nisbatlar a/b naqshlari
+ agregatsiya guruh statistikasi
+ vaqt komponentlar, lag, oyna
+ matn statistika va TF-IDF
Har guruh uchun:
CV natijasi, std, belgilar soni, hisoblash narxi
QAROR: yaxshilanish CV STD dan katta bo'lsa - qoldiring
aks holda - tashlang (murakkablik bepul emas)Guruh bo'lib qo'shish natijani tushunarli qiladi: "nisbatlar +0.011, vaqt +0.015, agregatsiya +0.010" degan jadval qaysi yo'nalishda davom etish kerakligini aniq ko'rsatadi.
2.3. Qachon to'xtash
TO'XTASH SIGNALLARI:
1. So'nggi 2-3 guruh CV std dan kam foyda berdi
2. Yaxshilanish bor, lekin ishlab chiqarish narxi oqlamaydi
3. Belgilar soni talqin chegarasidan oshdi
4. Yangi belgilar uchun ma'lumot manbai yo'q
5. Vaqt byudjeti tugadi
ODATIY TAQSIMOT:
birinchi 3-5 belgi guruhi -> foydaning 80%
keyingi 10 guruh -> foydaning 20%
QOIDA: to'xtash nuqtasini OLDINDAN belgilang
"CV std dan kam foyda beradigan 2 guruh ketma-ket kelsa - to'xtayman"To'xtash qoidasini oldindan belgilang: aks holda "yana bitta belgi" jarayoni cheksiz davom etadi va siz validatsiyaga overfitting qilasiz.
2.4. Yakuniy audit
TEKSHIRUV RO'YXATI:
[ ] Duplikatlar tozalanganmi (bo'lishdan OLDIN)
[ ] Har belgining yakka CV natijasi < 0.85
[ ] Validatsiya strategiyasi vazifaga mos
[ ] Barcha tayyorlash Pipeline ichida
[ ] Har belgi uchun "qachon ma'lum?" javobi bor
[ ] Belgilar ishlab chiqarishda hisoblanadi
[ ] CV va test natijasi yaqin
[ ] Permutation importance mantiqli
SHUBHALI BELGILAR:
- yakka AUC > 0.85
- permutation muhimligi hukmron (boshqalardan 5x katta)
- nomi "natija", "yopilish", "qaytarish" kabi so'zlarni o'z ichiga oladi Belgi nomlari ham signal beradi: yopilish_sababi, qaytarish_summasi, yakuniy_holat kabi nomlar deyarli har doim leakage ni anglatadi.
2.5. Hujjatlashtirish
BELGILAR LUG'ATI (feature dictionary):
nom | ta'rif | manba | qachon ma'lum | tur | yaratilgan sana | egasi
Misol:
qarz_nisbati | qarz / daromad | ariza formasi | ariza vaqtida |
sonli | 2026-09 | risk jamoasi
QO'SHIMCHA:
- har belgi guruhining CV hissasi
- tashlangan belgilar va sabablari
- leakage tekshiruvi natijasi
- ishlab chiqarishda hisoblash kodi/so'rovi Belgilar lug'ati — jamoaviy ishning asosi: usiz olti oydan keyin hech kim x_47 belgisining nima ekanini eslay olmaydi.
2.6. Ishlab chiqarishga tayyorlash
import joblib
paket = {
"quvur": quvur, # butun tayyorlash + model
"belgilar": list(X.columns), # kirish ustunlari va TARTIBI
"belgilar_lugati": lugat, # ta'riflar
"metrika": {"cv_auc": 0.812, "test_auc": 0.807},
"versiyalar": {"sklearn": sklearn.__version__},
"sana": "2026-09-21",
}
joblib.dump(paket, "model.joblib", compress=3)ISHLAB CHIQARISHDA TEKSHIRISH:
assert list(yangi.columns) == paket["belgilar"]
yangi kategoriyalar ulushi
NaN ulushi o'quvdagidan farq qiladimi
bashorat taqsimoti o'quvdagiga o'xshashmi Kirish ustunlari tartibini saqlang va tekshiring: ColumnTransformer nom bo'yicha ishlaydi, lekin massiv berilganda tartib muhim bo'ladi va jim xato paydo bo'lishi mumkin.
2.7. Tuzoqlar
Asosiy tuzoqlar: validatsiya strategiyasini kech tanlash; belgilarni bitta-bitta qo'shib vaqt yo'qotish; to'xtash qoidasisiz ishlash; yakuniy auditni o'tkazib yuborish; belgilar lug'atini yozmaslik; test to'plamini bir necha marta ishlatish; ishlab chiqarishda hisoblanmaydigan belgi yaratish; murakkablikni "bepul" deb hisoblash.
2.8. Tartib va to'xtash qoidasi
Feature engineering loyihasi tartib bilan olib boriladi: audit → leakage tekshiruvi → validatsiya strategiyasi → bazaviy → guruh bo'lib belgilar qo'shish → tanlash → sozlash → bir marta test → audit → saqlash. Har guruhning hissasini CV std bilan solishtiring va to'xtash qoidasini oldindan belgilang. Yakunda belgilar lug'ati va Pipeline paketi topshiriladi. Bu bilan 17-qism yakunlanadi.
3. Tez ma'lumotnoma
import joblib
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.model_selection import GroupKFold, cross_val_score, train_test_split
from sklearn.pipeline import Pipeline
# 1. audit
df.duplicated().sum(); df.isna().mean(); df.nunique()
# 2. guruh bo'lib baholash
for nom, ustunlar in guruhlar.items():
b = cross_val_score(quvur, X[ustunlar], y, cv=cv, scoring="roc_auc")
print(nom, b.mean(), b.std())
# 3. yakuniy
joblib.dump({"quvur": quvur, "belgilar": list(X.columns),
"lugat": lugat, "metrika": {...}}, "model.joblib", compress=3)
QOIDA: validatsiyani birinchi tanla · guruh bo'lib o'lcha ·
to'xtash qoidasini oldindan belgila · testni bir marta ishlatAmaliyot xulosasi
1 audit -> 2 leakage -> 3 validatsiya -> 4 bazaviy -> 5 guruhlar
-> 6 tanlash -> 7 sozlash -> 8 test -> 9 audit -> 10 saqlash
Har guruh CV std bilan solishtiriladi
Topshirishda: belgilar lug'ati + Pipeline paketi4. Batafsil misollar
Misollar real numpy/pandas/sklearn bilan (Python 3.14).
Misol 1 — Audit va validatsiya strategiyasi
"""1-4 qadamlar (real pandas/sklearn)."""
import numpy as np
import pandas as pd
from sklearn.dummy import DummyClassifier
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.model_selection import (GroupKFold, StratifiedKFold,
cross_val_score)
def yarat(seed: int = 42, mijozlar: int = 1400) -> pd.DataFrame:
"""Yetkazib berish: har mijozning bir necha buyurtmasi (guruh tuzilmasi)."""
rng = np.random.default_rng(seed)
qatorlar = []
boshlanish = pd.Timestamp("2025-01-01")
for m in range(mijozlar):
imzo = rng.normal(0, 1) # mijozning xulqi
kod = round(float(rng.random()), 6) # CRM kodi - signal YO'Q
hudud = rng.choice(["toshkent", "samarqand", "buxoro", "fargona"])
hq = {"toshkent": 0.0, "samarqand": 0.5, "buxoro": 1.0,
"fargona": 0.3}[hudud]
odatiy = rng.lognormal(12.0, 0.45) # mijozning odatiy summasi
for _ in range(int(rng.integers(8, 24))):
sana = boshlanish + pd.Timedelta(days=int(rng.integers(0, 400)))
summa = odatiy * rng.lognormal(0, 0.5)
masofa = rng.gamma(2, 110)
ogirlik = rng.gamma(2, 5)
soat = int(rng.integers(0, 24))
kuch = (-1.9 + hq
+ 3.0 * (ogirlik / masofa > 0.085)
+ 0.9 * (7 <= soat <= 10)
+ 1.0 * (sana.dayofweek >= 5)
+ 1.6 * (summa > 1.15 * odatiy)
+ 1.8 * imzo)
kechikdi = int(rng.random() < 1 / (1 + np.exp(-kuch)))
# LEAKAGE belgisi: qaytarish faqat kechikkanda yoziladi
qaytarish = summa * rng.uniform(0.3, 1.0) if kechikdi else 0.0
qatorlar.append([m, kod, sana, hudud, summa, masofa, ogirlik,
soat, qaytarish, kechikdi])
df = pd.DataFrame(qatorlar, columns=["mijoz", "kod", "sana", "hudud",
"summa", "masofa", "ogirlik", "soat",
"qaytarish", "kechikdi"])
dup = df.sample(frac=0.05, random_state=0) # duplikatlar
return pd.concat([df, dup], ignore_index=True)
def main() -> None:
df = yarat()
print("=== 1. Audit ===")
print(f" {len(df)} qator, {df['mijoz'].nunique()} mijoz")
print(f" {'ustun':<12} {'dtype':<16} {'noyob':>7} {'yo_qolgan':>10}")
for ustun in df.columns:
print(f" {ustun:<12} {str(df[ustun].dtype):<16} "
f"{df[ustun].nunique():>7} {int(df[ustun].isna().sum()):>10}")
dup = df.duplicated()
print(f" duplikatlar: {int(dup.sum())} ({dup.mean():.1%}) - TOZALANADI")
df = df.drop_duplicates().reset_index(drop=True)
print(f" tozalangandan keyin: {len(df)} qator")
y = df["kechikdi"].to_numpy()
guruh = df["mijoz"].to_numpy()
def model(iter_soni: int = 200):
return HistGradientBoostingClassifier(learning_rate=0.1,
max_iter=iter_soni,
random_state=0)
print("\n=== 2. Leakage tekshiruvi (yakka belgi) ===")
cv_guruh = GroupKFold(5)
print(f" {'belgi':<12} {'yakka CV AUC':>14} {'baho':<12}")
for ustun in ["summa", "masofa", "ogirlik", "soat", "kod", "qaytarish"]:
b = cross_val_score(model(100), df[[ustun]], y, cv=cv_guruh,
groups=guruh, scoring="roc_auc").mean()
baho = "SHUBHALI" if b > 0.85 else "OK"
print(f" {ustun:<12} {b:>14.4f} {baho:<12}")
print(" 'qaytarish' kechikkandan KEYIN yoziladi -> olib tashlanadi")
print("\n=== 3. Validatsiya strategiyasi ===")
belgilar = ["summa", "masofa", "ogirlik", "soat", "kod"]
oddiy = cross_val_score(model(), df[belgilar], y,
cv=StratifiedKFold(5, shuffle=True,
random_state=0),
scoring="roc_auc")
guruhli = cross_val_score(model(), df[belgilar], y, cv=cv_guruh,
groups=guruh, scoring="roc_auc")
print(f" StratifiedKFold: {oddiy.mean():.4f} (+-{oddiy.std():.4f})")
print(f" GroupKFold: {guruhli.mean():.4f} (+-{guruhli.std():.4f})")
print(f" farq: {oddiy.mean() - guruhli.mean():+.4f}")
print(" sabab: 'kod' mijozga xos - tasodifiy bo'linishda model")
print(" mijozning o'quvdagi qatorlaridan uning testdagi qatorlarini")
print(" taniydi (guruh leakage i)")
print(" QAROR: GroupKFold (bir mijozning ko'p buyurtmasi bor)")
print("\n=== 4. Bazaviy natija ===")
dummy = cross_val_score(DummyClassifier(strategy="prior"), df[belgilar], y,
cv=cv_guruh, groups=guruh,
scoring="roc_auc").mean()
print(f" {'model':<26} {'CV ROC AUC':>12}")
print(f" {'Dummy':<26} {dummy:>12.4f}")
print(f" {'HistGB (xom belgilar)':<26} {guruhli.mean():>12.4f}")
print(f" kechikish ulushi: {y.mean():.2%}")
print(" ⭐ Validatsiya strategiyasi - eng erta va eng muhim qaror")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Audit ===
22865 qator, 1400 mijoz
ustun dtype noyob yo_qolgan
mijoz int64 1400 0
kod float64 1399 0
sana datetime64[us] 400 0
hudud str 4 0
summa float64 21776 0
masofa float64 21776 0
ogirlik float64 21776 0
soat int64 24 0
qaytarish float64 12186 0
kechikdi int64 2 0
duplikatlar: 1089 (4.8%) - TOZALANADI
tozalangandan keyin: 21776 qator
=== 2. Leakage tekshiruvi (yakka belgi) ===
belgi yakka CV AUC baho
summa 0.5656 OK
masofa 0.6159 OK
ogirlik 0.5866 OK
soat 0.5353 OK
kod 0.5170 OK
qaytarish 1.0000 SHUBHALI
'qaytarish' kechikkandan KEYIN yoziladi -> olib tashlanadi
=== 3. Validatsiya strategiyasi ===
StratifiedKFold: 0.7163 (+-0.0045)
GroupKFold: 0.6937 (+-0.0067)
farq: +0.0227
sabab: 'kod' mijozga xos - tasodifiy bo'linishda model
mijozning o'quvdagi qatorlaridan uning testdagi qatorlarini
taniydi (guruh leakage i)
QAROR: GroupKFold (bir mijozning ko'p buyurtmasi bor)
=== 4. Bazaviy natija ===
model CV ROC AUC
Dummy 0.5000
HistGB (xom belgilar) 0.6937
kechikish ulushi: 55.96%
⭐ Validatsiya strategiyasi - eng erta va eng muhim qarorNima ko'rsatdi: 2.1-bo'lim.
Misol 2 — Belgilar guruhlarini bosqichma-bosqich qo'shish
"""5-qadam: har guruhning hissasini o'lchash (real pandas/sklearn)."""
import numpy as np
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.model_selection import GroupKFold, cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
def yarat(seed: int = 42, mijozlar: int = 1400) -> pd.DataFrame:
rng = np.random.default_rng(seed)
qatorlar = []
boshlanish = pd.Timestamp("2025-01-01")
for m in range(mijozlar):
imzo = rng.normal(0, 1)
kod = round(float(rng.random()), 6)
hudud = rng.choice(["toshkent", "samarqand", "buxoro", "fargona"])
hq = {"toshkent": 0.0, "samarqand": 0.5, "buxoro": 1.0,
"fargona": 0.3}[hudud]
odatiy = rng.lognormal(12.0, 0.45)
for _ in range(int(rng.integers(8, 24))):
sana = boshlanish + pd.Timedelta(days=int(rng.integers(0, 400)))
summa = odatiy * rng.lognormal(0, 0.5)
masofa = rng.gamma(2, 110)
ogirlik = rng.gamma(2, 5)
soat = int(rng.integers(0, 24))
kuch = (-1.9 + hq
+ 3.0 * (ogirlik / masofa > 0.085)
+ 0.9 * (7 <= soat <= 10)
+ 1.0 * (sana.dayofweek >= 5)
+ 1.6 * (summa > 1.15 * odatiy)
+ 1.8 * imzo)
qatorlar.append([m, kod, sana, hudud, summa, masofa, ogirlik,
soat, int(rng.random() < 1 / (1 + np.exp(-kuch)))])
return pd.DataFrame(qatorlar, columns=["mijoz", "kod", "sana", "hudud",
"summa", "masofa", "ogirlik",
"soat", "kechikdi"]).sort_values(
["mijoz", "sana"]).reset_index(drop=True)
def belgilar_qosh(df: pd.DataFrame) -> pd.DataFrame:
df = df.copy()
# nisbatlar
df["ogirlik_masofaga"] = df["ogirlik"] / df["masofa"].clip(lower=1)
df["summa_ogirlikka"] = df["summa"] / df["ogirlik"].clip(lower=0.1)
# vaqt
d = df["sana"].dt
df["hafta_kuni"] = d.dayofweek
df["oy"] = d.month
df["hafta_oxiri"] = (d.dayofweek >= 5).astype(int)
df["tigiz_soat"] = (((df["soat"] >= 7) & (df["soat"] <= 10))
| ((df["soat"] >= 17) & (df["soat"] <= 19))).astype(int)
df["soat_sin"] = np.sin(2 * np.pi * df["soat"] / 24)
df["soat_cos"] = np.cos(2 * np.pi * df["soat"] / 24)
# agregatsiya: FAQAT o'tmishdan (shift bilan) - leakage yo'q
g = df.groupby("mijoz")
df["summa_oynasi"] = g["summa"].transform(
lambda s: s.shift(1).rolling(10, min_periods=2).mean())
df["summa_nisbati"] = df["summa"] / df["summa_oynasi"]
df["mijoz_buyurtmalari"] = g["summa"].transform("count")
return df
XOM = ["summa", "masofa", "ogirlik", "soat", "kod"]
NISBATLAR = ["ogirlik_masofaga", "summa_ogirlikka"]
VAQT = ["hafta_kuni", "oy", "hafta_oxiri", "tigiz_soat", "soat_sin",
"soat_cos"]
AGREGAT = ["summa_oynasi", "summa_nisbati", "mijoz_buyurtmalari"]
def main() -> None:
df = belgilar_qosh(yarat())
y = df["kechikdi"].to_numpy()
guruh = df["mijoz"].to_numpy()
cv = GroupKFold(5)
def baho(sonli, kategoriya=()):
tayyor = ColumnTransformer(
[("s", "passthrough", list(sonli))]
+ ([("k", OneHotEncoder(handle_unknown="ignore",
sparse_output=False), list(kategoriya))]
if kategoriya else []))
quvur = Pipeline([("t", tayyor),
("m", HistGradientBoostingClassifier(
learning_rate=0.1, max_iter=200,
random_state=0))])
b = cross_val_score(quvur, df, y, cv=cv, groups=guruh,
scoring="roc_auc")
return b.mean(), b.std(), len(sonli) + len(kategoriya)
print("=== 1. Belgilar guruhlarini ketma-ket qo'shish ===")
guruhlar = {
"bazaviy (xom)": (XOM, ()),
"+ kategoriya": (XOM, ["hudud"]),
"+ nisbatlar": (XOM + NISBATLAR, ["hudud"]),
"+ vaqt": (XOM + NISBATLAR + VAQT, ["hudud"]),
"+ agregatsiya": (XOM + NISBATLAR + VAQT + AGREGAT, ["hudud"]),
}
print(f" {'guruh':<18} {'belgilar':>9} {'CV AUC':>9} {'std':>8} "
f"{'o_sish':>9}")
oldingi = None
natijalar = {}
for nom, (sonli, kat) in guruhlar.items():
o, s, n = baho(sonli, kat)
natijalar[nom] = (o, s, n)
osish = "-" if oldingi is None else f"{o - oldingi:+.4f}"
print(f" {nom:<18} {n:>9} {o:>9.4f} {s:>8.4f} {osish:>9}")
oldingi = o
print("\n=== 2. Har guruhning hissasi CV std bilan ===")
nomlar = list(guruhlar)
print(f" {'guruh':<18} {'o_sish':>9} {'std':>8} {'qaror':<22}")
qarorlar = []
for i in range(1, len(nomlar)):
oldin = natijalar[nomlar[i - 1]][0]
hozir, std, _ = natijalar[nomlar[i]]
osish = hozir - oldin
otdi = osish > std
qarorlar.append(otdi)
qaror = "QOLDIRISH" if otdi else "shovqin (std dan kam)"
print(f" {nomlar[i]:<18} {osish:>+9.4f} {std:>8.4f} {qaror:<22}")
print("\n=== 3. Har guruh ALOHIDA (xom bilan birga) ===")
alohida = {
"xom": (XOM, ()),
"xom + kategoriya": (XOM, ["hudud"]),
"xom + nisbatlar": (XOM + NISBATLAR, ()),
"xom + vaqt": (XOM + VAQT, ()),
"xom + agregatsiya": (XOM + AGREGAT, ()),
}
asos = natijalar["bazaviy (xom)"][0]
print(f" {'variant':<20} {'CV AUC':>9} {'xomdan o_sish':>16}")
for nom, (sonli, kat) in alohida.items():
o, _, _ = baho(sonli, kat)
print(f" {nom:<20} {o:>9.4f} {o - asos:>+16.4f}")
print("\n=== 4. To'xtash qarori ===")
eng_yaxshi = max(natijalar, key=lambda k: natijalar[k][0])
o, s, n = natijalar[eng_yaxshi]
print(f" eng yaxshi to'plam: {eng_yaxshi} ({n} belgi)")
print(f" CV AUC {o:.4f} (+-{s:.4f})")
print(f" bazaviydan o'sish: {o - asos:+.4f}")
print(f" std dan yuqori foyda bergan guruhlar: {sum(qarorlar)}/"
f"{len(qarorlar)}")
if not qarorlar[-1]:
print(" so'nggi guruh std dan kam berdi -> TO'XTASH signali")
print(" ⭐ Guruh bo'lib qo'shish natijani tushunarli qiladi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Belgilar guruhlarini ketma-ket qo'shish ===
guruh belgilar CV AUC std o_sish
bazaviy (xom) 5 0.6988 0.0057 -
+ kategoriya 6 0.6982 0.0063 -0.0005
+ nisbatlar 8 0.7088 0.0067 +0.0106
+ vaqt 14 0.7238 0.0061 +0.0150
+ agregatsiya 17 0.7339 0.0048 +0.0101
=== 2. Har guruhning hissasi CV std bilan ===
guruh o_sish std qaror
+ kategoriya -0.0005 0.0063 shovqin (std dan kam)
+ nisbatlar +0.0106 0.0067 QOLDIRISH
+ vaqt +0.0150 0.0061 QOLDIRISH
+ agregatsiya +0.0101 0.0048 QOLDIRISH
=== 3. Har guruh ALOHIDA (xom bilan birga) ===
variant CV AUC xomdan o_sish
xom 0.6988 +0.0000
xom + kategoriya 0.6982 -0.0005
xom + nisbatlar 0.7036 +0.0049
xom + vaqt 0.7127 +0.0139
xom + agregatsiya 0.7038 +0.0050
=== 4. To'xtash qarori ===
eng yaxshi to'plam: + agregatsiya (17 belgi)
CV AUC 0.7339 (+-0.0048)
bazaviydan o'sish: +0.0351
std dan yuqori foyda bergan guruhlar: 3/4
⭐ Guruh bo'lib qo'shish natijani tushunarli qiladiNima ko'rsatdi: 2.2, 2.3-bo'limlar.
Misol 3 — Tanlash, sozlash va yakuniy baho
"""6-8 qadamlar (real pandas/sklearn)."""
import numpy as np
import pandas as pd
from scipy.stats import randint, uniform
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.inspection import permutation_importance
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import (GroupKFold, GroupShuffleSplit,
RandomizedSearchCV, cross_val_score)
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
def yarat(seed: int = 42, mijozlar: int = 1100) -> pd.DataFrame:
rng = np.random.default_rng(seed)
qatorlar = []
boshlanish = pd.Timestamp("2025-01-01")
for m in range(mijozlar):
imzo = rng.normal(0, 1)
kod = round(float(rng.random()), 6)
hudud = rng.choice(["toshkent", "samarqand", "buxoro", "fargona"])
hq = {"toshkent": 0.0, "samarqand": 0.5, "buxoro": 1.0,
"fargona": 0.3}[hudud]
odatiy = rng.lognormal(12.0, 0.45)
for _ in range(int(rng.integers(8, 24))):
sana = boshlanish + pd.Timedelta(days=int(rng.integers(0, 400)))
summa = odatiy * rng.lognormal(0, 0.5)
masofa = rng.gamma(2, 110)
ogirlik = rng.gamma(2, 5)
soat = int(rng.integers(0, 24))
kuch = (-1.9 + hq
+ 3.0 * (ogirlik / masofa > 0.085)
+ 0.9 * (7 <= soat <= 10)
+ 1.0 * (sana.dayofweek >= 5)
+ 1.6 * (summa > 1.15 * odatiy)
+ 1.8 * imzo)
qatorlar.append([m, kod, sana, hudud, summa, masofa, ogirlik,
soat, int(rng.random() < 1 / (1 + np.exp(-kuch)))])
return pd.DataFrame(qatorlar, columns=["mijoz", "kod", "sana", "hudud",
"summa", "masofa", "ogirlik",
"soat", "kechikdi"]).sort_values(
["mijoz", "sana"]).reset_index(drop=True)
def belgilar_qosh(df: pd.DataFrame) -> pd.DataFrame:
df = df.copy()
df["ogirlik_masofaga"] = df["ogirlik"] / df["masofa"].clip(lower=1)
df["summa_ogirlikka"] = df["summa"] / df["ogirlik"].clip(lower=0.1)
d = df["sana"].dt
df["hafta_kuni"] = d.dayofweek
df["oy"] = d.month
df["hafta_oxiri"] = (d.dayofweek >= 5).astype(int)
df["tigiz_soat"] = (((df["soat"] >= 7) & (df["soat"] <= 10))
| ((df["soat"] >= 17) & (df["soat"] <= 19))).astype(int)
df["soat_sin"] = np.sin(2 * np.pi * df["soat"] / 24)
df["soat_cos"] = np.cos(2 * np.pi * df["soat"] / 24)
g = df.groupby("mijoz")
df["summa_oynasi"] = g["summa"].transform(
lambda s: s.shift(1).rolling(10, min_periods=2).mean())
df["summa_nisbati"] = df["summa"] / df["summa_oynasi"]
df["mijoz_buyurtmalari"] = g["summa"].transform("count")
return df
SONLI = ["summa", "masofa", "ogirlik", "soat", "kod", "ogirlik_masofaga",
"summa_ogirlikka", "hafta_kuni", "oy", "hafta_oxiri", "tigiz_soat",
"soat_sin", "soat_cos", "summa_oynasi", "summa_nisbati",
"mijoz_buyurtmalari"]
KATEGORIYA = ["hudud"]
def quvur_yarat(sonli_ustunlar, **model_kw):
tayyor = ColumnTransformer([
("s", "passthrough", list(sonli_ustunlar)),
("k", OneHotEncoder(handle_unknown="ignore", sparse_output=False),
KATEGORIYA)])
return Pipeline([("t", tayyor),
("m", HistGradientBoostingClassifier(
learning_rate=0.1, max_iter=250, random_state=0,
**model_kw))])
def main() -> None:
df = belgilar_qosh(yarat())
y = df["kechikdi"].to_numpy()
guruh = df["mijoz"].to_numpy()
cv = GroupKFold(4)
print("=== 1. O'quv va test ajratish (guruh bo'yicha) ===")
gss = GroupShuffleSplit(n_splits=1, test_size=0.25, random_state=0)
tr, te = next(gss.split(df, y, groups=guruh))
print(f" o'quv {len(tr)} qator ({len(np.unique(guruh[tr]))} mijoz)")
print(f" test {len(te)} qator ({len(np.unique(guruh[te]))} mijoz)")
print(f" kesishgan mijozlar: "
f"{len(np.intersect1d(guruh[tr], guruh[te]))}")
dftr, ytr, gtr = df.iloc[tr], y[tr], guruh[tr]
dfte, yte = df.iloc[te], y[te]
print("\n=== 2. Belgi tanlash (permutation, test qismida EMAS) ===")
ichki = GroupShuffleSplit(n_splits=1, test_size=0.25, random_state=1)
i_tr, i_val = next(ichki.split(dftr, ytr, groups=gtr))
nomlar = SONLI + KATEGORIYA
ustunlar = dftr[nomlar]
quvur = quvur_yarat(SONLI).fit(dftr.iloc[i_tr], ytr[i_tr])
r = permutation_importance(quvur, ustunlar.iloc[i_val], ytr[i_val],
n_repeats=8, scoring="roc_auc",
random_state=0, n_jobs=1)
tartib = np.argsort(-r.importances_mean)
print(f" {'belgi':<20} {'muhimlik':>11}")
for i in tartib[:6]:
print(f" {nomlar[i]:<20} {r.importances_mean[i]:>+11.4f}")
print(" eng past uchtasi:")
for i in tartib[-3:]:
print(f" {nomlar[i]:<20} {r.importances_mean[i]:>+11.4f}")
print(f" muhimligi <= 0 bo'lganlar: "
f"{int((r.importances_mean <= 0).sum())} ta")
print("\n=== 3. Tanlangan to'plamlarni CV da solishtirish ===")
to_plamlar = {}
for chegara, nom in [(-1.0, "hammasi"), (0.0, "muhimlik > 0"),
(0.002, "muhimlik > 0.002")]:
tanlangan = [nomlar[i] for i in range(len(nomlar))
if r.importances_mean[i] > chegara
and nomlar[i] != "hudud"]
if len(tanlangan) < 3:
continue
to_plamlar[nom] = tanlangan
b = cross_val_score(quvur_yarat(tanlangan), dftr, ytr, cv=cv,
groups=gtr, scoring="roc_auc")
print(f" {nom:<20} {len(tanlangan) + 1:>3} belgi, "
f"CV {b.mean():.4f} (+-{b.std():.4f})")
print("\n=== 4. Sozlash va yakuniy baho ===")
tanlangan = to_plamlar["muhimlik > 0"]
taqsimot = {"m__max_depth": randint(2, 9),
"m__min_samples_leaf": randint(10, 120),
"m__l2_regularization": uniform(0, 5)}
q = RandomizedSearchCV(quvur_yarat(tanlangan), taqsimot, n_iter=12, cv=cv,
scoring="roc_auc", random_state=0,
n_jobs=1).fit(dftr, ytr, groups=gtr)
qisqa = {k.replace("m__", ""): (round(float(v), 3)
if isinstance(v, (float, np.floating))
else int(v))
for k, v in sorted(q.best_params_.items())}
print(f" eng yaxshi parametrlar: {qisqa}")
print(f" ichki CV: {q.best_score_:.4f}")
test = roc_auc_score(yte, q.predict_proba(dfte)[:, 1])
print(f" TEST (bir marta): {test:.4f}")
print(f" optimizm: {q.best_score_ - test:+.4f}")
print(" ⭐ Test to'plami faqat BIR MARTA ishlatiladi")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. O'quv va test ajratish (guruh bo'yicha) ===
o'quv 12820 qator (825 mijoz)
test 4215 qator (275 mijoz)
kesishgan mijozlar: 0
=== 2. Belgi tanlash (permutation, test qismida EMAS) ===
belgi muhimlik
ogirlik_masofaga +0.1435
hafta_kuni +0.0116
summa_nisbati +0.0116
summa +0.0059
soat +0.0051
hudud +0.0041
eng past uchtasi:
ogirlik -0.0041
mijoz_buyurtmalari -0.0044
kod -0.0062
muhimligi <= 0 bo'lganlar: 6 ta
=== 3. Tanlangan to'plamlarni CV da solishtirish ===
hammasi 17 belgi, CV 0.7072 (+-0.0169)
muhimlik > 0 11 belgi, CV 0.7128 (+-0.0141)
muhimlik > 0.002 9 belgi, CV 0.7136 (+-0.0107)
=== 4. Sozlash va yakuniy baho ===
eng yaxshi parametrlar: {'l2_regularization': 1.488, 'max_depth': 2, 'min_samples_leaf': 98}
ichki CV: 0.7386
TEST (bir marta): 0.7347
optimizm: +0.0039
⭐ Test to'plami faqat BIR MARTA ishlatiladiNima ko'rsatdi: 2.2, 2.4-bo'limlar.
Misol 4 — Yakuniy audit va paket
"""9-10 qadamlar: audit, lug'at va saqlash (real pandas/sklearn)."""
import io
import pickle
import numpy as np
import pandas as pd
import sklearn
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import (GroupKFold, GroupShuffleSplit,
cross_val_score)
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
def yarat(seed: int = 42, mijozlar: int = 900) -> pd.DataFrame:
rng = np.random.default_rng(seed)
qatorlar = []
boshlanish = pd.Timestamp("2025-01-01")
for m in range(mijozlar):
imzo = rng.normal(0, 1)
hudud = rng.choice(["toshkent", "samarqand", "buxoro", "fargona"])
hq = {"toshkent": 0.0, "samarqand": 0.5, "buxoro": 1.0,
"fargona": 0.3}[hudud]
odatiy = rng.lognormal(12.0, 0.45)
for _ in range(int(rng.integers(8, 24))):
sana = boshlanish + pd.Timedelta(days=int(rng.integers(0, 400)))
summa = odatiy * rng.lognormal(0, 0.5)
masofa = rng.gamma(2, 110)
ogirlik = rng.gamma(2, 5)
soat = int(rng.integers(0, 24))
kuch = (-1.9 + hq
+ 3.0 * (ogirlik / masofa > 0.085)
+ 0.9 * (7 <= soat <= 10)
+ 1.0 * (sana.dayofweek >= 5)
+ 1.6 * (summa > 1.15 * odatiy)
+ 1.8 * imzo)
qatorlar.append([m, sana, hudud, summa, masofa, ogirlik, soat,
int(rng.random() < 1 / (1 + np.exp(-kuch)))])
return pd.DataFrame(qatorlar, columns=["mijoz", "sana", "hudud", "summa",
"masofa", "ogirlik", "soat",
"kechikdi"]).sort_values(
["mijoz", "sana"]).reset_index(drop=True)
def belgilar_qosh(df: pd.DataFrame) -> pd.DataFrame:
df = df.copy()
df["ogirlik_masofaga"] = df["ogirlik"] / df["masofa"].clip(lower=1)
df["tigiz_soat"] = (((df["soat"] >= 7) & (df["soat"] <= 10))
| ((df["soat"] >= 17) & (df["soat"] <= 19))).astype(int)
df["hafta_oxiri"] = (df["sana"].dt.dayofweek >= 5).astype(int)
g = df.groupby("mijoz")
df["summa_oynasi"] = g["summa"].transform(
lambda s: s.shift(1).rolling(10, min_periods=2).mean())
df["summa_nisbati"] = df["summa"] / df["summa_oynasi"]
return df
def hajm_kb(obyekt) -> float:
b = io.BytesIO()
pickle.dump(obyekt, b, protocol=pickle.HIGHEST_PROTOCOL)
return b.tell() / 1024
def main() -> None:
df = belgilar_qosh(yarat())
y = df["kechikdi"].to_numpy()
guruh = df["mijoz"].to_numpy()
sonli = ["summa", "masofa", "ogirlik", "soat", "ogirlik_masofaga",
"tigiz_soat", "hafta_oxiri", "summa_oynasi", "summa_nisbati"]
kategoriya = ["hudud"]
tayyor = ColumnTransformer([
("s", "passthrough", sonli),
("k", OneHotEncoder(handle_unknown="ignore", sparse_output=False),
kategoriya)], verbose_feature_names_out=False)
quvur = Pipeline([("t", tayyor),
("m", HistGradientBoostingClassifier(
learning_rate=0.1, max_iter=250, max_depth=4,
min_samples_leaf=40, random_state=0))])
gss = GroupShuffleSplit(n_splits=1, test_size=0.25, random_state=0)
tr, te = next(gss.split(df, y, groups=guruh))
quvur.fit(df.iloc[tr], y[tr])
cv_ball = cross_val_score(quvur, df.iloc[tr], y[tr], cv=GroupKFold(4),
groups=guruh[tr], scoring="roc_auc")
test_ball = roc_auc_score(y[te], quvur.predict_proba(df.iloc[te])[:, 1])
print("=== 1. Yakuniy audit ===")
tekshiruvlar = []
tekshiruvlar.append(("Duplikatlar", f"{int(df.duplicated().sum())}",
"OK" if df.duplicated().sum() == 0 else "TOZALANSIN"))
eng_kuchli, eng_nom = 0.0, ""
for ustun in sonli:
b = cross_val_score(HistGradientBoostingClassifier(
learning_rate=0.1, max_iter=100, random_state=0),
df.iloc[tr][[ustun]], y[tr], cv=GroupKFold(4), groups=guruh[tr],
scoring="roc_auc").mean()
if b > eng_kuchli:
eng_kuchli, eng_nom = b, ustun
tekshiruvlar.append(("Eng kuchli yakka belgi", f"{eng_kuchli:.4f}",
"SHUBHALI" if eng_kuchli > 0.85 else "OK"))
tekshiruvlar.append(("Validatsiya strategiyasi", "GroupKFold", "OK"))
tekshiruvlar.append(("Tayyorlash Pipeline ichida", "ha", "OK"))
farq = cv_ball.mean() - test_ball
tekshiruvlar.append(("CV va test farqi", f"{farq:+.4f}",
"SHUBHALI" if abs(farq) > 0.05 else "OK"))
print(f" {'tekshiruv':<28} {'qiymat':>12} {'holat':<12}")
for nom, qiymat, holat in tekshiruvlar:
print(f" {nom:<28} {qiymat:>12} {holat:<12}")
print(f" (eng kuchli yakka belgi: {eng_nom})")
print("\n=== 2. Belgilar lug'ati ===")
lugat = {
"summa": ("buyurtma summasi", "buyurtma vaqtida"),
"masofa": ("yetkazish masofasi (km)", "buyurtma vaqtida"),
"ogirlik": ("yuk og'irligi (kg)", "buyurtma vaqtida"),
"soat": ("buyurtma soati", "buyurtma vaqtida"),
"ogirlik_masofaga": ("ogirlik / masofa", "buyurtma vaqtida"),
"tigiz_soat": ("tig'iz soatlar bayrog'i", "buyurtma vaqtida"),
"hafta_oxiri": ("shanba/yakshanba", "buyurtma vaqtida"),
"summa_oynasi": ("oldingi 10 buyurtma o'rtachasi (shift)",
"buyurtma vaqtida"),
"summa_nisbati": ("summa / oyna o'rtachasi", "buyurtma vaqtida"),
"hudud": ("yetkazish hududi", "buyurtma vaqtida"),
}
print(f" {'belgi':<18} {'ta_rif':<40} {'qachon ma_lum':<18}")
for nom, (tarif, qachon) in lugat.items():
print(f" {nom:<18} {tarif:<40} {qachon:<18}")
print("\n=== 3. Ishlab chiqarish paketi ===")
paket = {
"quvur": quvur,
"belgilar": sonli + kategoriya,
"lugat": {k: v[0] for k, v in lugat.items()},
"metrika": {"cv_auc": round(float(cv_ball.mean()), 4),
"cv_std": round(float(cv_ball.std()), 4),
"test_auc": round(float(test_ball), 4)},
"validatsiya": "GroupKFold(4) mijoz bo'yicha",
"versiyalar": {"sklearn": sklearn.__version__,
"numpy": np.__version__, "pandas": pd.__version__},
"sana": "2026-09-21",
}
print(f" kalitlar: {sorted(paket)}")
print(f" metrika: {paket['metrika']}")
print(f" paket hajmi: {hajm_kb(paket):.1f} KB")
print("\n=== 4. Ishlab chiqarishda tekshirish ===")
yangi = df.iloc[te].head(3).copy()
print(f" ustunlar mos: "
f"{all(c in yangi.columns for c in paket['belgilar'])}")
p = quvur.predict_proba(yangi)[:, 1]
print(f" bashoratlar: {np.round(p, 4).tolist()}")
yangi2 = yangi.copy()
yangi2["hudud"] = "andijon" # o'quvda yo'q kategoriya
print(f" yangi hudud bilan: "
f"{np.round(quvur.predict_proba(yangi2)[:, 1], 4).tolist()}")
yangi3 = yangi.copy()
yangi3.loc[:, "summa_oynasi"] = np.nan # birinchi buyurtma
yangi3.loc[:, "summa_nisbati"] = np.nan
print(f" NaN bilan (birinchi buyurtma): "
f"{np.round(quvur.predict_proba(yangi3)[:, 1], 4).tolist()}")
print(" ⭐ Lug'at + paket + audit = topshirishga tayyor natija")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Yakuniy audit ===
tekshiruv qiymat holat
Duplikatlar 0 OK
Eng kuchli yakka belgi 0.6583 OK
Validatsiya strategiyasi GroupKFold OK
Tayyorlash Pipeline ichida ha OK
CV va test farqi +0.0015 OK
(eng kuchli yakka belgi: ogirlik_masofaga)
=== 2. Belgilar lug'ati ===
belgi ta_rif qachon ma_lum
summa buyurtma summasi buyurtma vaqtida
masofa yetkazish masofasi (km) buyurtma vaqtida
ogirlik yuk og'irligi (kg) buyurtma vaqtida
soat buyurtma soati buyurtma vaqtida
ogirlik_masofaga ogirlik / masofa buyurtma vaqtida
tigiz_soat tig'iz soatlar bayrog'i buyurtma vaqtida
hafta_oxiri shanba/yakshanba buyurtma vaqtida
summa_oynasi oldingi 10 buyurtma o'rtachasi (shift) buyurtma vaqtida
summa_nisbati summa / oyna o'rtachasi buyurtma vaqtida
hudud yetkazish hududi buyurtma vaqtida
=== 3. Ishlab chiqarish paketi ===
kalitlar: ['belgilar', 'lugat', 'metrika', 'quvur', 'sana', 'validatsiya', 'versiyalar']
metrika: {'cv_auc': 0.7165, 'cv_std': 0.0038, 'test_auc': 0.715}
paket hajmi: 94.5 KB
=== 4. Ishlab chiqarishda tekshirish ===
ustunlar mos: True
bashoratlar: [0.4132, 0.5269, 0.9326]
yangi hudud bilan: [0.394, 0.5077, 0.9326]
NaN bilan (birinchi buyurtma): [0.4132, 0.5269, 0.8611]
⭐ Lug'at + paket + audit = topshirishga tayyor natijaNima ko'rsatdi: 2.4, 2.5, 2.6-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Ko'proq belgi — yaxshiroq" | Murakkablik bepul emas |
| "Belgilarni bitta-bitta sinash kerak" | Guruh bo'lib samaraliroq |
| "Validatsiyani keyinroq tanlaymiz" | Birinchi qaror |
| "To'xtash o'z-o'zidan bo'ladi" | Qoidani oldindan belgilang |
| "Audit ixtiyoriy" | Majburiy qadam |
| "Lug'at keraksiz byurokratiya" | Jamoaviy ishning asosi |
| "Test to'plamini bir necha marta" | Bir marta |
| "Yaxshilanish har doim foyda" | CV std bilan solishtiring |
6. Keng tarqalgan xatolar va yechimlari
1. Validatsiyani kech tanlash
# belgilar yaratib bo'lgandan keyin GroupKFold kerakligini bilib qolish # ⚠️
# 3-qadamda strategiyani aniqlang # ✅2. Belgilarni bitta-bitta qo'shish
for belgi in 40_ta_belgi: cross_val_score(...) # 40 ta CV # ⚠️
for guruh in 5_ta_guruh: cross_val_score(...) # 5 ta CV # ✅3. To'xtash qoidasisiz
# "yana bitta belgi sinab ko'raman" (30-marta) # ⚠️
# "2 guruh ketma-ket std dan kam bersa - to'xtayman" # ✅4. Auditni o'tkazib yuborish
# "CV 0.84, tayyor" # ⚠️
# yakka belgi AUC, CV/test farqi, leakage ro'yxati # ✅5. Lug'atsiz topshirish
# 40 ta belgi, nomlari x_1..x_40 # ⚠️
# har belgi uchun ta'rif, manba, "qachon ma'lum" # ✅6. Testni ko'p marta ishlatish
for variant in variantlar: print(roc_auc_score(yte, ...)) # ⚠️
# CV da tanlang, testda bir marta # ✅7. Ishlab chiqarishda hisoblanmaydigan belgi
df["30_kunlik_oyna"] = ... # real vaqtda hisoblanadimi? # ⚠️
# har belgi uchun hisoblash kodini/so'rovini yozing # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 17.1-17.9-darslar (o'tilgan): Butun qism
- 12.9-dars (o'tilgan): Leakage
- 15.13-dars (o'tilgan): Ishlab chiqarish
- 18-qism: Model baholash va sozlash
- 19-qism: scikit-learn to'liq
8. Eng yaxshi amaliyotlar
Auditdan boshlang.
Validatsiyani birinchi tanlang.
Guruh bo'lib qo'shing.
CV std bilan solishtiring.
To'xtash qoidasini belgilang.
Yakuniy auditni o'tkazing.
Belgilar lug'atini yozing.
Testni bir marta ishlating.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # oqimning birinchi qadami?
2. # eng muhim erta qaror?
3. # belgilar qanday qo'shiladi?
4. # yaxshilanish nima bilan solishtiriladi?
5. # to'xtash qoidasi qachon belgilanadi?
6. # odatiy foyda taqsimoti?
7. # shubhali belgi signali?
8. # belgi nomlari nima aytadi?
9. # lug'atda nima bo'ladi?
10. # test necha marta?
11. # paketda nima saqlanadi?
12. # ishlab chiqarishda nima tekshiriladi?Javoblar
- Audit
- Validatsiya strategiyasi
- Guruh bo'lib
- CV standart og'ishi
- Oldindan
- Birinchi 3-5 guruh — 80%
- Yakka AUC > 0.85
- "yopilish", "qaytarish" — leakage
- Ta'rif, manba, "qachon ma'lum"
- Bir marta
- Pipeline, belgilar, lug'at, metrika, versiyalar
- Ustunlar, yangi kategoriya, NaN ulushi
Vazifa 2: Xatolarni tuzating
1. # belgilar yaratilgandan keyin GroupKFold kerakligini bilish
2. for belgi in 40_ta: cross_val_score(...)
3. # "yana bitta belgi sinayman" (30-marta)
4. # "CV 0.84, tayyor"
5. for variant in variantlar: print(roc_auc_score(yte, ...))Javoblar
1. # validatsiya strategiyasini 3-qadamda aniqlang
2. for guruh in 5_ta_guruh: cross_val_score(...)
3. # to'xtash qoidasini oldindan belgilang
4. # yakuniy audit: yakka AUC, CV/test farqi, leakage
5. # CV da tanlang, testda bir martaVazifa 3: Audit
Modellang:
- Ustunlar
- Leakage
- Validatsiya
- Bazaviy
Vazifa 4: Guruhlar
Modellang:
- Bosqichma-bosqich
- CV std bilan
- Alohida hissa
- To'xtash
Vazifa 5: Tanlash
Modellang:
- Ajratish
- Permutation
- To'plamlar
- Sozlash va test
Vazifa 6: Paket
Modellang:
- Audit
- Lug'at
- Paket
- Ishlab chiqarish
Vazifa 7: O'ylash
Jamoa 180 ta belgi yaratdi, lekin 12 tasi natijaning 95% ini beradi. Qolgan 168 tasi bilan nima qilish kerak?
Javob
Qisqa javob: ularni o'chirmang, lekin modelga qo'shmang. Ular ikki qiymatga ega: kelajakdagi tajribalar uchun material va hujjatlashtirilgan salbiy natija.
1. Nega modelga qo'shmaslik kerak
| Narx | Izoh |
|---|---|
| Hisoblash | Har belgi ishlab chiqarishda hisoblanadi |
| Kechikish | 180 belgi 12 tadan sekinroq |
| Drift xavfi | Har belgi buzilishi mumkin (15.13) |
| Talqin | 180 belgili modelni tekshirib bo'lmaydi |
| Xatolar | Ko'proq kod — ko'proq xato |
Teng aniqlikda 12 ta belgi har doim afzal.
2. Nega o'chirmaslik kerak
- Kelajakdagi tajribalar: ma'lumot o'zgarganda ular foydali bo'lishi mumkin
- Boshqa vazifalar: bu loyihada foydasiz belgi boshqasida ishlashi mumkin
- Hujjatlashtirilgan bilim: "biz buni sinadik, ishlamadi" — qimmatli ma'lumot
- Kod bazasi: belgi yaratish funksiyalari qayta ishlatiladi
3. To'g'ri saqlash usuli
belgilar/
asosiy.py - 12 ta ishlatiladigan belgi (ishlab chiqarishda)
tajriba.py - 168 ta sinalgan belgi (ishlatilmaydi)
NATIJALAR.md - har guruhning CV hissasi va qarorNATIJALAR.md da: guruh nomi, belgilar soni, CV o'sishi, std, qaror va sabab.
4. Qayta ko'rib chiqish vaqti
- Ma'lumot manbai o'zgarganda
- Yangi ma'lumot turi qo'shilganda (masalan matn ustuni)
- Model natijasi tushganda
- Har 6-12 oyda bir marta
5. Xulosa
- Modelga faqat 12 tasini qo'ying
- Qolganlarini kod bazasida saqlang
- Salbiy natijalarni hujjatlashtiring
- Davriy ravishda qayta ko'rib chiqing
Nimani mustahkamlaydi: 2.3, 2.5-bo'limlar.
Xulosa
Bu darsda to'liq belgi muhandisligi loyihasini qurdik.
Eng muhim uch fikr:
Validatsiya strategiyasi — eng erta va eng muhim qaror. Guruh tuzilmasi bor bo'lsa
GroupKFold, vaqt bo'lsaTimeSeriesSplit. Noto'g'ri CV bilan qolgan barcha o'lchovlar ma'nosiz bo'ladi: bir mijozning buyurtmalari tasodifiy bo'linsa, model mijozni eslab qoladi va CV optimistik chiqadi — mijozga xos belgi qancha ko’p bo’lsa, farq shuncha katta (bitta CRM kodi ham 0.02-0.03 qo’shadi).Belgilarni guruh bo'lib qo'shing va CV std bilan solishtiring. "nisbatlar +0.011, vaqt +0.015, agregatsiya +0.010" degan jadval qaysi yo'nalishda davom etish kerakligini aniq ko'rsatadi. Yaxshilanish CV standart og'ishidan kichik bo'lsa — bu shovqin, va belgini qo'shish murakkablikni bepulga oshiradi.
To'xtash qoidasi va audit — majburiy. To'xtash nuqtasini oldindan belgilang ("2 guruh ketma-ket std dan kam bersa"), aks holda siz validatsiyaga overfitting qilasiz. Yakunda audit (duplikatlar, yakka belgi AUC, CV/test farqi), belgilar lug'ati ("qachon ma'lum bo'ladi?" javobi bilan) va
Pipelinepaketi topshiriladi.
Bu bilan 17-qism — Feature engineering yakunlandi. Keyingi qismda model baholash va sozlashni o'rganamiz: cross-validation strategiyalari, giperparametr qidiruvi va model taqqoslash.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!