---
title: 'Çapraz Doğrulama ile Uyum'
source: 'https://academia.sh/tr/kurslar/oznitelik-muhendisligi/capraz-dogrulama-ile-uyum'
course: 'Veri Hazırlama ve Öznitelik Mühendisliği'
language: tr
updated: '2026-08-17T18:10:11+00:00'
license: 'CC BY-SA 4.0'
---

# Çapraz Doğrulama ile Uyum

Hazırlama zincirinin kat dışında ve kat içinde öğrenilmesinin verdiği iki çapraz doğrulama sayısının ayrılmış kümedeki gerçek sayıyla karşılaştırılması: sınama kümesindeki gerçek sayı 0,7817 iken kat içinde hazırlama 0,7966, kat dışında hazırlama 0,8105 veriyor ve kat içinde hazırlamanın sapması 0,0149, kat dışındakinin 0,0288'dir. Zincirin üçüncü adımı kat dışına çıktığı anda sayı 0,7966'dan 0,8115'e sıçrıyor. Tek bölmenin verdiği 0,8254 dört katın en yükseğine eşittir ve gerçek sayıdan 0,0437 uzaktır. Kurs kapanışında on iki dersin karar öncesi ve karar sonrası sayıları tek tabloda toplanır.

Önceki ders hazırlama zincirini bir nesneye bağladı ve zincirin tamamının yalnız eğitim kümesinden
öğrenildiğini güvence altına aldı. Ölçüm yine tek bir bölmeden okundu: 756 satır eğitim, 252 satır
sınama. O 252 satır bir kez kullanıldı ve tek bir sayı verdi. Başka bir bölme başka bir sayı
verirdi ve hangisinin doğru olduğunu söylemenin yolu yoktu.

**Çapraz doğrulama** (cross-validation) bu soruna yanıt verir: elde kalan veri **kat**lara
bölünür, her kat sırayla ölçüm kümesi olur, kalanlar eğitim kümesi olur ve sonunda birkaç sayı
ile bunların saçılması elde edilir. Hazırlama zinciri işin içine girince yeni bir soru doğar ve
kursun ikinci kuralı burada son biçimini alır: zincir kat dışında bir kez mi öğrenilir, yoksa
her katın içinde yeniden mi. İki yordam iki ayrı sayı verir; bu ders hangisinin **ayrılmış
kümedeki gerçek sayıya** yakın çıktığını ölçer.

- **OS36.** Çapraz doğrulama havuzu K01'in eğitim ve doğrulama kümeleridir: 1.008 satır. Sınama
  kümesinin 252 satırı hiçbir kata, hiçbir hazırlama adımına ve hiçbir seçime girmez.
- **OS37.** Kat sayısı **dörttür**; her katta 252 satır ölçüm kümesi olur, yani sınama kümesiyle
  aynı büyüklükte. Kat sayısı sonuca bakılarak seçilmemiştir.
- **OS38.** Zincir önceki dersin zinciridir, ölçekleme adımı çıkarılmıştır: doldurma, hedef
  temelli kodlama, öznitelik seçimi. Ölçeklemenin karar ağacındaki katkısı orada tam sıfır ölçüldü.
- **OS39.** Kat dışında öğrenilen adım sayısı 0'dan 3'e kadar değiştirilir. Sıfır, zincirin
  tamamının kat içinde öğrenilmesidir.
- **OS40.** Gerçek sayı, zincirin 1.008 satırdan öğrenildiği ve sınama kümesinde ölçüldüğü
  sayıdır: bu kursun tek bir kez okunan sayısıdır.
- **OS41.** Saçılma, dört kat sayısının kendi ortalamasından ortalama uzaklığıdır ve M26'nın
  değişkenlik ölçüsüdür.
- **OS42.** Ayar bütçesi hesabı bu dersin konusu değildir ve M27/K03'e bırakılır; burada hiçbir
  model ayarı seçilmez, model kurs boyunca sabit kalan derinlik 6 karar ağacıdır.

## Kat Dışında ve Kat İçinde

```python
# ORTAK — MODELDIR. M27/K01'in KURGU abone tablosu ayni tohumla yeniden uretilir;
# model derinlik 6 karar agacidir. Onceki dersten kalan tek yeni sutun kisi_basi.
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, VERI = [], []
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})
for k in ABONE:
    r, v = uretec(TOHUM + 7000 + k["no"]), []
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        v.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()
    if not v:
        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),
         "bolge_ad": k["bolge"][0]}
    for b in BOLGE:
        x["b_" + b[0]] = int(k["bolge"][0] == b[0])
    VERI.append(x)

TEMEL = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
         "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]
TABAN_ALAN = TEMEL + ["kisi_basi"]
for x in VERI:
    x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3)


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]


K = karistir(VERI, TOHUM + 90000)
EGT, DOG, SIN = K[:756], K[756:1008], K[1008:]


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, alanlar, enaz=2):
    p, en = sum(x["supheli"] for x in s) / len(s), None
    if derinlik and len(s) >= 2 * enaz and 0.0 < p < 1.0:
        for a in alanlar:
            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, alanlar, enaz),
            "sag": agac(en[4], derinlik - 1, alanlar, 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)
```

