---
title: 'Eğitim, Doğrulama ve Sınama Kümeleri'
source: 'https://academia.sh/tr/kurslar/makine-ogrenmesine-giris/egitim-dogrulama-ve-test-kumeleri'
course: 'Makine Öğrenmesine Giriş'
language: tr
updated: '2026-08-17T18:10:13+00:00'
license: 'CC BY-SA 4.0'
---

# Eğitim, Doğrulama ve Sınama Kümeleri

Aynı modelin gördüğü ve görmediği veride iki ayrı sayı verdiğinin ölçülmesi: 1.260 abone 756/252/252 olarak bölünür, derinlik 6 karar ağacı eğitimde 0,8466, doğrulamada 0,7897, sınamada 0,7778 doğruluk verir ve taban çizgisi de üç kümede 0,7778, 0,8135, 0,7579 olarak üç ayrı sayıdır. Aynı yordamdan üretilmiş 48 aday arasından seçim yapıldıkça seçim kümesindeki sayı ile bakılmamış kümedeki sayı arasındaki fark 0,0211'den 0,0411'e çıkar. Zaman sıralı bölmede sınama doğruluğu 0,6865'e düşer ama tabanın üstündeki fark 0,0198'den 0,0397'ye çıkar.

Altı derste modelin ürettiği sayı hep aynı veri üzerinde ölçüldü. Elle yazılmış kural kümesi ile
kurallarını veriden çıkaran yordam yan yana kondu, dört öğrenme türünün istediği etiket sayısı
sayıldı, vekil görevin kattığı fark ölçüldü, dört problem tipine dört ayrı taban çizgisi seçildi,
iş akışındaki geri dönüşler sayıldı ve aynı problemin üç rolde üç ayrı çıktıya döndüğü gösterildi.
Hepsinde ölçü modelin **gördüğü** veriden okundu. Modelin **görmediği** bir veride ne olacağı hiç
sorulmadı.

Bu ders o soruyu sorar ve kursun kuralını kurar: **ayrılmış bir kümede ölçülmemiş başarım, başarım
değil ezberdir.** Sorunun üç yüzü var. Aynı model üç kümede kaç sayı verir, bu kümelerden hangisine
kaç kez bakılabilir, ve kümeler hangi kurala göre ayrılır.

- **GE1.** Küme M26'nın bölgesel ölçüm ağından devralınır ve **kurgudur**: 3.199 satırlık uzun
  biçimli okuma tablosu, 1.329 abone, üç dönem, beş bölge, tohum 20260218.
- **GE2.** Etiket bu müfredatta eklenir ve **kurgudur**: kaçak ya da arıza şüphesi taşıyan abone.
  Gerçek bir denetim kaydı değildir; gizli bir puanın eşiğe vurulmasıyla üretilir.
- **GE3.** Modelleme birimi abonedir. Okumalar abone düzeyinde özetlenir; hiç okuma üretmemiş 69
  abone dışarıda kalır ve geriye 1.260 abone kalır.
- **GE4.** Öznitelikler yedi alandan gelir: bölge (beş ikili sütun), hane büyüklüğü, memnuniyet,
  dönem sayısı, ortalama tüketim, oynaklık, sıfır okuma.
- **GE5.** Ölçü **doğruluktur**: doğru sınıflandırılan abone oranı. Sınıflar dengesizdir ve
  doğruluğun bunu ne kadar gizlediği bu kursun konusu değildir.
- **GE6.** Taban çizgisi, eğitim kümesindeki en sık sınıfı bütün abonelere söylemektir. Bu yordam
  hiçbir şey öğrenmez ve hiçbir özniteliğe bakmaz.
- **GE7.** Bölme oranı 60/20/20'dir ve bir karardır. Kümeler bir kez bölünür, dersin sonuna kadar
  aynı kalır.
- **GE8.** Abone numarası ağa katılma sırasıdır. Şüphe oranı bu sıra boyunca artar; bu artış
  kurguya bilerek konmuştur ve zaman sıralı bölmenin ölçtüğü şeydir.

## Üç Küme, Üç Sayı

