16-bo‘lim
Kross-validatsiya va qayta o'qitish
K-fold validatsiya, o'qitish egri chiziqlari, siljish va tarqoqlik muvozanati hamda ma'lumot sizib chiqishi.
Ushbu bo‘lim mundarijasi
Bitta sinov to'plamidagi natija tasodifiy bo'lishi mumkin. Bu bo'limda modelni ishonchli baholashni o'rganamiz.
Bitta bo'linishning muammosi #
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
X, y = load_breast_cancer(return_X_y=True)
for tasodif in [0, 1, 2, 3, 4]:
X_o, X_s, y_o, y_s = train_test_split(
X, y, test_size=0.2, random_state=tasodif
)
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_o, y_o)
print(f"random_state={tasodif}: aniqlik = {model.score(X_s, y_s):.3f}")
random_state=0: aniqlik = 0.947
random_state=1: aniqlik = 0.982
random_state=2: aniqlik = 0.965
random_state=3: aniqlik = 0.921
random_state=4: aniqlik = 0.974
Farq 6 foiz. Model o'zgarmadi, faqat bo'linish o'zgardi.
Agar hisobotda 0.982 ni yozsangiz - bu omadli tasodifni natija sifatida
ko'rsatish bo'lardi.
Yechim - kross-validatsiya.
K-fold kross-validatsiya #
from sklearn.model_selection import cross_val_score
model = RandomForestClassifier(n_estimators=100, random_state=42)
ballar = cross_val_score(model, X, y, cv=5, scoring="accuracy")
print(f"Har bir bo'linish: {ballar.round(3)}")
print(f"O'rtacha: {ballar.mean():.3f}")
print(f"Standart og'ish: {ballar.std():.3f}")
print(f"Ishonch oralig'i: {ballar.mean():.3f} ± {ballar.std() * 2:.3f}")
Har bir bo'linish: [0.939 0.947 0.965 0.965 0.973]
O'rtacha: 0.958
Standart og'ish: 0.013
Ishonch oralig'i: 0.958 ± 0.026
0.958 emas, 0.958 ± 0.013.
Katta og'ish (± 0.08) modelning beqarorligini bildiradi - u
ma'lumotning qaysi qismini ko'rganiga qarab juda farq qiladi.
Validatsiya turlari #
from sklearn.model_selection import (
KFold, StratifiedKFold, TimeSeriesSplit,
LeaveOneOut, GroupKFold, ShuffleSplit,
)
# Oddiy
kf = KFold(n_splits=5, shuffle=True, random_state=42)
# Sinf nisbatini saqlaydi - klassifikatsiya uchun standart
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
# Vaqt qatorlari uchun
tss = TimeSeriesSplit(n_splits=5)
# Har bir namuna alohida sinov - juda sekin
loo = LeaveOneOut()
# Guruhlar aralashmasin
gkf = GroupKFold(n_splits=5)
| Usul | Qachon |
|---|---|
KFold | Regressiya, umumiy holat |
StratifiedKFold | Klassifikatsiya (standart) |
TimeSeriesSplit | Vaqtga bog'liq ma'lumot |
GroupKFold | Bir bemorning bir necha yozuvi bo'lsa |
LeaveOneOut | Juda kam ma'lumot (100 dan kam) |
# XATO - kelajakdan o'tmishni bashorat qilish
cross_val_score(model, X, y, cv=KFold(5))
# TO'G'RI
cross_val_score(model, X, y, cv=TimeSeriesSplit(5))
Oddiy KFold modelga kelajakni ko'rsatadi va natija haqiqatdan
ancha yaxshi chiqadi.
Bir nechta metrika #
from sklearn.model_selection import cross_validate
natijalar = cross_validate(
model, X, y, cv=5,
scoring=["accuracy", "precision", "recall", "f1", "roc_auc"],
return_train_score=True,
)
import pandas as pd
jadval = pd.DataFrame(natijalar)
print(jadval[[u for u in jadval.columns if u.startswith("test_")]].mean().round(3))
test_accuracy 0.958
test_precision 0.962
test_recall 0.975
test_f1 0.968
test_roc_auc 0.991
Siljish va tarqoqlik #
| Muammo | Yechimlar |
|---|---|
| Yuqori siljish | Murakkabroq model, yangi belgilar, regularizatsiyani kamaytirish |
| Yuqori tarqoqlik | Ko'proq ma'lumot, regularizatsiya, belgilarni kamaytirish, ansambl |
O'qitish egri chizig'i #
from sklearn.model_selection import learning_curve
import matplotlib.pyplot as plt
olchamlar, ball_oqitish, ball_validatsiya = learning_curve(
RandomForestClassifier(n_estimators=100, random_state=42),
X, y, cv=5,
train_sizes=np.linspace(0.1, 1.0, 10),
n_jobs=-1,
)
plt.figure(figsize=(9, 5))
plt.plot(olchamlar, ball_oqitish.mean(axis=1), "o-", label="O'qitish")
plt.plot(olchamlar, ball_validatsiya.mean(axis=1), "o-", label="Validatsiya")
plt.fill_between(olchamlar,
ball_validatsiya.mean(axis=1) - ball_validatsiya.std(axis=1),
ball_validatsiya.mean(axis=1) + ball_validatsiya.std(axis=1),
alpha=0.15)
plt.xlabel("O'qitish namunalari soni")
plt.ylabel("Aniqlik")
plt.legend()
plt.grid(alpha=0.3)
plt.show()
Bu grafik juda qimmatli savolga javob beradi: "ma'lumot yig'ishga vaqt sarflaymizmi yoki modelni yaxshilaymizmi?"
- Chiziqlar orasida katta bo'shliq va validatsiya o'smoqda → ma'lumot yig'ing
- Chiziqlar yaqin va ikkalasi ham past → modelni murakkablashtiring
- Chiziqlar yaqin va ikkalasi ham yuqori → tayyor
Validatsiya egri chizig'i #
from sklearn.model_selection import validation_curve
from sklearn.tree import DecisionTreeClassifier
chuqurliklar = range(1, 21)
ball_o, ball_v = validation_curve(
DecisionTreeClassifier(random_state=42),
X, y,
param_name="max_depth",
param_range=chuqurliklar,
cv=5,
)
for chuqurlik, o, v in zip(chuqurliklar, ball_o.mean(axis=1), ball_v.mean(axis=1)):
if chuqurlik in [1, 2, 3, 5, 10, 20]:
print(f"chuqurlik={chuqurlik:2d} o'qitish={o:.3f} validatsiya={v:.3f}")
chuqurlik= 1 o'qitish=0.925 validatsiya=0.919
chuqurlik= 2 o'qitish=0.945 validatsiya=0.928
chuqurlik= 3 o'qitish=0.968 validatsiya=0.933
chuqurlik= 5 o'qitish=0.991 validatsiya=0.926
chuqurlik=10 o'qitish=1.000 validatsiya=0.919
chuqurlik=20 o'qitish=1.000 validatsiya=0.919
Eng yaxshi chuqurlik - 3. Undan keyin o'qitish o'sadi, validatsiya tushadi.
Ma'lumot sizib chiqishi #
Bu eng xavfli va eng ko'p uchraydigan xato.
| Tur | Misol |
|---|---|
| Tayyorlashda | Butun ma'lumotda fit_transform |
| Belgi orqali | narx_kategoriyasi belgisi narx dan hisoblangan |
| Vaqt orqali | Kelajakdagi ma'lumot o'qitishga tushgan |
| Takrorlar orqali | Bir xil qator ham o'qitishda, ham sinovda |
| Guruh orqali | Bir bemorning yozuvlari ikkala to'plamda |
# XATO
from sklearn.preprocessing import StandardScaler
X_masshtab = StandardScaler().fit_transform(X)
ballar = cross_val_score(model, X_masshtab, y, cv=5)
print(f"Sizib chiqish bilan: {ballar.mean():.3f}")
# TO'G'RI
from sklearn.pipeline import make_pipeline
quvur = make_pipeline(StandardScaler(), model)
ballar = cross_val_score(quvur, X, y, cv=5)
print(f"Pipeline bilan: {ballar.mean():.3f}")
Kross-validatsiyada Pipeline har bir bo'linish uchun qaytadan fit
qiladi. Bu qo'lda qilishda unutib qo'yiladigan qadam.
Qoida: barcha tayyorlash bosqichlarini Pipeline ichiga joylashtiring.
Belgi orqali sizib chiqish #
# Bemor kasalligini bashorat qilamiz
belgilar = [
"yosh", "bosim", "xolesterin",
"buyurilgan_dori", # SHUBHALI!
]
buyurilgan_dori faqat tashxis qo'yilgandan keyin ma'lum bo'ladi.
Model 99% aniqlik ko'rsatadi, lekin amalda foydasiz - bashorat vaqtida
bu ma'lumot yo'q.
"Bashorat qilish paytida bu ma'lumot menda bormi?"
Agar javob "yo'q" bo'lsa - belgini olib tashlang.
Uchta to'plam #
# 1. Avval sinov to'plamini ajratamiz va UNGA TEGMAYMIZ
X_toliq, X_sinov, y_toliq, y_sinov = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# 2. Qolganini o'qitish va validatsiyaga bo'lamiz
X_o, X_val, y_o, y_val = train_test_split(
X_toliq, y_toliq, test_size=0.25, random_state=42, stratify=y_toliq
)
print(f"O'qitish: {len(X_o)}")
print(f"Validatsiya: {len(X_val)}")
print(f"Sinov: {len(X_sinov)}")
O'qitish: 341
Validatsiya: 114
Sinov: 114
| To'plam | Vazifasi | Necha marta ishlatiladi |
|---|---|---|
| O'qitish | Model parametrlarini topish | Ko'p |
| Validatsiya | Giperparametrlarni tanlash | Ko'p |
| Sinov | Yakuniy baho | Bir marta |
Agar siz sinov natijasini ko'rib, keyin modelni o'zgartirsangiz - sinov to'plami validatsiyaga aylanadi va u endi xolis emas.
Bu "sinov to'plamiga qarash orqali qayta o'qitish" deb ataladi. Kaggle musobaqalarida jamoalar aynan shu sababdan yakuniy reytingda pastga tushadi.
To'g'ri ish tartibi #
from sklearn.model_selection import GridSearchCV
# 1. Sinov to'plamini ajratamiz
X_toliq, X_sinov, y_toliq, y_sinov = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# 2. Pipeline quramiz
quvur = make_pipeline(StandardScaler(), RandomForestClassifier(random_state=42))
# 3. Giperparametrlarni kross-validatsiya bilan tanlaymiz
tor = {
"randomforestclassifier__n_estimators": [50, 100, 200],
"randomforestclassifier__max_depth": [3, 5, 10, None],
}
qidiruv = GridSearchCV(quvur, tor, cv=5, n_jobs=-1, scoring="f1")
qidiruv.fit(X_toliq, y_toliq)
print(f"Eng yaxshi parametrlar: {qidiruv.best_params_}")
print(f"CV natijasi: {qidiruv.best_score_:.3f}")
# 4. Faqat endi sinov to'plamini ochamiz
print(f"Yakuniy sinov: {qidiruv.score(X_sinov, y_sinov):.3f}")
CV natijasi odatda biroz optimistik bo'ladi, chunki giperparametrlar aynan shu bo'linishlarga moslashtirilgan.
Farq 1-2 foiz bo'lsa - normal. 10 foiz bo'lsa - jiddiy muammo bor.
- Bitta modelni beshta turli
random_statebilan sinang - farqni ko'ring. cross_val_scorebilan 5-fold natijani oling.- O'rtacha va standart og'ishni chiqaring.
StratifiedKFoldva oddiyKFoldni solishtiring.cross_validatebilan beshta metrikani birdan hisoblang.- O'qitish egri chizig'ini chizing - ko'proq ma'lumot kerakmi?
max_depthuchun validatsiya egri chizig'ini chizing.- Ataylab sizib chiqish yarating (butun ma'lumotda
fit_transform) va natijani Pipeline bilan solishtiring. - Uchta to'plamga bo'ling va to'g'ri tartibda ishlang.
- Sizning loyihangizda "bashorat paytida bu ma'lumot bormi?" savolini har bir belgiga bering.
Xulosa #
- Bitta bo'linishdagi natija tasodifiy - unga ishonmang.
- Kross-validatsiya barcha ma'lumotdan foydalanib ishonchli baho beradi.
- Natijani har doim
o'rtacha ± og'ishko'rinishida yozing. - Klassifikatsiyada
StratifiedKFold, vaqt qatorlaridaTimeSeriesSplit. - Yuqori siljish: ikkalasida ham yomon → murakkabroq model.
- Yuqori tarqoqlik: o'qitishda a'lo, sinovda yomon → ko'proq ma'lumot yoki regularizatsiya.
- O'qitish egri chizig'i "ko'proq ma'lumot kerakmi?" savoliga javob beradi.
- Ma'lumot sizib chiqishi - eng xavfli xato;
Pipelineundan himoya qiladi. - Har bir belgi uchun so'rang: "bashorat paytida bu bormi?"
- Sinov to'plamini faqat bir marta, eng oxirida ishlating.
Keyingi bo'limda giperparametrlarni sozlashni chuqurroq ko'ramiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.