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.

🕑 12 daqiqa o‘qish 📄 887 so‘z 👁 5 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Bitta bo'linishning muammosi
  2. K-fold kross-validatsiya
  3. Validatsiya turlari
  4. Bir nechta metrika
  5. Siljish va tarqoqlik
  6. O'qitish egri chizig'i
  7. Validatsiya egri chizig'i
  8. Ma'lumot sizib chiqishi
  9. Belgi orqali sizib chiqish
  10. Uchta to'plam
  11. To'g'ri ish tartibi
  12. Xulosa

Bitta sinov to'plamidagi natija tasodifiy bo'lishi mumkin. Bu bo'limda modelni ishonchli baholashni o'rganamiz.

Bitta bo'linishning muammosi #

Python
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}")
Natija
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
0.921 dan 0.982 gacha - qaysi biri to'g'ri?

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 #

5-fold kross-validatsiya 1-bo'linish 0.96 2-bo'linish 0.94 3-bo'linish 0.98 4-bo'linish 0.95 5-bo'linish 0.97 O'rtacha: 0.960 ± 0.014 Qizil - sinov qismi · Ko'k - o'qitish qismi Har bir namuna bir marta sinovda, to'rt marta o'qitishda qatnashadi
Barcha ma'lumot ham o'qitishda, ham sinovda ishlatiladi
Python
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}")
Natija
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
Har doim standart og'ishni ham yozing

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 #

Python
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)
UsulQachon
KFoldRegressiya, umumiy holat
StratifiedKFoldKlassifikatsiya (standart)
TimeSeriesSplitVaqtga bog'liq ma'lumot
GroupKFoldBir bemorning bir necha yozuvi bo'lsa
LeaveOneOutJuda kam ma'lumot (100 dan kam)
Vaqt qatorlarida oddiy KFold ishlatmang
Python
# 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.

TimeSeriesSplit - o'qitish faqat o'tmishda 1-qadam 2-qadam 3-qadam 4-qadam Vaqt O'qitish oynasi o'sib boradi, sinov har doim kelajakda
Vaqt qatorlarida tartib buzilmasligi shart

Bir nechta metrika #

Python
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))
Natija
test_accuracy     0.958
test_precision    0.962
test_recall       0.975
test_f1           0.968
test_roc_auc      0.991

Siljish va tarqoqlik #

Siljish (bias) va tarqoqlik (variance) Yuqori siljish Bir joyda, lekin nishondan uzoq Yetarli o'qimagan Yuqori tarqoqlik Tarqoq, lekin nishon atrofida Qayta o'qigan Muvozanat Bir joyda va nishonda Yaxshi model Qanday tashxis qo'yiladi? O'qitishda ham, sinovda ham yomon → yuqori siljish → murakkabroq model kerak O'qitishda a'lo, sinovda yomon → yuqori tarqoqlik → ko'proq ma'lumot yoki regularizatsiya
Har qanday model xatosi shu ikki manbadan iborat
MuammoYechimlar
Yuqori siljishMurakkabroq model, yangi belgilar, regularizatsiyani kamaytirish
Yuqori tarqoqlikKo'proq ma'lumot, regularizatsiya, belgilarni kamaytirish, ansambl

O'qitish egri chizig'i #

Python
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()
O'qitish egri chizig'i nimani ko'rsatadi Ko'proq ma'lumot yordam beradi o'qitish validatsiya Chiziqlar hali yaqinlashmoqda Ma'lumot yig'ishni davom ettiring Ma'lumot yordam bermaydi o'qitish validatsiya Ikkalasi ham past va yonma-yon Model juda sodda - uni murakkablashtiring
Bu grafik "ko'proq ma'lumot kerakmi?" savoliga javob beradi
Amaliy foyda

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 #

Python
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}")
Natija
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.

Sizib chiqishning turlari
TurMisol
TayyorlashdaButun ma'lumotda fit_transform
Belgi orqalinarx_kategoriyasi belgisi narx dan hisoblangan
Vaqt orqaliKelajakdagi ma'lumot o'qitishga tushgan
Takrorlar orqaliBir xil qator ham o'qitishda, ham sinovda
Guruh orqaliBir bemorning yozuvlari ikkala to'plamda
Python
# 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}")
Pipeline - sizib chiqishga qarshi eng yaxshi himoya

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 #

Python
# 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.

Har bir belgi uchun savol bering

"Bashorat qilish paytida bu ma'lumot menda bormi?"

Agar javob "yo'q" bo'lsa - belgini olib tashlang.

Uchta to'plam #

Python
# 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)}")
Natija
O'qitish:    341
Validatsiya: 114
Sinov:       114
To'plamVazifasiNecha marta ishlatiladi
O'qitishModel parametrlarini topishKo'p
ValidatsiyaGiperparametrlarni tanlashKo'p
SinovYakuniy bahoBir marta
Sinov to'plamini bir marta ishlating

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 #

Python
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 va sinov natijasi

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.

Amaliy topshiriq
  1. Bitta modelni beshta turli random_state bilan sinang - farqni ko'ring.
  2. cross_val_score bilan 5-fold natijani oling.
  3. O'rtacha va standart og'ishni chiqaring.
  4. StratifiedKFold va oddiy KFold ni solishtiring.
  5. cross_validate bilan beshta metrikani birdan hisoblang.
  6. O'qitish egri chizig'ini chizing - ko'proq ma'lumot kerakmi?
  7. max_depth uchun validatsiya egri chizig'ini chizing.
  8. Ataylab sizib chiqish yarating (butun ma'lumotda fit_transform) va natijani Pipeline bilan solishtiring.
  9. Uchta to'plamga bo'ling va to'g'ri tartibda ishlang.
  10. 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'ish ko'rinishida yozing.
  • Klassifikatsiyada StratifiedKFold, vaqt qatorlarida TimeSeriesSplit.
  • 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; Pipeline undan 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.

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.