Kurulum kümeyi üretir, etiketi ekler, üçe böler ve tek bir karar ağacı eğitir. Ağaç bir modeldir:
her düğümde bir öznitelik ve bir eşik seçer, kümeyi ikiye ayırır ve yaprakta çoğunluk sınıfını
söyler. Derinlik 6 bir seçimdir ve gerekçesi bir sonraki derse bırakılır.

```python
# genelleme.py — MODELDIR. M26'nin kurgu olcum agi ayni tohumla uretilir; okumalar
# abone duzeyinde ozetlenir ve uzerine KURGU bir kacak/ariza suphesi etiketi eklenir.
import math

TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF
BOLGE = [("kuzey", 0.28, 21, 0.00), ("guney", 0.22, 17, -0.10),
         ("dogu", 0.18, 26, 0.30), ("bati", 0.14, 14, -0.05),
         ("merkez", 0.18, 23, 0.05)]


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


def ayrik(u, w):
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


ABONE = []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
OKUMA = {}
for k in ABONE:
    r = uretec(TOHUM + 7000 + k["no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        OKUMA.setdefault(k["no"], []).append(0.0 if r() < 0.038 else math.floor(
            k["bolge"][2] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100)
        r()

VERI = []
for k in ABONE:
    v = OKUMA.get(k["no"])
    if v is None:
        continue
    ort, oyn, r = sum(v) / len(v), max(v) - min(v), uretec(TOHUM + 51000 + k["no"])
    z = (0.052 * (ort - 20) + 0.85 * (min(v) == 0.0) + 0.026 * oyn
         + 0.24 * (k["hane"] >= 5) - 0.20 * (k["memnuniyet"] >= 4) + k["bolge"][3]
         + 0.9 * (k["no"] - 10001) / 1399 + (r() + r() + r() - 1.5) * 1.30)
    x = {"no": k["no"], "hane": k["hane"], "memnuniyet": k["memnuniyet"],
         "donem": len(v), "ort_tuketim": round(ort, 2), "oynaklik": round(oyn, 2),
         "sifir_okuma": int(min(v) == 0.0), "supheli": int(z > 1.35)}
    for b in BOLGE:
        x["b_" + b[0]] = int(k["bolge"][0] == b[0])
    VERI.append(x)

ALAN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
        "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]
print(f"okuma {sum(len(v) for v in OKUMA.values())}, abone {len(ABONE)}, "
      f"etiketli abone {len(VERI)}, supheli {sum(x['supheli'] for x in VERI)}")


def karistir(veri, tohum):
    r, s = uretec(tohum), list(range(len(veri)))
    for i in range(len(s) - 1, 0, -1):
        j = int(r() * (i + 1))
        s[i], s[j] = s[j], s[i]
    return [veri[i] for i in s]


def uce_bol(K):
    a, b = int(len(K) * 0.6), int(len(K) * 0.8)
    return K[:a], K[a:b], K[b:]


EGT, DOG, SIN = uce_bol(karistir(VERI, TOHUM + 90000))
print(f"egitim {len(EGT)}, dogrulama {len(DOG)}, sinama {len(SIN)}")


def gini(s):
    p = sum(x["supheli"] for x in s) / len(s) if s else 0.0
    return 2 * p * (1 - p)


def agac(s, derinlik, enaz=2):
    p = sum(x["supheli"] for x in s) / len(s)
    en = None
    if derinlik and len(s) >= 2 * enaz and 0.0 < p < 1.0:
        for a in ALAN:
            d = sorted({x[a] for x in s})
            for v in (d[1:] if len(d) < 10 else
                      [d[int(i * len(d) / 10)] for i in range(1, 10)]):
                sol = [x for x in s if x[a] < v]
                sag = [x for x in s if x[a] >= v]
                if min(len(sol), len(sag)) < enaz:
                    continue
                k = gini(s) - (len(sol) * gini(sol) + len(sag) * gini(sag)) / len(s)
                if en is None or k > en[0]:
                    en = (k, a, v, sol, sag)
    if en is None or en[0] <= 1e-9:
        return {"tahmin": int(p > 0.5)}
    return {"alan": en[1], "esik": en[2], "sol": agac(en[3], derinlik - 1, enaz),
            "sag": agac(en[4], derinlik - 1, enaz)}


def tahmin(d, x):
    while "tahmin" not in d:
        d = d["sol"] if x[d["alan"]] < d["esik"] else d["sag"]
    return d["tahmin"]


def dogruluk(d, s):
    return sum(tahmin(d, x) == x["supheli"] for x in s) / len(s)


def taban(egt, s):
    c = int(sum(x["supheli"] for x in egt) * 2 > len(egt))
    return sum(x["supheli"] == c for x in s) / len(s)


M = agac(EGT, 6)
print(f"\n{'yordam':<28} {'egitim':>8} {'dogrulama':>10} {'sinama':>8}")
print(f"{'taban (en sik sinif)':<28} {taban(EGT, EGT):>8.4f} {taban(EGT, DOG):>10.4f} "
      f"{taban(EGT, SIN):>8.4f}")
print(f"{'karar agaci, derinlik 6':<28} {dogruluk(M, EGT):>8.4f} "
      f"{dogruluk(M, DOG):>10.4f} {dogruluk(M, SIN):>8.4f}")
```