Boru hattı önceki dersin nesnesidir. `ogren` yöntemi bu kez fazladan iki değer alır: kat dışındaki
kaynak ve o kaynaktan öğrenecek adım sayısı. Sıfır verildiğinde zincirin tamamı kendisine verilen
kat içi kümeden öğrenir.

```python
for x in VERI:
    r = uretec(TOHUM + 61000 + x["no"])
    r(), r()
    x["a_muhur"] = int(r() < (0.42 if x["supheli"] else 0.10))
    r = uretec(TOHUM + 21000 + x["no"])
    x["tarife_kodu"] = (24 * [b[0] for b in BOLGE].index(x["bolge_ad"])
                        + 4 * (x["hane"] - 1) + int(r() * 4))
    x["memnuniyet"] = None if r() < 0.08 else x["memnuniyet"]
HAVUZ = TABAN_ALAN + ["a_muhur", "tarife_hedef"]


class Doldurma:
    ad = "doldurma"

    def ogren(self, s):
        v = sorted(x["memnuniyet"] for x in s if x["memnuniyet"] is not None)
        self.nesne = {"ortanca": v[len(v) // 2]}

    def uygula(self, s):
        for x in s:
            if x["memnuniyet"] is None:
                x["memnuniyet"] = self.nesne["ortanca"]


class HedefKodlama:
    ad = "hedef kodlama"

    def ogren(self, s):
        g, self.genel = {}, sum(x["supheli"] for x in s) / len(s)
        for x in s:
            g.setdefault(x["tarife_kodu"], []).append(x["supheli"])
        self.nesne = {k: sum(v) / len(v) for k, v in g.items()}

    def uygula(self, s):
        for x in s:
            x["tarife_hedef"] = round(self.nesne.get(x["tarife_kodu"], self.genel), 4)


class Secim:
    ad = "secim"

    def __init__(self, havuz):
        self.havuz = havuz

    def ogren(self, s):
        g0, self.nesne = gini(s), []
        for a in self.havuz:
            d, en = sorted({x[a] for x in s}), 0.0
            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)) >= 20:
                    en = max(en, g0 - (len(sol) * gini(sol)
                                       + len(sag) * gini(sag)) / len(s))
            if en >= 0.004:
                self.nesne.append(a)

    def uygula(self, s):
        pass


class BoruHatti:
    def __init__(self, adimlar, derinlik=6):
        self.adimlar, self.derinlik = adimlar, derinlik

    def ogren(self, egt, dis_kaynak=None, dis_sayisi=0):
        egt = [dict(x) for x in egt]
        dis = [dict(x) for x in (dis_kaynak or [])]
        for i, a in enumerate(self.adimlar):
            if i < dis_sayisi:
                a.ogren(dis)
                a.uygula(dis)
            else:
                a.ogren(egt)
            a.uygula(egt)
        self.model = agac(egt, self.derinlik, self.adimlar[-1].nesne)
        self.egitimde = dogruluk(self.model, egt)
        return self

    def olc(self, s):
        s = [dict(x) for x in s]
        for a in self.adimlar:
            a.uygula(s)
        return dogruluk(self.model, s)


def zincir(havuz=None):
    return [Doldurma(), HedefKodlama(), Secim(havuz or HAVUZ)]


KALAN, KAT = K[:1008], 4


def kat_bol(veri, i, k=KAT):
    n = len(veri) // k
    return ([x for j, x in enumerate(veri) if not i * n <= j < (i + 1) * n],
            veri[i * n:(i + 1) * n])


def capraz(dis_sayisi):
    v = []
    for i in range(KAT):
        ic, disari = kat_bol(KALAN, i)
        v.append(BoruHatti(zincir()).ogren(ic, KALAN, dis_sayisi).olc(disari))
    return v


def ortalama(v):
    return sum(v) / len(v)


def sacilma(v):
    o = ortalama(v)
    return (sum((q - o) ** 2 for q in v) / len(v)) ** 0.5


G = BoruHatti(zincir()).ogren(KALAN).olc(SIN)
TEK = BoruHatti(zincir()).ogren(K[:756]).olc(K[756:1008])
print(f"{'kat disinda':<12} " + " ".join(f"{'kat ' + str(i + 1):>7}" for i in range(KAT))
      + f" {'ortalama':>9} {'sacilma':>8} {'fark':>8}")
for d in range(4):
    v = capraz(d)
    print(f"{str(d) + ' adim':<12} " + " ".join(f"{q:>7.4f}" for q in v)
          + f" {ortalama(v):>9.4f} {sacilma(v):>8.4f} {ortalama(v) - G:>+8.4f}")
print(f"\ntek bolme 756/252 {TEK:.4f}, fark {TEK - G:+.4f}")
print(f"sinama kumesindeki gercek sayi {G:.4f}, taban cizgisi {taban(KALAN, SIN):.4f}")
```

