Asosiy qismga o'tish

Mashq 3: yashirin leakage

43-bob 8 kod bloki 1729 so'z

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

Nega bu mashq

0-bobda agent_komissiyasi ustunini ko'rsatdim va "bu leakage" dedim. Oson edi — nomi ham, ma'nosi ham ochiq.

Bu mashqda men hech narsa aytmayman.

Faylda leakage bor. U ID ustuniga o'xshaydi — va siz "ID ni tashla" qoidasini bilasiz, demak uni tashlaysiz. Lekin savol boshqa: nega u leakage, va shu turdagi tuzoqni keyingi safar qanday topasiz?

Bundan tashqari faylda ikkinchi shubhali ustun bor. U leakage emas — u haqiqiy signal. Ikkisini ajratish — bu mashqning asosiy ishi.

Ma'lumot bilan tanishuv

python8 qator
import pandas as pd

td = pd.read_csv(DATA / "talaba_bitirdi.csv", keep_default_na=False, na_values=[""])
print("shakli:", td.shape)
print()
print(td.dtypes.to_string())
print()
show(td.head(8))
Chiqish
shakli: (900, 9)

talaba_id            object
kirish_bali           int64
davomat_foiz          int64
uy_vazifa_bali        int64
ishlaydi              int64
masofa_km           float64
oxirgi_tolov_oyi      int64
diplom_seriya        object
bitirdi               int64
talaba_idkirish_balidavomat_foizuy_vazifa_baliishlaydimasofa_kmoxirgi_tolov_oyidiplom_seriyabitirdi
T-5000062938203.610D-2000001
T-50001661006907.210D-2000011
T-50002581004212.49D-2000021
T-50003507510011610D-2000031
T-5000456885505.78D-2000041
T-5000548807407.512D-2000051
T-50006637974025.78D-2000061
T-5000781989516.614D-2000071
python8 qator
print("Target:")
print(td.bitirdi.value_counts(normalize=True).sort_index().round(4).to_string())
print()
print(f"BAZA (hammaga '1' desa): {td.bitirdi.mean():.4f}")
print()
yoq = td.isna().sum()
print("Bo'sh qiymatlar:")
print(yoq[yoq > 0].to_string() if (yoq > 0).any() else "  yo'q")
Chiqish
Target:
bitirdi
0    0.1144
1    0.8856

BAZA (hammaga '1' desa): 0.8856

Bo'sh qiymatlar:
diplom_seriya    103

Topshiriq

0-bobdagi 12 qadamni o'zingiz yuring. Hech kim sizga yo'l ko'rsatmaydi. Daftaringizga quyidagilarni yozib boring:

python15 qator
import pandas as pd
show(pd.DataFrame([
    {"#": 1, "Yozib qo'yiladigan javob": "Nechta qator, nechta ustun"},
    {"#": 2, "Yozib qo'yiladigan javob": "\"Men ___ ni ___ dan bashorat qilaman\" — bitta jumla"},
    {"#": 3, "Yozib qo'yiladigan javob": "Vazifa turi: regression / binary / multiclass"},
    {"#": 4, "Yozib qo'yiladigan javob": "Target nisbati va BAZA raqami"},
    {"#": 5, "Yozib qo'yiladigan javob": "Split qildingizmi? stratify kerakmi?"},
    {"#": 6, "Yozib qo'yiladigan javob": "Dummy natijasi"},
    {"#": 7, "Yozib qo'yiladigan javob": "Qaysi ustunlarni tashladingiz va NEGA"},
    {"#": 8, "Yozib qo'yiladigan javob": "Missing va turlar bilan nima qildingiz"},
    {"#": 9, "Yozib qo'yiladigan javob": "Birinchi halol natijangiz"},
    {"#": 10, "Yozib qo'yiladigan javob": "Qaysi metrikani tanladingiz va NEGA"},
    {"#": 11, "Yozib qo'yiladigan javob": "Xatolar qaysi guruhda to'plangan"},
    {"#": 12, "Yozib qo'yiladigan javob": "Qaysi BITTA o'zgarishni qildingiz va natija"},
]))
#Yozib qo'yiladigan javob
1Nechta qator, nechta ustun
2"Men ___ ni ___ dan bashorat qilaman" — bitta jumla
3Vazifa turi: regression / binary / multiclass
4Target nisbati va BAZA raqami
5Split qildingizmi? stratify kerakmi?
6Dummy natijasi
7Qaysi ustunlarni tashladingiz va NEGA
8Missing va turlar bilan nima qildingiz
9Birinchi halol natijangiz
10Qaysi metrikani tanladingiz va NEGA
11Xatolar qaysi guruhda to'plangan
12Qaysi BITTA o'zgarishni qildingiz va natija