```
okuma 3199, abone 1329, etiketli abone 1260, supheli 276
egitim 756, dogrulama 252, sinama 252

yordam                         egitim  dogrulama   sinama
taban (en sik sinif)           0.7778     0.8135   0.7579
karar agaci, derinlik 6        0.8466     0.7897   0.7778
```

Tablonun ilk satırı beklenmedik olanı söylüyor. **Taban çizgisi de üç sayıdır.** Hiçbir şey
öğrenmeyen, hiçbir özniteliğe bakmayan ve her aboneye aynı yanıtı veren yordam eğitim kümesinde
0,7778, doğrulama kümesinde 0,8135, sınama kümesinde 0,7579 doğruluk veriyor. Aradaki 0,0556'lık
açıklık tümüyle bölmenin rastgeleliğinden geliyor: 252 abonelik bir kümede şüpheli oranı birkaç
puan oynadığında en sık sınıfın doğruluğu da o kadar oynuyor. Bir model sayısını başka bir kümenin
tabanıyla karşılaştırmak bu yüzden hatadır; taban her kümede yeniden hesaplanır.

İkinci satır dersin asıl sayısıdır. Aynı model, aynı ölçü, üç küme, üç sayı — ve **iki farklı
işaret**. Eğitim kümesinde model kendi tabanını 6,9 puan geçiyor. Doğrulama kümesinde tabanın 2,4
puan **altında** kalıyor. Sınama kümesinde tabanı 2,0 puan geçiyor. Eğitim kümesinden okunan 0,8466
sayısı yanlış hesaplanmış değil; doğru hesaplanmış ama yanlış soruyu yanıtlıyor. O sayı modelin
gelecekte ne yapacağını değil, geçmişi ne kadar ezberlediğini ölçüyor.

Geriye şu soru kalıyor: madem ayrılmış bir küme yetiyor, niçin iki tane ayrılmış küme var.

## Sınama Kümesine Kaç Kez Bakılır

Doğrulama kümesi ile sınama kümesinin farkı ölçüde değil kullanımdadır. Doğrulama kümesi **seçim**
için, sınama kümesi **rapor** için ayrılır. Aradaki fark ölçülebilir. Aşağıdaki kod aynı yordamdan
48 aday üretiyor: hepsi derinlik 6 karar ağacı, tek farkları eğitim kümesinin hangi yüzde 85'ini
gördükleri. Aralarında gerçek bir kalite farkı yok.

```python
HAVUZ = []
for a in range(48):
    alt = karistir(EGT, TOHUM + 91000 + a * 17)[:int(len(EGT) * 0.85)]
    m = agac(alt, 6)
    HAVUZ.append((dogruluk(m, DOG), dogruluk(m, SIN)))
rs = uretec(TOHUM + 92000)
print(f"{len(HAVUZ)} aday, hepsi ayni yordam; ortalama dogrulama "
      f"{sum(x[0] for x in HAVUZ) / len(HAVUZ):.4f}, en iyi tek aday "
      f"{max(x[0] for x in HAVUZ):.4f}, ortalama sinama "
      f"{sum(x[1] for x in HAVUZ) / len(HAVUZ):.4f}")
print(f"\n{'bakilan aday':>12} {'secilen dogrulama':>18} "
      f"{'ayni model sinama':>18} {'fark':>8}")
for k in (1, 2, 4, 8, 16, 32):
    d = s = 0.0
    for _ in range(100):
        en = max([HAVUZ[int(rs() * len(HAVUZ))] for _ in range(k)], key=lambda t: t[0])
        d, s = d + en[0], s + en[1]
    print(f"{k:>12} {d / 100:>18.4f} {s / 100:>18.4f} {(d - s) / 100:>+8.4f}")
```