```
kat disinda    kat 1   kat 2   kat 3   kat 4  ortalama  sacilma     fark
0 adim        0.7976  0.7738  0.7897  0.8254    0.7966   0.0187  +0.0149
1 adim        0.7976  0.7738  0.7897  0.8254    0.7966   0.0187  +0.0149
2 adim        0.8016  0.8135  0.8333  0.7976    0.8115   0.0139  +0.0298
3 adim        0.8016  0.8056  0.8452  0.7897    0.8105   0.0209  +0.0288

tek bolme 756/252 0.8254, fark +0.0437
sinama kumesindeki gercek sayi 0.7817, taban cizgisi 0.7579
```

Son sütun dersin yanıtıdır. Zincirin tamamı kat içinde öğrenildiğinde çapraz doğrulama 0,7966
veriyor ve gerçek sayının 0,0149 üstünde kalıyor. Zincirin tamamı kat dışında öğrenildiğinde
0,8105 veriyor ve sapma 0,0288'e, yani iki katına çıkıyor. **Kat içinde hazırlama, gerçek sayıya
yakın olan yordamdır.**

Sıçramanın nereden geldiği ara satırlarda görünüyor. Doldurma kat dışına çıktığında hiçbir şey
değişmiyor; hedef temelli kodlama kat dışına çıktığı anda ortalama 0,7966'dan 0,8115'e atlıyor.
Seçim buna ölçüm çözünürlüğünün altında bir düşüş ekliyor. Kat dışında hazırlamanın maliyetinin
tamamı tek bir adımdan geliyor ve o adım etiketi kullanan adımdır.

Bu, önceki dersteki tabloyla aynı yapıdadır ve aynı nedenle oluşur. Kat dışında öğrenilen hedef
temelli kodlama, her katın ölçüm satırlarının etiketlerini o satırların göreceği sayıya karıştırır.
Kat sayısı arttıkça ölçüm satırlarının payı düşer ve şişme küçülür; azaldıkça büyür. Bu yüzden
**kat dışında hazırlanmış bir çapraz doğrulama sayısı kendi kat sayısından bağımsız okunamaz.**

Sapmanın işareti de dikkat ister. Kat içinde hazırlama gerçek sayıyı 0,0149 aşıyor, yani hâlâ
iyimser; nedeni sızıntı değil, zincirin her katta bir kez daha veriye bakmasıdır. Çapraz doğrulama
gerçek sayıyı ölçmez, gerçek sayının etrafındaki bir aralığı ölçer.

## Tek Bölmenin Tek Sayısı

Tek bölme 0,8254 veriyor ve gerçek sayıdan 0,0437 uzakta. Bu sayı, kat içinde hazırlanmış dört kat
sayısının **en yükseğine** eşittir. Tek bölme yanlış bir hesap yapmadı; yalnız bu aralığın bir
ucuna denk geldi ve tek bir sayı olduğu için hangi uca denk geldiğini söyleyemedi.

Dört katın saçılması 0,0187'dir. Bir bölmeden okunan sayı bu büyüklükte bir dalgalanma taşır ve
0,0119'luk bir katkıyı bu dalgalanmadan ayırmak tek bölmeyle olanaksızdır. Kursun ilk üç dersinde
ölçülen 0,0119'luk katkılar bu yüzden "ölçüldü ve sıfırdan ayrılamadı" diye yazıldı.

Çapraz doğrulamanın kattığı şey daha büyük bir sayı değil, sayının yanında bir **aralıktır**. Ve
o aralık ancak hazırlama zinciri kat içinde öğrenildiğinde gerçek aralıktır.

## Özet

- Sınama kümesindeki gerçek sayı 0,7817; kat içinde hazırlama 0,7966 (sapma 0,0149), kat dışında
  hazırlama 0,8105 (sapma 0,0288) veriyor.
- Sapmanın tamamı tek bir adımdan geliyor: doldurma kat dışına çıktığında sayı değişmiyor, hedef
  temelli kodlama kat dışına çıktığında ortalama 0,7966'dan 0,8115'e sıçrıyor.
- Kat dışında hazırlanmış bir çapraz doğrulama sayısı kat sayısından bağımsız okunamaz, çünkü
  şişmenin büyüklüğü ölçüm satırlarının paya oranına bağlıdır.
- Tek bölmenin verdiği 0,8254, dört katın en yükseğine eşittir ve gerçek sayıdan 0,0437 uzaktır;
  tek sayı hangi uca denk geldiğini söyleyemez.