Va eng muhim, 13-savol:

Qaysi gipotezangiz RAD ETILDI?

Agar bitta ham rad etilmagan bo'lsa — siz hech narsani sinab ko'rmadingiz. Qaytib boring.

Yagona ko'rsatma

Boshqa yordam bermayman. Faqat bitta narsa:

Har bir ustun uchun shu savolni bering

"Bashorat qilish PAYTIDA bu ustun menda bo'ladimi?"

Yangi talaba hozir o'qishga kirdi. Uning haqida qaysi ustunlar hoziroq ma'lum? Qaysi biri faqat keyinroq paydo bo'ladi?

Bu savol leakage ni ustun nomiga qaramasdan topadi.

Baza 0.8852 — accuracy sizni aldaydi

Target 88.6% "bitirdi". Demak "hammaga bitirdi" deydigan model ~0.885 oladi.

Agar sizning modelingiz 0.89 chiqarsa — bu deyarli hech narsa degani. Boshqa metrika kerak. Qaysi biri? 6 va 8-bobni qayta o'qing.

O'zingizni tekshirish

Avval o'zingiz ishlang. Rostdan ham. Keyin pastga qarang.

python17 qator
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.dummy import DummyClassifier
from sklearn.metrics import accuracy_score, f1_score, recall_score, precision_score

halol = ["kirish_bali", "davomat_foiz", "uy_vazifa_bali", "ishlaydi", "masofa_km"]
y = td["bitirdi"]
tr, te, ytr, yte = train_test_split(td, y, test_size=0.3, random_state=42, stratify=y)

baza = accuracy_score(yte, DummyClassifier(strategy="most_frequent").fit(tr[halol], ytr).predict(te[halol]))
m1 = LogisticRegression(max_iter=2000).fit(tr[halol], ytr)
b1 = m1.predict(te[halol])

print(f"BAZA                    : {baza:.4f}")
print(f"Halol 5 ustun — accuracy: {accuracy_score(yte, b1):.4f}   (farq {accuracy_score(yte, b1)-baza:+.4f})")
print(f"Halol 5 ustun — F1      : {f1_score(yte, b1):.4f}")
print(f"Halol 5 ustun — recall  : {recall_score(yte, b1):.4f}")
Chiqish
BAZA                    : 0.8852
Halol 5 ustun — accuracy: 0.8963   (farq +0.0111)
Halol 5 ustun — F1      : 0.9447
Halol 5 ustun — recall  : 1.0000

Mana birinchi dars: model bazadan atigi bir oz yuqori. Accuracy bu yerda deyarli foydasiz.

Endi tuzoqni ochamiz.

python10 qator
td2 = td.copy()
td2["diplom_bor"] = td2.diplom_seriya.notna().astype(int)
tr2, te2 = td2.loc[tr.index], td2.loc[te.index]