```
48 aday, hepsi ayni yordam; ortalama dogrulama 0.7875, en iyi tek aday 0.8214, ortalama sinama 0.7657

bakilan aday  secilen dogrulama  ayni model sinama     fark
           1             0.7860             0.7650  +0.0211
           2             0.7982             0.7699  +0.0283
           4             0.8069             0.7693  +0.0375
           8             0.8113             0.7742  +0.0371
          16             0.8149             0.7756  +0.0394
          32             0.8177             0.7767  +0.0411
```

Sütunların **düzeyi** değil, aralarındaki farkın **büyümesi** okunur. Doğrulama ile sınama arasında
zaten sabit bir 0,0218'lik açıklık var, çünkü iki kümenin tabanı farklı (0,8135 ve 0,7579); bu
açıklık seçimden gelmiyor. Seçimden gelen şey şudur: bakılan aday sayısı 1'den 32'ye çıkarken
seçilen modelin doğrulama sayısı 0,7860'tan 0,8177'ye, yani 3,2 puan yükseliyor; **aynı modellerin**
sınama sayısı ise yalnız 1,2 puan yükseliyor. Aradaki 2,0 puan hiçbir modelin kazandığı bir şey
değil, seçimin kendisinin ürettiği bir sayıdır.

En sert satır ilk çıktıdadır. Kırk sekiz adayın ortalama doğrulaması 0,7875 ve bu, doğrulama
kümesinin tabanı olan 0,8135'in **altındadır**: ortalama bir aday, "hiçbiri şüpheli değil"
demekten kötüdür. Yine de en iyi tek aday 0,8214 okuyor ve tabanı geçmiş görünüyor. Elli aday
deneyip en iyisini rapor eden bir çalışma, tabanı geçmeyen bir yordamı tabanı geçmiş gibi
gösterebilir. Bu, müfredatın ikinci iddiasının ilk küçük örneğidir ve tam biçimi kursun son
dersinde ölçülecek.

Kural buradan çıkar: bir kümeye bakıp ona göre karar verildiği anda o küme bir doğrulama kümesine
dönüşür. Sınama kümesine bir kez, en sonda, tek bir model için bakılır. İkinci bakış onu doğrulama
kümesi yapar ve raporlanan sayıyı seçim payı kadar şişirir.

## Bölme Bir Karardır

Şimdiye kadarki bölme rastgeleydi: 1.260 abone karıştırılıp üçe ayrıldı. Bu, kümedeki her satırın
birbirinin yerine geçebildiğini varsayar. Ağ zamanla genişlediyse ve sonradan katılan aboneler
öncekilerden farklıysa varsayım tutmaz. Aşağıdaki kod aynı veriyi bu kez **kayıt sırasına göre**
bölüyor: ilk yüzde 60 eğitim, sonraki yüzde 20 doğrulama, son yüzde 20 sınama.

```python
ZE, ZD, ZS = uce_bol(sorted(VERI, key=lambda x: x["no"]))
Z = agac(ZE, 6)
print(f"{'kume':<12} {'supheli orani':>14} {'taban':>8} {'agac':>8}")
for ad, s in (("egitim", ZE), ("dogrulama", ZD), ("sinama", ZS)):
    print(f"{ad:<12} {sum(x['supheli'] for x in s) / len(s):>14.4f} "
          f"{taban(ZE, s):>8.4f} {dogruluk(Z, s):>8.4f}")
print(f"\nrastgele bolmede sinama: taban {taban(EGT, SIN):.4f}, agac "
      f"{dogruluk(M, SIN):.4f}, fark {dogruluk(M, SIN) - taban(EGT, SIN):+.4f}")
print(f"zaman sirali bolmede sinama: taban {taban(ZE, ZS):.4f}, agac "
      f"{dogruluk(Z, ZS):.4f}, fark {dogruluk(Z, ZS) - taban(ZE, ZS):+.4f}")
```