- Katların saçılması 0,0187'dir; bu büyüklükteki bir dalgalanma varken 0,0119'luk bir katkı tek
  bölmeyle sıfırdan ayrılamaz.

## Kurs Kapanışı

On iki dersin hesabı tek tabloda duruyor ve her sayı kendi dersinden okundu. Karar öncesi ve karar
sonrası sütunları hep **ayrılmış kümede** ölçüldü; taban çizgisi bütün derslerde 0,7579'dur.

| Ders | Karar öncesi | Karar sonrası | Katkı |
|---|---|---|---|
| Hazırlama 01 veri temizleme | 0,7659 ham kayıt | 0,7778 üç düzeltme | +0,0119 |
| Hazırlama 02 öznitelik ölçekleme | 0,7579 ölçeksiz | 0,8016 standart puan | +0,0437 |
| Hazırlama 03 kategorik kodlama | 0,7302 alan kullanılmadı | 0,7778 bir-sıcak kodlama | +0,0476 |
| Hazırlama 04 eksik değer | 0,7619 ortanca ile doldurma | 0,8333 eksiklik göstergesi | +0,0714 |
| Hazırlama 05 dengesiz sınıflar | 0,7778 ham küme | 0,7619 iki kat çoğaltma | −0,0159 |
| Hazırlama 06 aykırı değer | 0,7698 kırpma yok | 0,8016 çit ile kırpıldı | +0,0317 |
| Seçim 01 öznitelik üretme | 0,7778 on bir sütun | 0,7897 oran özniteliği | +0,0119 |
| Seçim 02 zaman ve metin | 0,7897 on iki sütun | 0,8214 nottan beş sayı | +0,0317 |
| Seçim 03 öznitelik seçimi | 0,8135 seçim yok | 0,8254 gömülü yöntem | +0,0119 |
| Seçim 04 boyut azaltma | 0,8254 ham on üç sütun | 0,8175 iki bileşen | −0,0079 |
| Seçim 05 boru hatları | 0,8294 elle zincir | 0,7817 boru hattı | −0,0476 |
| Seçim 06 çapraz doğrulama | 0,8105 kat dışında | 0,7966 kat içinde | −0,0139 |

İkinci ve altıncı hazırlama dersinin satırları eğim temelli doğrusal modelden, kalan on satır
kursun sabit karar ağacından okunur; beşinci hazırlama dersinin satırı doğruluk sütunudur ve aynı
karar yakalanan şüpheli sayısını 21'den 33'e çıkarır.

Kursun birinci kuralı tablonun kendisidir: **bir hazırlama adımı, ayrılmış kümede ölçülen katkısı
kadar vardır.** Katkı sütununda **dört** satır sıfır ya da eksidir. Bu dördü ölçülmeseydi kümede
kalırdı ve dördü de makul bir gerekçeyle savunulurdu.

Kursun ikinci kuralı son iki satırda okunur: **her hazırlama adımı yalnız eğitim kümesinden
öğrenilir ve ayrılmış kümeye uygulanır.** O iki satırdaki eksi işaretler kayıp değil, geri
alınmış şişmedir; boru hattı 0,0476, kat içinde hazırlama 0,0139 sayı düşürdü ve düşen sayının
hiçbiri öğrenmeden gelmiyordu. Ölçülen katkının işaretine bakmadan önce nereden geldiğine bakmak
gerekir.

Geriye kursun başında açılan bir hesap kalıyor. Birinci ders, sınama kümesine her bakışın bir
**seçim payı** biriktirdiğini yazmış ve payın hesabını kursun sonuna bırakmıştı. Tablonun kendisi
o hesabı veriyor: on iki satırın her biri iki sayı taşıyor, yani sınama kümesine **en az 24 kez**
bakıldı ve derslerin içindeki süpürmelerle bu sayı çok daha yüksek. Tablodaki hiçbir sayı bu
yüzden bir genelleme kestirimi değildir; hepsi bir karşılaştırmadır. Gerçek sayı ancak bu kurs
boyunca hiç dokunulmamış bir kümede okunur ve o küme artık yoktur.

On iki derste öznitelikler kuruldu ve her adımın katkısı ayrılmış kümede ölçüldü. Ama bütün bu
ölçümler boyunca **model** hep aynı iki üç aile arasından seçildi: derinlik 6 bir karar ağacı,
yanında bir eğim temelli doğrusal model ve bir uzaklık temelli yordam. Ailenin kendisinin ne
kattığı hiç sorulmadı; derinliğin niçin altı olduğu, komşu sayısının niçin on beş olduğu ve bu
sayıların hangi kümeden okunması gerektiği hiç ölçülmedi. Sonraki kurs, Denetimli Öğrenme, bu
soruları ele alır.