m2 = LogisticRegression(max_iter=2000).fit(tr2[halol + ["diplom_bor"]], ytr)
b2 = m2.predict(te2[halol + ["diplom_bor"]])
print(f"+ diplom_seriya (bor/yo'q): accuracy {accuracy_score(yte, b2):.4f}   <-- MUKAMMAL")
print()
print("Nega? Tekshiramiz:")
print(pd.crosstab(td2.diplom_bor, td2.bitirdi).to_string())
Chiqish
+ diplom_seriya (bor/yo'q): accuracy 1.0000   <-- MUKAMMAL

Nega? Tekshiramiz:
bitirdi       0    1
diplom_bor          
0           103    0
1             0  797

Mana. diplom_seriya faqat bitirganlarda bor.

Diqqat qiling: muammo ustun ID bo'lgani uchun emas. Muammo shundaki, uning bo'sh yoki bo'lmasligi target ni aytib turadi. Agar siz uni OneHotEncoder ga bersangiz ham, notna() qilsangiz ham — natija bir xil yolg'on bo'ladi.

Va mantiqan ham ochiq: diplom seriyasi bitirgandan KEYIN beriladi. Bashorat qilish paytida u yo'q.

Endi ikkinchi shubhali ustun.

python6 qator
m3 = LogisticRegression(max_iter=2000).fit(tr[halol + ["oxirgi_tolov_oyi"]], ytr)
b3 = m3.predict(te[halol + ["oxirgi_tolov_oyi"]])
print(f"+ oxirgi_tolov_oyi: accuracy {accuracy_score(yte, b3):.4f}  F1 {f1_score(yte, b3):.4f}")
print()
print("Guruhlar bo'yicha o'rtacha:")
print(td.groupby("bitirdi").oxirgi_tolov_oyi.agg(["mean", "min", "max"]).round(2).to_string())
Chiqish
+ oxirgi_tolov_oyi: accuracy 0.9037  F1 0.9465

Guruhlar bo'yicha o'rtacha:
          mean  min  max
bitirdi                 
0         7.71    2   14
1        11.05    6   14

Bu ustun ham target bilan bog'liq — bitirganlar ko'proq oy to'lagan. Lekin u leakage emas. Farqni ko'ring:

python10 qator
show(pd.DataFrame([
    {"Ustun": "diplom_seriya",
     "Target bilan bog'liq": "To'liq (100%)",
     "Bashorat paytida bormi": "YO'Q — bitirgandan keyin beriladi",
     "Hukmi": "LEAKAGE — tashlanadi"},
    {"Ustun": "oxirgi_tolov_oyi",
     "Target bilan bog'liq": "Qisman",
     "Bashorat paytida bormi": "HA — har oy ma'lum bo'ladi",
     "Hukmi": "Haqiqiy signal — ishlatiladi (lekin ehtiyot bilan)"},
]))
UstunTarget bilan bog'liqBashorat paytida bormiHukmi
diplom_seriyaTo'liq (100%)YO'Q — bitirgandan keyin beriladiLEAKAGE — tashlanadi
oxirgi_tolov_oyiQismanHA — har oy ma'lum bo'ladiHaqiqiy signal — ishlatiladi (lekin ehtiyot bilan)

"Target bilan bog'liq" va "leakage" bir xil narsa EMAS

Agar siz "target bilan kuchli bog'liq hamma ustunni tashlaymiz" qoidasini olsangiz — siz eng foydali xususiyatlarni tashlab yuborasiz. Model qurishdan maqsad aynan shunday ustunlarni topish.

Leakage ni ajratadigan savol bog'liqlik kuchi emas. Savol — vaqt: bu ma'lumot bashorat qilish paytida mavjudmi?

oxirgi_tolov_oyi uchun ehtiyot nuqtasi bor: agar siz semestr oxirida bashorat qilsangiz, u halol. Agar talaba birinchi kuni bashorat qilmoqchi bo'lsangiz — u ham leakage bo'ladi, chunki hali to'lov tarixi yo'q.

Demak leakage savolga bog'liq, ustunga emas.

Uch mashqdan keyin

python8 qator
show(pd.DataFrame([
    {"Mashq": "42. penguins", "Nimani sinadi": "Naqsh buzilishi — binary dan multiclass ga",
     "Asosiy dars": "average='macro' va 3x3 matritsa"},
    {"Mashq": "43. iflos savdo", "Nimani sinadi": "Tozalash ishning 80 foizi",
     "Asosiy dars": "Kirill/lotin, matn son, dublikat; va 'model qurib bo'lmaydi' halol xulosasi"},
    {"Mashq": "44. yashirin leakage", "Nimani sinadi": "Tuzoqni o'zingiz topish",
     "Asosiy dars": "Leakage ni VAQT savoli ajratadi, bog'liqlik kuchi emas"},
]))
MashqNimani sinadiAsosiy dars
42. penguinsNaqsh buzilishi — binary dan multiclass gaaverage='macro' va 3x3 matritsa
43. iflos savdoTozalash ishning 80 foiziKirill/lotin, matn son, dublikat; va 'model qurib bo'lmaydi' halol xulosasi
44. yashirin leakageTuzoqni o'zingiz topishLeakage ni VAQT savoli ajratadi, bog'liqlik kuchi emas

Agar uch mashqni ham o'zingiz yurib chiqqan bo'lsangiz — siz endi yangi dataset oldida to'xtamaydigan odam bo'ldingiz.

Protokolni esda tuting. Bazani birinchi o'lchang. Mukammal natijadan shubhalaning. Xatolarni o'qing. Va har bir rad etilgan gipotezani yozib qo'ying — ular sizning haqiqiy bilimingiz.

Bu bobni bepul o'qidingiz.

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

Telegramda yozish Narxlar