```
kume          supheli orani    taban     agac
egitim               0.1561   0.8439   0.9074
dogrulama            0.2738   0.7262   0.7381
sinama               0.3532   0.6468   0.6865

rastgele bolmede sinama: taban 0.7579, agac 0.7778, fark +0.0198
zaman sirali bolmede sinama: taban 0.6468, agac 0.6865, fark +0.0397
```

Şüpheli oranı eğitim kümesinde 0,1561 iken sınama kümesinde 0,3532. Rastgele bölmede bu üç sayı
birbirine yakındı, çünkü karıştırma sonradan katılan aboneleri üç kümeye eşit dağıtıyordu. Zaman
sıralı bölme onları tek bir kümede topluyor ve modelin karşılaşacağı asıl durumu kuruyor: geçmişten
öğren, geleceği tahmin et.

Sonuç iki yönde birden okunur ve ikisi de doğrudur. Sınama doğruluğu 0,7778'den 0,6865'e, yani 9,1
puan düşüyor — rastgele bölmenin verdiği sayı ağa yeni katılan bir abone için fazla iyimserdi.
Ama tabanın üstündeki fark 0,0198'den 0,0397'ye, yani iki katına **çıkıyor**. Sebep tabanın da
düşmesidir: eğitim kümesinin en sık sınıfını söyleyen yordam, şüpheli oranının yükseldiği bir
sınama kümesinde 0,6468'e iniyor.

Yalnız model sayısına bakan biri zaman sıralı bölmeyi "modeli bozan" bir karar sanır. Yanına
tabanını yazan biri tersini görür: zorlaşan küme modeli değil tabanı daha çok cezalandırmıştır ve
modelin gerçekte kattığı fark orada daha büyüktür. Müfredatın kuralı bu satırda çalışıyor — bir
model, kendisinden daha aptal bir yordamı ne kadar geçtiği kadar iyidir, ve o yordam her zaman
aynı kümede yeniden ölçülür.

## Özet

- Aynı derinlik 6 karar ağacı eğitim kümesinde 0,8466, doğrulama kümesinde 0,7897, sınama kümesinde
  0,7778 doğruluk veriyor; taban çizgisi de üç kümede 0,7778, 0,8135 ve 0,7579 olarak üç ayrı sayı
  olduğu için taban her kümede yeniden hesaplanır.
- Model eğitim kümesinde tabanını 6,9 puan geçiyor, doğrulama kümesinde tabanın 2,4 puan altında
  kalıyor, sınama kümesinde 2,0 puan geçiyor; gördüğü veriden okunan sayı doğru hesaplanmış ama
  yanlış soruyu yanıtlıyor.
- Aynı yordamdan üretilmiş 48 aday arasından en iyisini seçmek, bakılan aday 1'den 32'ye çıkarken
  doğrulama sayısını 3,2 puan yükseltirken sınama sayısını yalnız 1,2 puan yükseltiyor; aradaki 2,0
  puan seçimin kendi payıdır.
- Kırk sekiz adayın ortalama doğrulaması 0,7875 ile tabanın altındadır, ama en iyi aday 0,8214
  okuyup tabanı geçmiş görünür; seçim, tabanı geçmeyen bir yordamı geçmiş gösterebilir.
- Zaman sıralı bölmede sınama doğruluğu 0,6865'e düşüyor ama taban da 0,6468'e düştüğü için
  modelin kattığı fark 0,0198'den 0,0397'ye çıkıyor; bölme kararı iki sayıyı birden oynatır.

## Sonraki Adım

Bu derste derinlik 6 gerekçesiz seçildi ve üç sayı o seçimin üzerinde okundu. Oysa derinlik modelin
**kapasitesidir**: kaç ayrı kural öğrenebileceğini belirler. Kapasite düşürüldüğünde eğitim sayısı
da ayrılmış küme sayısı da düşer; yükseltildiğinde eğitim sayısı yükselmeye devam eder ama ayrılmış
küme sayısı bir noktadan sonra geri döner. Sonraki ders kapasiteyi adım adım artırıp iki sayıyı yan
yana basar, ayrışmanın başladığı noktayı yazar ve iki bozulmayı adlandırır: eksik uyum ile aşırı
uyum.
