Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Dispersiya manbalari
- 2.2. Nima uchun std/sqrt(k) noto'g'ri
- 2.3. Fold soni ta'siri
- 2.4. Takroriy CV
- 2.5. Bias-dispersiya muvozanati
- 2.6. To'g'ri hisobot
- 2.7. Tuzoqlar
- 2.8. Ikki raqam: o'rtacha va noaniqlik
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Fold soni nimaga ta'sir qiladi
- Misol 2 — std/sqrt(k) nima uchun noto'g'ri
- Misol 3 — Takroriy CV
- Misol 4 — Dispersiya manbalarini ajratish
- 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
18.3-dars: CV dispersiyasi va necha fold
18-QISM — MODEL BAHOLASH VA SOZLASH · 3-dars
1. Kirish va motivatsiya
cross_val_score bir massiv qaytaradi va deyarli hamma shunday yozadi:
print(f"{ball.mean():.3f} +- {ball.std():.3f}")Bu qator noto'g'ri talqin qilinadi. Chiqqan std — foldlar orasidagi tarqoqlik, bahoning standart xatosi emas. Va std / sqrt(k) deb bo'lish ham noto'g'ri, chunki foldlar mustaqil emas: ular bir-biriga o'xshash o'quv to'plamlarini ishlatadi va xatolari korrelyatsiyali.
Ikkinchi savol — necha fold. 5 mi, 10 mi, 20 mi? Javob "ko'proq yaxshiroq" emas: fold soni ortgani sari bias kamayadi, lekin narx chiziqli o'sadi va bahoning dispersiyasi ma'lum nuqtadan keyin kamaymaydi.
Bu darsda: CV bahosining dispersiya manbalari, fold soni ta'siri, takroriy CV, nima uchun oddiy std/sqrt(k) ishlamaydi va CV natijasini to'g'ri hisobot qilish.
Real vaziyat. Maqolada "yangi usul 0.847, bazaviy 0.839, ya'ni 0.008 yaxshi" deyilgan. Sharhlovchi bir savol berdi: "CV ni 10 ta boshqa seed bilan takrorlang". Takrorlanganda bazaviy 0.841 ± 0.006, yangi usul 0.845 ± 0.007 chiqdi — farq shovqin ichida qoldi va maqola qayta yozildi.
Bu darsda CV dispersiyasini o'rganamiz.
Bu darsda:
- Dispersiya manbalari
- Nima uchun std/sqrt(k) noto'g'ri
- Fold soni ta'siri
- Takroriy CV
- Bias-dispersiya muvozanati
- To'g'ri hisobot
- Tuzoqlar
- Amaliy: ishonchli taqqoslash
ℹ Misollar real numpy/sklearn bilan (Python 3.14).
2. Nazariya — chuqur tushuntirish
2.1. Dispersiya manbalari
CV bahosi uchta manbadan tebranadi:
1. MA'LUMOT tasodifiyligi
sizdagi n qator - katta populyatsiyadan bitta namuna
boshqa namunada natija boshqacha bo'lardi
2. BO'LINISH tasodifiyligi
qaysi qator qaysi foldga tushdi (random_state)
3. MODEL tasodifiyligi
RF, boosting, SGD, neyron tarmoq - ichki seed
TAKRORIY CV faqat 2-manbani kamaytiradi.
1-manba faqat ko'proq MA'LUMOT bilan kamayadi.Takroriy CV bahoni "aniqroq" qilmaydi, u faqat bo'linish shovqinini kamaytiradi — ma'lumot namunasidan kelgan noaniqlik qoladi.
2.2. Nima uchun std/sqrt(k) noto'g'ri
Mustaqil o'lchovlar uchun: SE = std / sqrt(k)
LEKIN CV foldlari MUSTAQIL EMAS:
5-fold da har ikki o'quv to'plami qatorlarining
~75% ini BAHAM ko'radi -> fold ballari korrelyatsiyali
ya'ni formulaning SHARTI buzilgan
IKKI BOSHQA NARSA BOR:
A. bo'linish shovqini - "boshqa CV seed olsam?"
odatda KICHIK (takroriy CV uni yanada kamaytiradi)
B. ma'lumot shovqini - "boshqa ma'lumot yig'sam?"
hisobotdagi ishonch oralig'i AYNAN shuni bildirishi kerak
std/sqrt(k) na A ni, na B ni o'lchaydi:
ba'zan B ga yaqin chiqadi, ba'zan ikki barobar adashadi
(Bengio & Grandvalet 2004: k-fold CV dispersiyasining
xolis baholovchisi UMUMAN mavjud emas)
TO'G'RI YO'L:
- alohida test to'plamining SE si (eng ishonchli)
- takroriy CV -> takrorlar orasidagi tarqoqlik (A uchun)
- konservativ: fold std ning o'zini ishlating std / sqrt(k) — ishonch oralig'i emas: uning shartlari buzilgan va u qaysi noaniqlikni o'lchayotgani aniq emas.
2.3. Fold soni ta'siri
k kichik (2-3):
o'quv to'plami kichik -> model zaifroq -> baho PESSIMISTIK
foldlar mustaqilroq
k katta (10-20):
o'quv to'plami to'liqqa yaqin -> bias kichik
foldlar juda o'xshash -> korrelyatsiya yuqori
narx k barobar
k = n (LeaveOneOut):
bias eng kichik, dispersiya eng katta, narx eng yuqori
AMALIYOT:
n > 5000 -> k = 5 yetarli
n 1000-5000 -> k = 5 yoki 10
n < 1000 -> k = 10 + takrorlashk = 5 amaliyotda deyarli har doim yetarli: 10 ga oshirish bias ni biroz kamaytiradi, lekin narxni ikki barobar oshiradi.
2.4. Takroriy CV
RepeatedStratifiedKFold(n_splits=5, n_repeats=R)
Har takror - boshqa aralashtirish:
R=1 -> 5 ta o'lchov, bahoning std i katta
R=5 -> 25 ta o'lchov
R=10 -> 50 ta o'lchov
BAHONING std i taxminan 1/sqrt(R) kabi kamayadi
(lekin ma'lumot shovqiniga BORIB TO'XTAYDI)
TAKRORLAR o'rtachalari orasidagi std - bo'linish
shovqinining to'g'ri o'lchoviTakrorlar o'rtachalarining tarqoqligi — "agar boshqa seed olsam, natija qancha o'zgarardi?" degan savolga to'g'ri javob.
2.5. Bias-dispersiya muvozanati
bias dispersiya narx
k = 2 yuqori o'rta 1x
k = 5 o'rta o'rta 2.5x
k = 10 past o'rta 5x
k = n (LOO) eng past yuqori n/2 x
MA'LUMOT KAM bo'lsa bias muhimroq -> k kattaroq
MA'LUMOT KO'P bo'lsa bias kichik -> k = 5
ESLATMA: o'rganish egri chizig'i tekis bo'lsa
(18.8-dars), k ning ta'siri deyarli yo'qk ning ta'siri o'rganish egri chizig'iga bog'liq: model 80% ma'lumotda 90% dagidek ishlasa, k = 5 va k = 10 farq qilmaydi.
2.6. To'g'ri hisobot
YOZING:
- strategiya: StratifiedKFold(5, shuffle=True, random_state=0)
- takrorlar: 5
- o'rtacha va TAKRORLAR orasidagi std
- alohida test natijasi (bor bo'lsa)
- sinalgan nomzodlar soni
YOZMANG:
"AUC 0.8472 +- 0.0031" (std/sqrt(k) dan olingan)
YAXSHIROQ:
"5x5 takroriy CV: 0.847 (takrorlar bo'yicha std 0.006),
alohida testda 0.843" Raqamni uch xonagacha yaxlitlang: CV bahosi to'rtinchi xonagacha aniq emas, 0.8472 yozish soxta aniqlik beradi.
2.7. Tuzoqlar
Asosiy tuzoqlar: std/sqrt(k) ni SE deb ishlatish; foldlar orasidagi std ni bahoning noaniqligi deb o'ylash; bitta CV natijasiga asoslanib qaror qabul qilish; k ni "ko'proq yaxshiroq" deb oshirish; takroriy CV ni ma'lumot shovqinini ham kamaytiradi deb o'ylash; to'rt xonali aniqlik e'lon qilish; turli seed li natijalarni taqqoslash.
2.8. Ikki raqam: o'rtacha va noaniqlik
CV natijasi bitta raqam emas — u o'rtacha va noaniqlik juftligi. Noaniqlikni to'g'ri o'lchash uchun takroriy CV ishlating va takrorlar o'rtachalari orasidagi tarqoqlikni yozing; foldlar korrelyatsiyali bo'lgani uchun std/sqrt(k) haqiqiy noaniqlikni past ko'rsatadi. k = 5 ko'p hollarda yetarli; kichik ma'lumotda k = 10 va takrorlash. Ikki modelni taqqoslashda farq noaniqlikdan katta bo'lishi shart.
3. Tez ma'lumotnoma
import numpy as np
from sklearn.model_selection import RepeatedStratifiedKFold, cross_val_score
cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=5, random_state=0)
ball = cross_val_score(model, X, y, cv=cv, scoring="roc_auc")
# takrorlar bo'yicha o'rtachalar (5 ta)
takrorlar = ball.reshape(5, 5).mean(axis=1)
print(f"{ball.mean():.3f}, takrorlar std: {takrorlar.std():.4f}")
# NOTO'G'RI: ball.std() / np.sqrt(len(ball))
# TO'G'RI: takrorlar.std() yoki konservativ ball.std()
QOIDA: takroriy CV · takrorlar std i · uch xona ·
farq noaniqlikdan katta bo'lsinCV dispersiyasi xulosasi
Dispersiya manbalari: ma'lumot, bo'linish, model
Takroriy CV faqat bo'linish shovqinini kamaytiradi
std/sqrt(k) - noto'g'ri (foldlar korrelyatsiyali)
k = 5 odatda yetarli; kichik ma'lumotda 10 + takror4. Batafsil misollar
Misollar real numpy/sklearn bilan (Python 3.14).
Misol 1 — Fold soni nimaga ta'sir qiladi
"""k ning bias, dispersiya va narxga ta'siri (real numpy/sklearn)."""
import numpy as np
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
def model():
return make_pipeline(StandardScaler(),
LogisticRegression(max_iter=2000))
def main() -> None:
X, y = make_classification(n_samples=21000, n_features=20,
n_informative=6, n_redundant=4,
flip_y=0.15, class_sep=0.9, random_state=0)
X_ish, y_ish = X[:1000], y[:1000] # mavjud ma'lumot
X_haq, y_haq = X[1000:], y[1000:] # 'haqiqat' to'plami
m = model().fit(X_ish, y_ish)
haqiqiy = roc_auc_score(y_haq, m.predict_proba(X_haq)[:, 1])
print("=== 1. Sozlama ===")
print(f" mavjud: {len(y_ish)} qator, 'haqiqat': {len(y_haq)} qator")
print(f" to'liq ma'lumotda o'rgatilgan model: {haqiqiy:.4f}")
print("\n=== 2. Fold soni va baho ===")
print(f" {'k':>4} {'CV o_rtacha':>12} {'fold std':>10} "
f"{'haqiqiydan farq':>17} {'modellar':>9}")
for k in [2, 3, 5, 10, 20]:
b = cross_val_score(model(), X_ish, y_ish,
cv=StratifiedKFold(k, shuffle=True,
random_state=0),
scoring="roc_auc")
print(f" {k:>4} {b.mean():>12.4f} {b.std():>10.4f} "
f"{b.mean() - haqiqiy:>+17.4f} {k:>9}")
print(" k kichik -> o'quv to'plami kichik -> baho pastroq (bias)")
print("\n=== 3. Bahoning barqarorligi (20 ta seed) ===")
print(f" {'k':>4} {'baho o_rtachasi':>16} {'bahoning std i':>16}")
for k in [2, 3, 5, 10, 20]:
ballar = [cross_val_score(model(), X_ish, y_ish,
cv=StratifiedKFold(k, shuffle=True,
random_state=s),
scoring="roc_auc").mean()
for s in range(20)]
print(f" {k:>4} {np.mean(ballar):>16.4f} {np.std(ballar):>16.5f}")
print(" k oshgani sari bahoning tebranishi kamayadi, lekin")
print(" ma'lum nuqtadan keyin to'xtaydi")
print("\n=== 4. Ma'lumot hajmi k ning ahamiyatini kamaytiradi ===")
print(f" {'n':>7} {'k=2':>9} {'k=5':>9} {'k=10':>9} {'k=2 va k=10':>13}")
for n in [300, 1000, 4000]:
Xn, yn = X[:n], y[:n]
ballar = {}
for k in [2, 5, 10]:
ballar[k] = cross_val_score(model(), Xn, yn,
cv=StratifiedKFold(k, shuffle=True,
random_state=0),
scoring="roc_auc").mean()
print(f" {n:>7} {ballar[2]:>9.4f} {ballar[5]:>9.4f} "
f"{ballar[10]:>9.4f} {ballar[10] - ballar[2]:>+13.4f}")
print(" ⭐ k = 5 amaliyotda deyarli har doim yetarli")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Sozlama ===
mavjud: 1000 qator, 'haqiqat': 20000 qator
to'liq ma'lumotda o'rgatilgan model: 0.8280
=== 2. Fold soni va baho ===
k CV o_rtacha fold std haqiqiydan farq modellar
2 0.8372 0.0042 +0.0091 2
3 0.8315 0.0056 +0.0034 3
5 0.8279 0.0158 -0.0001 5
10 0.8291 0.0266 +0.0010 10
20 0.8291 0.0513 +0.0011 20
k kichik -> o'quv to'plami kichik -> baho pastroq (bias)
=== 3. Bahoning barqarorligi (20 ta seed) ===
k baho o_rtachasi bahoning std i
2 0.8261 0.00558
3 0.8286 0.00324
5 0.8295 0.00239
10 0.8299 0.00207
20 0.8303 0.00242
k oshgani sari bahoning tebranishi kamayadi, lekin
ma'lum nuqtadan keyin to'xtaydi
=== 4. Ma'lumot hajmi k ning ahamiyatini kamaytiradi ===
n k=2 k=5 k=10 k=2 va k=10
300 0.8025 0.8334 0.8416 +0.0391
1000 0.8372 0.8279 0.8291 -0.0081
4000 0.8288 0.8312 0.8327 +0.0040
⭐ k = 5 amaliyotda deyarli har doim yetarliNima ko'rsatdi: 2.3, 2.5-bo'limlar.
Misol 2 — std/sqrt(k) nima uchun noto'g'ri
"""Uch xil 'noaniqlik' va naiv formula (real numpy/sklearn)."""
import numpy as np
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
def model():
return make_pipeline(StandardScaler(),
LogisticRegression(max_iter=2000))
N = 800 # bitta ma'lumot to'plamining hajmi
def main() -> None:
# katta "populyatsiya", undan mustaqil namunalar olamiz
X_pool, y_pool = make_classification(n_samples=60000, n_features=20,
n_informative=6, n_redundant=4,
flip_y=0.15, class_sep=0.9,
random_state=0)
rng = np.random.default_rng(0)
X, y = X_pool[:N], y_pool[:N]
print("=== 1. Bitta CV natijasi ===")
b = cross_val_score(model(), X, y,
cv=StratifiedKFold(5, shuffle=True, random_state=0),
scoring="roc_auc")
print(f" fold ballari: {np.round(b, 4).tolist()}")
print(f" o'rtacha: {b.mean():.4f}")
print(f" fold std: {b.std(ddof=1):.4f}")
naiv = float(b.std(ddof=1) / np.sqrt(5))
print(f" naiv 'SE' = std/sqrt(5): {naiv:.4f}")
print("\n=== 2. A: faqat BO'LINISH shovqini ===")
bolinish = np.array([cross_val_score(
model(), X, y,
cv=StratifiedKFold(5, shuffle=True, random_state=s),
scoring="roc_auc").mean() for s in range(150)])
print(f" bitta ma'lumot, 150 ta turli CV seed")
print(f" bahoning std i: {bolinish.std(ddof=1):.4f}")
print(" bu FAQAT 'boshqa seed olsam nima bo'lardi' savoliga javob")
print("\n=== 3. B: MA'LUMOT namunasi shovqini ===")
namunalar = []
for _ in range(150):
idx = rng.choice(len(y_pool), N, replace=False)
namunalar.append(cross_val_score(
model(), X_pool[idx], y_pool[idx],
cv=StratifiedKFold(5, shuffle=True, random_state=0),
scoring="roc_auc").mean())
namunalar = np.array(namunalar)
print(f" 150 ta MUSTAQIL ma'lumot to'plami (n={N})")
print(f" bahoning std i: {namunalar.std(ddof=1):.4f}")
print(" bu 'boshqa ma'lumot yig'sam nima bo'lardi' savoliga javob")
print(" hisobotdagi ishonch oralig'i AYNAN shuni aks ettirishi kerak")
print("\n=== 4. Uch raqamni taqqoslash ===")
print(f" {'usul':<38} {'qiymat':>9}")
print(f" {'naiv std/sqrt(k)':<38} {naiv:>9.4f}")
print(f" {'A: bo_linish shovqini':<38} "
f"{bolinish.std(ddof=1):>9.4f}")
print(f" {'B: ma_lumot shovqini (MUHIMI)':<38} "
f"{namunalar.std(ddof=1):>9.4f}")
print(f" {'fold std (konservativ)':<38} {b.std(ddof=1):>9.4f}")
print(f" naiv / B nisbati: {naiv / namunalar.std(ddof=1):.2f}")
print(" naiv formula A ni ham, B ni ham o'lchamaydi -")
print(" u shunchaki BOSHQA kattalik va unga ishonib bo'lmaydi")
print("\n=== 5. Ma'lumot hajmi ortganda ===")
print(f" {'n':>6} {'naiv SE':>9} {'B (haqiqiy)':>13} "
f"{'naiv/B':>8}")
for n in [400, 800, 1600]:
Xn, yn = X_pool[:n], y_pool[:n]
bn = cross_val_score(model(), Xn, yn,
cv=StratifiedKFold(5, shuffle=True,
random_state=0),
scoring="roc_auc")
naiv_n = float(bn.std(ddof=1) / np.sqrt(5))
ballar = []
for _ in range(80):
idx = rng.choice(len(y_pool), n, replace=False)
ballar.append(cross_val_score(
model(), X_pool[idx], y_pool[idx],
cv=StratifiedKFold(5, shuffle=True, random_state=0),
scoring="roc_auc").mean())
haqiqiy_n = float(np.std(ballar, ddof=1))
print(f" {n:>6} {naiv_n:>9.4f} {haqiqiy_n:>13.4f} "
f"{naiv_n / haqiqiy_n:>7.2f}")
print(" ⭐ std/sqrt(k) ni ishonch oralig'i sifatida yozmang")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Bitta CV natijasi ===
fold ballari: [0.7729, 0.8436, 0.8339, 0.7731, 0.8336]
o'rtacha: 0.8114
fold std: 0.0353
naiv 'SE' = std/sqrt(5): 0.0158
=== 2. A: faqat BO'LINISH shovqini ===
bitta ma'lumot, 150 ta turli CV seed
bahoning std i: 0.0034
bu FAQAT 'boshqa seed olsam nima bo'lardi' savoliga javob
=== 3. B: MA'LUMOT namunasi shovqini ===
150 ta MUSTAQIL ma'lumot to'plami (n=800)
bahoning std i: 0.0169
bu 'boshqa ma'lumot yig'sam nima bo'lardi' savoliga javob
hisobotdagi ishonch oralig'i AYNAN shuni aks ettirishi kerak
=== 4. Uch raqamni taqqoslash ===
usul qiymat
naiv std/sqrt(k) 0.0158
A: bo_linish shovqini 0.0034
B: ma_lumot shovqini (MUHIMI) 0.0169
fold std (konservativ) 0.0353
naiv / B nisbati: 0.93
naiv formula A ni ham, B ni ham o'lchamaydi -
u shunchaki BOSHQA kattalik va unga ishonib bo'lmaydi
=== 5. Ma'lumot hajmi ortganda ===
n naiv SE B (haqiqiy) naiv/B
400 0.0157 0.0224 0.70
800 0.0158 0.0133 1.18
1600 0.0180 0.0105 1.71
⭐ std/sqrt(k) ni ishonch oralig'i sifatida yozmangNima ko'rsatdi: 2.2-bo'lim.
Misol 3 — Takroriy CV
"""Takrorlar sonining bahoga ta'siri (real numpy/sklearn)."""
import numpy as np
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import RepeatedStratifiedKFold, cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
def model():
return make_pipeline(StandardScaler(),
LogisticRegression(max_iter=2000))
def main() -> None:
X, y = make_classification(n_samples=400, n_features=18, n_informative=6,
flip_y=0.15, class_sep=0.95, random_state=0)
print("=== 1. Kichik ma'lumot ===")
print(f" {len(y)} qator, {X.shape[1]} belgi")
print("\n=== 2. Takrorlar soni va bahoning barqarorligi ===")
print(f" {'R':>4} {'o_lchovlar':>11} {'baho':>9} "
f"{'bahoning std i':>16} {'narx':>7}")
for R in [1, 2, 5, 10, 20]:
ballar = []
for s in range(15):
cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=R,
random_state=s)
ballar.append(cross_val_score(model(), X, y, cv=cv,
scoring="roc_auc").mean())
print(f" {R:>4} {5 * R:>11} {np.mean(ballar):>9.4f} "
f"{np.std(ballar, ddof=1):>16.5f} {5 * R:>5}x")
print(" std ~ 1/sqrt(R) kabi kamayadi, lekin nolga tushmaydi")
print("\n=== 3. Takrorlar orasidagi tarqoqlik ===")
R = 10
cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=R, random_state=0)
b = cross_val_score(model(), X, y, cv=cv, scoring="roc_auc")
takrorlar = b.reshape(R, 5).mean(axis=1)
print(f" jami o'lchov: {len(b)}")
print(f" takror o'rtachalari: {np.round(takrorlar[:5], 4).tolist()} ...")
print(f" umumiy o'rtacha: {b.mean():.4f}")
print(f" fold std (barcha 50 o'lchov): {b.std(ddof=1):.4f}")
print(f" TAKRORLAR std i: {takrorlar.std(ddof=1):.4f} <- to'g'ri o'lchov")
print("\n=== 4. Ikki modelni taqqoslash ===")
modellar = {
"C=0.03": make_pipeline(StandardScaler(),
LogisticRegression(C=0.03, max_iter=2000)),
"C=1.0": make_pipeline(StandardScaler(),
LogisticRegression(C=1.0, max_iter=2000)),
}
cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=10, random_state=0)
natija = {}
for nom, m in modellar.items():
bb = cross_val_score(m, X, y, cv=cv, scoring="roc_auc")
natija[nom] = bb.reshape(10, 5).mean(axis=1)
print(f" {nom:<8} {bb.mean():.4f} "
f"(takrorlar std {natija[nom].std(ddof=1):.4f})")
farq = natija["C=1.0"] - natija["C=0.03"]
print(f" juftlashgan farq: {farq.mean():+.4f} "
f"(std {farq.std(ddof=1):.4f})")
muhim = abs(farq.mean()) > 2 * farq.std(ddof=1) / np.sqrt(len(farq))
print(f" farq shovqindan katta: {muhim}")
print(" ⭐ Juftlashgan farq alohida o'rtachalardan ishonchliroq")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Kichik ma'lumot ===
400 qator, 18 belgi
=== 2. Takrorlar soni va bahoning barqarorligi ===
R o_lchovlar baho bahoning std i narx
1 5 0.7947 0.00805 5x
2 10 0.7940 0.00520 10x
5 25 0.7919 0.00362 25x
10 50 0.7905 0.00198 50x
20 100 0.7905 0.00173 100x
std ~ 1/sqrt(R) kabi kamayadi, lekin nolga tushmaydi
=== 3. Takrorlar orasidagi tarqoqlik ===
jami o'lchov: 50
takror o'rtachalari: [0.8049, 0.7979, 0.7992, 0.7809, 0.7985] ...
umumiy o'rtacha: 0.7941
fold std (barcha 50 o'lchov): 0.0492
TAKRORLAR std i: 0.0066 <- to'g'ri o'lchov
=== 4. Ikki modelni taqqoslash ===
C=0.03 0.7822 (takrorlar std 0.0058)
C=1.0 0.7941 (takrorlar std 0.0066)
juftlashgan farq: +0.0119 (std 0.0030)
farq shovqindan katta: True
⭐ Juftlashgan farq alohida o'rtachalardan ishonchliroqNima ko'rsatdi: 2.1, 2.4-bo'limlar.
Misol 4 — Dispersiya manbalarini ajratish
"""Ma'lumot, bo'linish va model shovqini (real numpy/sklearn)."""
import numpy as np
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold, cross_val_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
def yarat(seed: int, n: int = 600):
return make_classification(n_samples=n, n_features=18, n_informative=6,
n_redundant=4, flip_y=0.15, class_sep=0.9,
random_state=seed)
def main() -> None:
print("=== 1. Manba A: MA'LUMOT namunasi ===")
ballar = []
for seed in range(30):
X, y = yarat(seed)
m = make_pipeline(StandardScaler(),
LogisticRegression(max_iter=2000))
ballar.append(cross_val_score(
m, X, y, cv=StratifiedKFold(5, shuffle=True, random_state=0),
scoring="roc_auc").mean())
manba_a = float(np.std(ballar, ddof=1))
print(f" 30 ta turli ma'lumot to'plami (CV seed qat'iy)")
print(f" bahoning std i: {manba_a:.4f}")
print("\n=== 2. Manba B: BO'LINISH tasodifiyligi ===")
X, y = yarat(0)
ballar = []
for s in range(30):
m = make_pipeline(StandardScaler(),
LogisticRegression(max_iter=2000))
ballar.append(cross_val_score(
m, X, y, cv=StratifiedKFold(5, shuffle=True, random_state=s),
scoring="roc_auc").mean())
manba_b = float(np.std(ballar, ddof=1))
print(f" bitta ma'lumot, 30 ta turli CV seed")
print(f" bahoning std i: {manba_b:.4f}")
print("\n=== 3. Manba C: MODEL tasodifiyligi ===")
ballar = []
for s in range(30):
m = RandomForestClassifier(n_estimators=100, min_samples_leaf=3,
random_state=s, n_jobs=1)
ballar.append(cross_val_score(
m, X, y, cv=StratifiedKFold(5, shuffle=True, random_state=0),
scoring="roc_auc").mean())
manba_c = float(np.std(ballar, ddof=1))
print(f" bitta ma'lumot, bitta CV seed, 30 ta model seed")
print(f" bahoning std i: {manba_c:.4f}")
print("\n=== 4. Taqqoslash va xulosa ===")
print(f" {'manba':<28} {'std':>9} {'kamaytirish usuli':<26}")
print(f" {'A. ma_lumot namunasi':<28} {manba_a:>9.4f} "
f"{'ko_proq ma_lumot':<26}")
print(f" {'B. bo_linish (CV seed)':<28} {manba_b:>9.4f} "
f"{'takroriy CV':<26}")
print(f" {'C. model seed (RF)':<28} {manba_c:>9.4f} "
f"{'kop daraxt / seed o_rtacha':<26}")
eng = max([("A", manba_a), ("B", manba_b), ("C", manba_c)],
key=lambda kv: kv[1])
print(f" eng katta manba: {eng[0]} ({eng[1]:.4f})")
print(" takroriy CV faqat B ni kamaytiradi")
print(" ⭐ Eng katta manbani bilmasangiz, noto'g'ri narsani tuzatasiz")
if __name__ == "__main__":
main()Natijaning muhim qismi:
=== 1. Manba A: MA'LUMOT namunasi ===
30 ta turli ma'lumot to'plami (CV seed qat'iy)
bahoning std i: 0.0701
=== 2. Manba B: BO'LINISH tasodifiyligi ===
bitta ma'lumot, 30 ta turli CV seed
bahoning std i: 0.0036
=== 3. Manba C: MODEL tasodifiyligi ===
bitta ma'lumot, bitta CV seed, 30 ta model seed
bahoning std i: 0.0027
=== 4. Taqqoslash va xulosa ===
manba std kamaytirish usuli
A. ma_lumot namunasi 0.0701 ko_proq ma_lumot
B. bo_linish (CV seed) 0.0036 takroriy CV
C. model seed (RF) 0.0027 kop daraxt / seed o_rtacha
eng katta manba: A 0.0701-bob
takroriy CV faqat B ni kamaytiradi
⭐ Eng katta manbani bilmasangiz, noto'g'ri narsani tuzatasizNima ko'rsatdi: 2.1-bo'lim.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"std/sqrt(k) — SE" |
Formulaning sharti buzilgan |
"Fold std — bahoning noaniqligi" |
Foldlar orasidagi tarqoqlik |
| "Ko'proq fold — aniqroq baho" | 5 dan keyin foyda kam |
| "LOO eng aniq" | Dispersiyasi yuqori |
| "Takroriy CV noaniqlikni yo'qotadi" | Faqat bo'linish shovqinini |
| "0.8472 — aniq raqam" | Uch xona yetarli |
| "Bitta CV yetarli" | Kichik ma'lumotda yo'q |
| "Turli seed li natijalar taqqoslanadi" | Bir xil bo'linish kerak |
6. Keng tarqalgan xatolar va yechimlari
1. Naiv standart xato
print(f"{b.mean():.4f} +- {b.std()/np.sqrt(len(b)):.4f}") # ⚠️
print(f"{b.mean():.3f} (takrorlar std {takrorlar.std():.3f})") # ✅2. Bitta CV ga asoslanish
ball = cross_val_score(m, X, y, cv=5).mean() # ⚠️
cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=5,
random_state=0) # ✅3. Fold sonini oshirish bilan "aniqlik" izlash
cross_val_score(m, X, y, cv=50) # ⚠️
cross_val_score(m, X, y, cv=RepeatedStratifiedKFold(5, 10)) # ✅4. Turli seed li natijalarni taqqoslash
a = cross_val_score(m1, X, y, cv=KFold(5, shuffle=True))
b = cross_val_score(m2, X, y, cv=KFold(5, shuffle=True)) # ⚠️
CV = KFold(5, shuffle=True, random_state=0) # ikkalasiga ham # ✅5. Soxta aniqlik
print(f"AUC: {ball.mean():.6f}") # ⚠️
print(f"AUC: {ball.mean():.3f}") # ✅6. Model seed ini e'tiborsiz qoldirish
RandomForestClassifier() # har safar boshqa natija # ⚠️
RandomForestClassifier(random_state=0) # ✅7. Farqni noaniqliksiz e'lon qilish
print("Yangi model 0.008 ga yaxshi") # ⚠️
print(f"farq {d.mean():+.3f}, takrorlar std {d.std():.3f}") # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 18.1-dars (o'tilgan): Baholash dizayni
- 18.2-dars (o'tilgan): CV turlari
- 18.4-dars: Nested CV
- 18.10-dars: Modellarni taqqoslash
- 18.11-dars: Validatsiyaga overfitting
8. Eng yaxshi amaliyotlar
Takroriy CV ishlating.
Takrorlar
stdini yozing.std/sqrt(k)ni ishlatmang.k = 5 dan boshlang.
Bir xil bo'linishda taqqoslang.
Model
random_stateini qo'ying.Uch xonagacha yaxlitlang.
Farqni noaniqlik bilan birga bering.
9. Amaliy topshiriq
Vazifa 1: Bashorat qiling
1. # dispersiyaning uch manbasi?
2. # takroriy CV qaysi manbani kamaytiradi?
3. # nima uchun std/sqrt(k) noto'g'ri?
4. # k kichik bo'lsa baho qanday?
5. # k = n nima deyiladi?
6. # amaliyotda qaysi k?
7. # R oshsa std qanday kamayadi?
8. # takrorlar std i nimani o'lchaydi?
9. # necha xonagacha yaxlitlash?
10. # ikki modelni qanday taqqoslash?
11. # juftlashgan farq nima uchun yaxshi?
12. # model seed qachon muhim?Javoblar
- Ma'lumot, bo'linish, model
- Bo'linish
- Foldlar korrelyatsiyali — formula sharti buzilgan
- Pessimistik (bias)
- LeaveOneOut
- 5
- ~`1/sqrt(R)`
- Bo'linish shovqinini
- Uch
- Bir xil bo'linishda, juftlashgan
- Bo'linish shovqini o'zaro qisqaradi
- RF, boosting, SGD, neyron tarmoq
Vazifa 2: Xatolarni tuzating
1. print(f"{b.mean():.4f} +- {b.std()/np.sqrt(len(b)):.4f}")
2. ball = cross_val_score(m, X, y, cv=5).mean()
3. cross_val_score(m, X, y, cv=50)
4. a = cross_val_score(m1, X, y, cv=KFold(5, shuffle=True))
b = cross_val_score(m2, X, y, cv=KFold(5, shuffle=True))
5. print("Yangi model 0.008 ga yaxshi")Javoblar
1. print(f"{b.mean():.3f} (takrorlar std {takrorlar.std():.3f})")
2. cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=5, random_state=0)
3. cross_val_score(m, X, y, cv=RepeatedStratifiedKFold(5, 10))
4. CV = KFold(5, shuffle=True, random_state=0) # ikkalasiga ham
5. print(f"farq {d.mean():+.3f}, takrorlar std {d.std():.3f}")Vazifa 3: Fold soni
Modellang:
- Sozlama
- k va baho
- Barqarorlik
- Ma'lumot hajmi
Vazifa 4: Naiv SE
Modellang:
- Bitta CV
- Haqiqiy tebranish
- Taqqoslash
- k bo'yicha
Vazifa 5: Takroriy CV
Modellang:
- Ma'lumot
- R va barqarorlik
- Takrorlar tarqoqligi
- Ikki model
Vazifa 6: Manbalar
Modellang:
- Ma'lumot
- Bo'linish
- Model
- Taqqoslash
Vazifa 7: O'ylash
Hamkasbingiz aytdi: "CV da 5 ta fold 0.84, 0.86, 0.83, 0.87, 0.85 chiqdi. Demak model 0.85 ± 0.008 (std/sqrt(5)). Bizning maqsadimiz 0.84 edi, shuning uchun maqsadga yetdik." Qaysi joyda xato bor?
Javob
Qisqa javob: ikkita xato bor — noto'g'ri SE va noto'g'ri savol.
1. std/sqrt(5) — noto'g'ri
Fold ballari: 0.84, 0.86, 0.83, 0.87, 0.85. Ularning std i ≈ 0.016, std/sqrt(5) ≈ 0.007.
Lekin 5-fold CV da har ikki o'quv to'plami qatorlarning 75% ini baham ko'radi. Bu foldlar mustaqil emas, ya'ni markaziy limit teoremasining sharti buzilgan. Haqiqiy tebranish (turli random_state bilan) odatda bu bahodan 2-3 barobar katta chiqadi — bu holda ~0.015-0.020.
2. "Maqsadga yetdik" — noto'g'ri savol
| Savol | Javob |
|---|---|
| "CV bahosi 0.84 dan katta bo'ldimi?" | Ha, lekin bu muhim emas |
| "Model ishlab chiqarishda 0.84 beradimi?" | Noma'lum |
CV bahosi — o'tmishdagi ma'lumot bo'yicha va sozlash qilingan bo'lsa optimistik. Ishlab chiqarish natijasi odatda pastroq.
3. To'g'ri yondashuv
# 1. takroriy CV
cv = RepeatedStratifiedKFold(n_splits=5, n_repeats=10, random_state=0)
b = cross_val_score(model, X_ish, y_ish, cv=cv, scoring="roc_auc")
takrorlar = b.reshape(10, 5).mean(axis=1)
print(f"{b.mean():.3f} (takrorlar std {takrorlar.std(ddof=1):.3f})")
# 2. alohida test to'plamida tasdiqlash (bir marta)
test_ball = roc_auc_score(y_test, model.fit(X_ish, y_ish)
.predict_proba(X_test)[:, 1])4. Qanday hisobot qilish kerak
"5×10 takroriy CV: 0.851, takrorlar bo'yicha std 0.014. Alohida test to'plamida (n=4000): 0.846. Sinalgan nomzodlar: 14 ta. Maqsad 0.84 — test natijasi undan yuqori, lekin farq 0.006-bob test SE sidan (≈0.008) kichik, shuning uchun maqsadga yetilganini ishonchli deb aytib bo'lmaydi."
5. Xulosa
std/sqrt(k)ni ishlatmang- Takroriy CV va takrorlar
stdi - Yakuniy raqamni alohida testdan oling
- Maqsad bilan taqqoslashda ham SE ni hisobga oling
Nimani mustahkamlaydi: 2.2, 2.6-bo'limlar.
Xulosa
Bu darsda CV bahosining dispersiyasini o'rgandik.
Eng muhim uch fikr:
std / sqrt(k)— standart xato emas. CV foldlari o'quv ma'lumotining katta qismini baham ko'radi, shuning uchun ballari korrelyatsiyali va formulaning sharti buzilgan. Amalda u ikki boshqa kattalikning hech birini o'lchamaydi: bo'linish shovqinidan bir necha barobar katta, ma'lumot shovqiniga esa ba'zan yaqin, ba'zan ikki barobar uzoq. Ishonchli raqam alohida test to'plamidan, bo'linish shovqini esa takroriy CV dan olinadi.Dispersiyaning uch manbasi bor: ma'lumot, bo'linish, model. Takroriy CV faqat bo'linish shovqinini kamaytiradi; ma'lumot namunasidan kelgan noaniqlik faqat ko'proq ma'lumot bilan kamayadi. Shuning uchun
n_repeatsni cheksiz oshirish bahoni "aniq" qilmaydi — u ma'lum chegaraga borib to'xtaydi.k = 5 dan boshlang, kichik ma'lumotda takrorlang. Fold sonini oshirish bias ni kamaytiradi, lekin narxni chiziqli oshiradi va ma'lum nuqtadan keyin bahoni barqarorlashtirmaydi. Ikki modelni taqqoslashda bir xil bo'linish va juftlashgan farq ishlating — shunda bo'linish shovqini o'zaro qisqaradi.
Keyingi darsda nested cross-validationni o'rganamiz: giperparametr sozlash CV bahosini qanchalik optimistik qiladi va bu optimizmdan qanday qutulish mumkin.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!