---
title: 'Makine Öğrenmesine Giriş'
source: 'https://academia.sh/tr/kurslar/makine-ogrenmesine-giris'
language: tr
updated: '2026-08-17T04:42:05+00:00'
license: 'CC BY-SA 4.0'
lessons: 11
outcomes:
    - 'Öğrenme türlerini problem tipine göre ayırır ve her tipin taban çizgisini seçer'
    - 'Genelleme, aşırı uyum ve eksik uyumu eğitim ile ayrılmış küme sayılarını yan yana okuyarak tanır'
    - 'Uçtan uca bir makine öğrenmesi iş akışını tarif eder ve veri sızıntısının şişirdiği farkı ölçer'
---

# Makine Öğrenmesine Giriş

Modelin gördüğü veride ölçülen sayı ile görmediği veride ölçülen sayının iki ayrı sayı olduğunun gösterilmesi: kural yazma ile örnekten öğrenmenin taban çizgisi karşısındaki farkı, öğrenme türlerinin istediği etiket sayısı, etiketin veriden türetildiği vekil görevin kattığı, dört problem tipinin dört ayrı tabanı, iş akışında geri dönüşün oynattığı sayı, aynı problemin üç rolde farklı çıktıya dönüşmesi, eğitim, doğrulama ve sınama kümelerinin ayrım gerekçesi, kapasite arttıkça iki sayının ayrıştığı nokta, yanlılık ile değişkenliğin ayrıştırılması, ceza katsayısının oynattığı iki sayı ve sızıntının şişirdiği fark.

## Temel Kavramlar

Kararı veriden öğrenen bir yordamın ne yaptığının ve neyi ne kadar kazandırdığının taban çizgisiyle birlikte sayılması: elle yazılmış kural kümesi ile kurallarını veriden çıkaran yordamın aynı problemdeki farkı, denetimli, denetimsiz, yarı denetimli ve pekiştirmeli kurulumların istediği etiket sayısı, etiketin veriden türetildiği vekil görevin asıl görevde kattığı, sınıflandırma, bağlanım, kümeleme ve sıralama problemlerinin dört ayrı tabanı, problem tanımından izlemeye giden akışta geri dönüş sayısı ve aynı problemin üç rolde farklı çıktıya dönüşmesi.

### Makine Öğrenmesi Nedir

Source: https://academia.sh/tr/kurslar/makine-ogrenmesine-giris/makine-ogrenmesi-nedir

Aynı kaçak şüphesi problemi üç yordamla çözülür ve üç sayı yan yana basılır: öğrenmeyen taban çizgisi ayrılmış kümede 0,7533, saha uzmanının elle yazdığı kural kümesi 0,7507, kurallarını veriden çıkaran üç soruluk karar ağacı 0,8594. Elle yazılmış kural tabanın 0,0027 altında kalır, ağaç 0,1061 üstüne çıkar. Fark eşiklerden gelmez: aynı eşikler elle yazılmış kurala taşındığında sayı 0,7480'e iner. Ayrılmış kümedeki 377 abonenin 93'ü şüphelidir; elle yazılmış kural 151 abone işaretler ve 76'sı boş çıkar, ağaç 66 abone işaretler ve 13'ü boş çıkar. Küme 3.199 satırlık okuma tablosundan 1.260 satırlık abone tablosuna indirilir, tohum 20260218.

Veri Analitiği müfredatı doksan derste veriden karara giden yolun her adımını ölçtü ve her
adımda kararın sayıyı oynattığını gösterdi. Kapanışta tek bir soru açık kaldı: bütün o
kararları **insan** verdi. Hangi satır sayılacak, hangi eşik seçilecek, hangi kanal
kullanılacak. Kararı **veriden öğrenen** bir yordamın hangi sayıyı oynattığı ve o yordamın
kendi kararlarının nerede durduğu hiç sorulmadı.

Bu ders o soruyu sorar ve müfredatın ölçü birimini kurar. Bundan sonra bir modelin ürettiği
hiçbir sayı tek başına yazılmaz; yanında **taban çizgisi** durur — aynı problemi öğrenmeden
çözmeye çalışan bir yordamın aynı ölçüdeki sayısı. Müfredatın kuralı buradan çıkar: **bir
model, kendisinden daha aptal bir yordamı ne kadar geçtiği kadar iyidir. Taban çizgisi
yazılmayan başarım ölçülmemiş sayılır.**

- **MK1.** Küme **kurgudur** ve Veri Analitiği müfredatından devralınır: 3.199 satırlık uzun
  biçimli okuma tablosu, 1.329 abone, üç dönem, beş bölge, tohum 20260218. **Etiket bu
  müfredatta eklenir ve o da kurgudur**; etiketi üreten kural koda açıkça yazılır ve hiçbir
  modele verilmez.
- **MK2. Makine öğrenmesi (machine learning)**, kuralı elle yazmak yerine örneklerden
  çıkarmaktır. Girdi bir kural değil, girdi–çıktı çiftlerinden oluşan bir örnek kümesidir;
  çıktı bir karardır ve o kararı veren yapı **model** diye anılır.
- **MK3. Öznitelik (feature)** modele verilen sütun, **etiket (label)** modelin kestirmesi
  istenen sütundur. Aynı tabloda hangi sütunun öznitelik hangisinin etiket olduğu veriden
  değil, sorulan sorudan gelir.
- **MK4. Taban çizgisi (baseline)**, öğrenmeyen bir yordamdır ve **her derste açıkça seçilir**.
  Bu derste en sık sınıfı söylemektir; sınıflar dengesiz olduğu için bu yordam öğrenmeden de
  yüksek bir doğruluk üretir ve modelin geçmesi gereken çıtayı dürüstçe yükseltir.
- **MK5.** Her sayı iki kümede ölçülür: yordamın kurulduğu **eğitim kümesi** ve yordamın hiç
  görmediği **ayrılmış küme**. Ayrımın niçin böyle yapıldığı bu konunun konusu değildir;
  Genelleme konusu bunu ele alır. Burada ayrım kursun kuralı olarak uygulanır.
- **MK6.** Ölçünün kendisi bir karardır. Doğruluk, boşuna gidilen ziyaretle kaçırılan kaçağı
  aynı ağırlıkta sayar; bu ağırlık bir seçimdir ve seçildiği yerde yazılır.
- **MK7.** Modeller bu müfredatta **standart kitaplıkla ve küçük ölçekte** yazılır. Amaç bir
  kitaplığı taklit etmek değil, yordamın davranışını satır satır ölçülebilir kılmaktır.

#### Problem ve Kurgu Küme

Soru şudur: sayaç okumalarından, **kaçak ya da arıza şüphesi** taşıyan aboneyi saha ekibi
kapıya gitmeden önce ayırt etmek. Elde olan şey ölçüm ağının okuma tablosudur; istenen şey her
abone için bir karardır. Tablo önce aynı tohumla yeniden üretilir.

```python
# veri.py — MODELDIR: bolgesel olcum agi ayni tohumla yeniden uretilir.
# Kume kurgudur; hicbir gercek abone, sayac ya da bolge temsil edilmez.
import math

TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF
DONEM = ["2026-01", "2026-02", "2026-03"]
BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26),
         ("bati", 0.14, 14), ("merkez", 0.18, 23)]


def uretec(t: int):
    """Dogrusal eslemeli uretec: tohum koda yazilidir, cikti kosumdan kosuma ayni."""
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

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


def ayrik(u: float, w: list[float]) -> int:
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


_abone, _elenen = [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    k = {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2],
         "hane_kisi": ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05]),
         "memnuniyet": ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17]) + 1}
    (_elenen if r() < 0.046 else _abone).append(k)
_gecerli = {a["abone_no"] for a in _abone}

OKUMA = []
for k in _abone + _elenen:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp(
            (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100
        if k["abone_no"] in _gecerli:
            OKUMA.append({"abone_no": k["abone_no"], "bolge": k["bolge"],
                          "donem": DONEM[d], "tuketim_m3": t})
        r()
print(f"kurgu okuma tablosu (tohum {TOHUM}): {len(OKUMA)} satir, {len(_gecerli)} abone")
```

```
kurgu okuma tablosu (tohum 20260218): 3199 satir, 1329 abone
```

Bu tablo bir modele doğrudan verilemez. Karar abone başınadır, tablo ise okuma başınadır ve bir
abone bir, iki ya da üç satırla temsil edilmektedir. Modelin göreceği biçim **abone başına tek
satır** olmalıdır; her satır bir aboneyi özetleyen dokuz sayı ve bir etiket taşır.

```python
# ozet.py — okuma tablosu abone basina tek satira indirilir ve etiket eklenir.
# Etiketi ureten kural KURGUDUR, koda acikca yazilmistir ve modele verilmez.
OZNITELIK = ["ortalama", "kisi_basi", "dusus", "sifir_okuma", "okuma_sayisi",
             "memnuniyet", "hane_kisi", "en_yuksek", "en_dusuk"]

_grup = {}
for o in OKUMA:
    _grup.setdefault(o["abone_no"], []).append(o)

ABONE = []
for k in _abone:
    o = _grup.get(k["abone_no"])
    if not o:
        continue
    t = [x["tuketim_m3"] for x in o]
    ort = sum(t) / len(t)
    a = {"abone_no": k["abone_no"], "bolge": k["bolge"],
         "hane_kisi": k["hane_kisi"], "memnuniyet": k["memnuniyet"],
         "okuma_sayisi": len(t), "ortalama": ort, "en_yuksek": max(t),
         "en_dusuk": min(t), "sifir_okuma": sum(1 for v in t if v == 0),
         "kisi_basi": ort / max(1, k["hane_kisi"]),
         "dusus": (t[0] - t[-1]) / t[0] if len(t) > 1 and t[0] > 0 else 0.0}
    r = uretec(TOHUM + 31000 + a["abone_no"])
    gizli = (1.30 * a["sifir_okuma"] + 1.25 * (a["dusus"] > 0.45)
             + 1.05 * (a["kisi_basi"] > 12.0) + 0.65 * (a["okuma_sayisi"] < 3)
             + 0.45 * (a["memnuniyet"] <= 2) - 1.55)
    a["suphe"] = 1 if gizli + (r() + r() - 1.0) * 1.1 > 0 else 0
    ABONE.append(a)

r = uretec(TOHUM + 90001)
EGITIM, AYRILMIS = [], []
for a in ABONE:
    (EGITIM if r() < 0.70 else AYRILMIS).append(a)


def dogruluk(tahmin, kume: list[dict]) -> float:
    return sum(1 for a in kume if tahmin(a) == a["suphe"]) / len(kume)


def poz(k: list[dict]) -> int:
    return sum(a["suphe"] for a in k)


print(f"model tablosu: {len(ABONE)} abone, {len(OZNITELIK)} oznitelik, 1 etiket")
print(f"etiket: {poz(ABONE)} supheli, {len(ABONE) - poz(ABONE)} temiz, "
      f"supheli orani yuzde {100 * poz(ABONE) / len(ABONE):.1f}")
print(f"egitim {len(EGITIM)} abone ({poz(EGITIM)} supheli), "
      f"ayrilmis {len(AYRILMIS)} abone ({poz(AYRILMIS)} supheli)")
```

```
model tablosu: 1260 abone, 9 oznitelik, 1 etiket
etiket: 327 supheli, 933 temiz, supheli orani yuzde 26.0
egitim 883 abone (234 supheli), ayrilmis 377 abone (93 supheli)
```

1.329 abonenin 1.260'ı model tablosuna girdi; 69 abonenin hiç okuması yoktur ve özetlenecek bir
şeyi de yoktur. Şüpheli oranı yüzde 26,0'dır. Bu oran modelin geçmesi gereken çıtayı doğrudan
belirler: hiç düşünmeden herkese "temiz" diyen bir yordam abonelerin yüzde 74'ünde haklı çıkar.

Etiketi üreten kural blokta durmaktadır ve gerçek bir kaçak tespiti değildir. Sıfır yazılmış
okuma, dönemler arasında sert düşüş, kişi başına yüksek tüketim, eksik dönem ve düşük
memnuniyet bir puanda toplanır, üstüne gürültü eklenir ve puan sıfırı geçerse abone şüpheli
sayılır. Gürültü kasıtlıdır: gürültüsüz bir etiket, öznitelikleri yeterince bölen her yordamın
tam isabet ettiği bir bulmacaya dönüşür ve hiçbir şey ölçülmez.

#### Taban Çizgisi ve Elle Yazılmış Kural

İki yordam yazılır. Birincisi hiçbir şey öğrenmez: eğitim kümesindeki en sık sınıfı bakar ve
herkese onu söyler. İkincisi saha uzmanının kafasındaki kuraldır — sıfır okuma varsa, tüketim
sert düştüyse ya da kişi başına tüketim yüksekse abone işaretlenir. Eşikler deneyimden gelir.

```python
# kural.py — iki yordam: ogrenmeyen taban cizgisi ve elle yazilmis kural kumesi.
from collections import Counter

en_sik = Counter(a["suphe"] for a in EGITIM).most_common(1)[0][0]


def taban(a: dict) -> int:
    return en_sik


def elle(a: dict) -> int:
    """Saha uzmaninin yazdigi kural kumesi: esikler deneyimden gelir."""
    if a["sifir_okuma"] >= 1:
        return 1
    if a["dusus"] > 0.50:
        return 1
    if a["kisi_basi"] > 15.0:
        return 1
    return 0


EN = [26, 12, 12]
y = lambda h: str(h[0]).ljust(EN[0]) + str(h[1]).rjust(EN[1]) + str(h[2]).rjust(EN[2])
print(y(["yordam", "egitimde", "ayrilmista"]))
for ad, f in [("taban: hep en sik sinif", taban), ("elle yazilmis kural", elle)]:
    print(y([ad, f"{dogruluk(f, EGITIM):.4f}", f"{dogruluk(f, AYRILMIS):.4f}"]))
```

```
yordam                        egitimde  ayrilmista
taban: hep en sik sinif         0.7350      0.7533
elle yazilmis kural             0.7622      0.7507
```

Uzmanın kuralı eğitim kümesinde tabanı 0,0272 geçiyor, ayrılmış kümede ise 0,0027 **altında**
kalıyor. Üç makul kural, üç makul eşik ve alan bilgisi, hiçbir şey öğrenmeyen bir yordamı
geçmeye yetmemiştir. Bu sonucun kendisi bir bulgudur: eğer taban çizgisi yazılmasaydı, tablodaki
0,7507 rahatlıkla "kural kümesi abonelerin dörtte üçünde doğru karar veriyor" diye
raporlanabilirdi.

#### Kurallarını Veriden Çıkaran Yordam

Üçüncü yordam kuralın **biçimini** insandan, **içeriğini** veriden alır. Biçim şudur: bir
öznitelik seç, bir eşik seç, kümeyi ikiye böl, her parçada aynı işi yinele. Hangi özniteliğin
hangi eşikle seçileceği aranarak bulunur; aranan şey bölmeden sonra iki parçanın **etiket
bakımından ne kadar karıştığıdır**. Bu yapı **karar ağacı** diye anılır.

```python
# agac.py — kurallarini veriden cikaran yordam: acgozlu bolme ile uc soruluk
# bir karar agaci. Kutuphane cagrilmaz; bolme olcutu ve durma kurali burada.
DERINLIK, EN_AZ = 3, 40


def safsizlik(k: list[dict]) -> float:
    """Bir kumede iki etiketin ne kadar karistigi: tek etiketliyse sifir."""
    if not k:
        return 0.0
    p = poz(k) / len(k)
    return 2 * p * (1 - p)


def en_iyi_bolme(k: list[dict]):
    en, secim = safsizlik(k) * len(k), None
    for oz in OZNITELIK:
        for esik in sorted({a[oz] for a in k})[1:]:
            sol = [a for a in k if a[oz] < esik]
            sag = [a for a in k if a[oz] >= esik]
            m = safsizlik(sol) * len(sol) + safsizlik(sag) * len(sag)
            if m < en - 1e-9:  # kayan noktali esitlik sinanmaz, kucuk pay birakilir
                en, secim = m, (oz, esik, sol, sag)
    return secim


def cogunluk(k: list[dict]) -> int:
    return 1 if 2 * poz(k) > len(k) else 0


def ogren(k: list[dict], derinlik: int):
    b = en_iyi_bolme(k) if derinlik and len(k) >= EN_AZ else None
    if b is None:
        return cogunluk(k)
    sol, sag = ogren(b[2], derinlik - 1), ogren(b[3], derinlik - 1)
    return sol if sol == sag else (b[0], b[1], sol, sag)


def uygula(dugum, a: dict) -> int:
    while isinstance(dugum, tuple):
        dugum = dugum[2] if a[dugum[0]] < dugum[1] else dugum[3]
    return dugum


def yazdir(d, girinti: str = "") -> None:
    if not isinstance(d, tuple):
        print(f"{girinti}-> {'supheli' if d else 'temiz'}")
        return
    print(f"{girinti}{d[0]} < {d[1]:.3f}")
    yazdir(d[2], girinti + "  ")
    yazdir(d[3], girinti + "  ")


AGAC = ogren(EGITIM, DERINLIK)
yazdir(AGAC)
print()
print(y(["yordam", "egitimde", "ayrilmista"]))
SIRA = [("taban: hep en sik sinif", taban), ("elle yazilmis kural", elle),
        ("veriden ogrenilen agac", lambda a: uygula(AGAC, a))]
for ad, f in SIRA:
    print(y([ad, f"{dogruluk(f, EGITIM):.4f}", f"{dogruluk(f, AYRILMIS):.4f}"]))
```

```
dusus < 0.461
  kisi_basi < 12.060
    -> temiz
    okuma_sayisi < 3.000
      -> supheli
      -> temiz
  en_dusuk < 6.000
    -> supheli
    kisi_basi < 13.052
      -> temiz
      -> supheli

yordam                        egitimde  ayrilmista
taban: hep en sik sinif         0.7350      0.7533
elle yazilmis kural             0.7622      0.7507
veriden ogrenilen agac          0.8709      0.8594
```

Ağaç ayrılmış kümede tabanı 0,1061 geçiyor. Bu, dersin ölçtüğü sayıdır ve tek başına değil üç
satırlık tablonun içinde anlam taşır: aynı problemde öğrenmeyen yordam 0,7533, alan bilgisiyle
yazılmış kural 0,7507, veriden çıkarılmış kural 0,8594 vermektedir.

Ağacın bulduğu eşikler etiketi üreten kuralın eşiklerine yakındır. Etiket kuralı düşüş için
0,45, kişi başına tüketim için 12,0 kullanıyor; ağaç 0,461 ve 12,060 buluyor. Ağaç bu sayıları
hiç görmedi; yalnız 883 abonenin özniteliklerine ve etiketlerine baktı.

#### Farkın Nereden Geldiği

Fark eşiklerden geliyor gibi durur — uzman 0,50 ve 15,0 tahmin etmiş, ağaç 0,461 ve 12,060
bulmuştur. Bu açıklama sınanabilir: uzmanın kuralındaki eşikler ağacınkilerle değiştirilir ve
sayı yeniden ölçülür.

```python
# ayristir.py — fark esiklerden mi geliyor: uzmanin kurali ayni bicimde kalir,
# esikleri agacin buldugu degerlerle degistirilir.
def elle_veriden_esik(a: dict) -> int:
    return 1 if (a["sifir_okuma"] >= 1 or a["dusus"] > 0.461
                 or a["kisi_basi"] > 12.060) else 0


D = [26, 13, 8, 14, 8]
z = lambda h: str(h[0]).ljust(D[0]) + "".join(str(v).rjust(D[i + 1])
                                              for i, v in enumerate(h[1:]))
print(f"ayrilmis kume: {len(AYRILMIS)} abone, {poz(AYRILMIS)} supheli")
print(z(["yordam", "isaretlenen", "dogru", "bos ziyaret", "kacan"]))
YORDAM = SIRA + [("elle, agacin esikleriyle", elle_veriden_esik)]
for ad, f in YORDAM:
    im = [a for a in AYRILMIS if f(a) == 1]
    d = poz(im)
    print(z([ad, len(im), d, len(im) - d, poz(AYRILMIS) - d]))
print()
for ad, f in YORDAM:
    print(f"{ad:<26}ayrilmista dogruluk {dogruluk(f, AYRILMIS):.4f}")
```

```
ayrilmis kume: 377 abone, 93 supheli
yordam                      isaretlenen   dogru   bos ziyaret   kacan
taban: hep en sik sinif               0       0             0      93
elle yazilmis kural                 151      75            76      18
veriden ogrenilen agac               66      53            13      40
elle, agacin esikleriyle            184      91            93       2

taban: hep en sik sinif   ayrilmista dogruluk 0.7533
elle yazilmis kural       ayrilmista dogruluk 0.7507
veriden ogrenilen agac    ayrilmista dogruluk 0.8594
elle, agacin esikleriyle  ayrilmista dogruluk 0.7480
```

Açıklama çürüdü. Uzmanın kuralı ağacın eşikleriyle çalıştırıldığında sayı 0,7507'den 0,7480'e
**düştü**. Fark eşiklerde değil, koşulların **birleştirilme biçimindedir**. Uzmanın kuralı üç
koşulu "veya" ile bağlar: biri tutan her abone işaretlenir. Ağaç aynı koşulları iç içe kullanır
— kişi başına tüketime yalnız düşüşün küçük olduğu dalda bakar, o dalda ikinci bir koşul olarak
okuma sayısını sorar, düşüşün büyük olduğu dalda ise bambaşka bir özniteliğe geçer.

Sonucu sayım tablosu veriyor. Uzmanın kuralı 151 abone işaretliyor ve 75'ini doğru buluyor; 76
ziyaret boşa gidiyor. Ağaç 66 abone işaretliyor, 53'ünü doğru buluyor, 13 ziyaret boşa gidiyor.
Ağaç daha az kaçak yakalıyor — 53'e karşı 75 — ama yaklaşık altı kat az boş ziyaret üretiyor
ve doğruluk ölçüsü boş ziyareti kaçırılan kaçakla aynı ağırlıkta saydığı için ağaç kazanıyor.

Bu, MK6'nın somut karşılığıdır. Boş bir ziyaretin bedeli kaçırılan kaçağınkinden düşükse ölçü
değişir, ölçü değişince sıralama da değişebilir: son satırdaki yordam 93
şüphelinin 91'ini yakalıyor ve yalnız 2'sini kaçırıyor, ama 93 boş ziyaretle. Hangi yordamın
"iyi" olduğu, doğruluğun içine gömülü ağırlık seçimiyle birlikte belirlenir.

#### Özet

- Makine öğrenmesi kuralı elle yazmak yerine örneklerden çıkarmaktır; bu derste kural üç
  soruluk bir karar ağacıdır ve 883 abonelik eğitim kümesinden çıkarılmıştır.
- Taban çizgisi bu derste en sık sınıfı söylemektir ve ayrılmış kümede 0,7533 verir; şüpheli
  oranı yüzde 26,0 olduğu için öğrenmeyen bir yordam bile yüksek görünen bir sayı üretir.
- Elle yazılmış kural kümesi ayrılmış kümede 0,7507 vererek tabanın altında kalır; veriden
  öğrenilen ağaç 0,8594 ile tabanı 0,1061 geçer.
- Fark eşiklerden gelmez: aynı eşikler elle yazılmış kurala taşındığında sayı 0,7480'e iner.
  Fark koşulların iç içe mi "veya" ile mi birleştirildiğinden gelir.
- Doğruluk ölçüsü boş ziyaretle kaçırılan kaçağı eşit sayar; ağaç 53 kaçak yakalayıp 13 boş
  ziyaret üretirken uzmanın kuralı 75 yakalayıp 76 boş ziyaret üretir ve ölçü değişirse
  sıralama da değişir.

#### Sonraki Adım

Bu ders tek bir kurulum kullandı: her abonenin etiketi biliniyordu ve yordam 883 etiketin
tamamını gördü. Etiket bu müfredatta bedava üretildi, sahada değil. Gerçekte bir etiket bir
saha ziyareti demektir ve ziyaret sayılıdır. Sonraki ders aynı problemi dört ayrı kurulumda
kurar — denetimli, denetimsiz, yarı denetimli ve pekiştirmeli — ve her kurulumun kaç etiket
istediğini sayar: 883 etiketin tamamı yerine 60 etiketle çalışıldığında tabanın üstündeki farkın
ne kadarının kaldığı, etiketsiz bir kurulumun aynı kümeden ne çıkarabildiği ve etiketi ziyaret
ederek öğrenen bir yordamın bütçesini nasıl harcadığı ölçülür.

### Öğrenme Türleri

Source: https://academia.sh/tr/kurslar/makine-ogrenmesine-giris/ogrenme-turleri

Aynı kaçak şüphesi problemi dört kurulumda kurulur ve her kurulumun istediği etiket sayısı sayılır: denetimli 883 etiketle ayrılmış kümede 0,8594, denetimsiz 6 etiketle 0,8117, yarı denetimli 60 etiketle 0,8090, pekiştirmeli 120 ziyaretle 0,8090. Taban çizgisi 0,7533'tür. Etiket bütçesi 883'ten 30'a inerken ayrılmış küme sayısı 0,8594'ten 0,7745'e düşer, eğitim sayısı ise 0,8709'dan 0,9400'e çıkar. İki kümeli bölme tabanın tam üstüne oturur, altı kümeli bölme 0,0584 kazandırır. Ziyaret politikası 120 ziyarette 73 kaçak bulur, aynı bütçe rastgele harcansa 25 bulunur.

Önceki ders tek bir kurulum kullandı: 883 abonenin etiketi biliniyordu ve yordam hepsini gördü.
Etiket orada bedava üretildi. Sahada bir etiket bir kapı ziyareti demektir; ziyaret sayılıdır.
Kurulumu belirleyen şey budur — hangi bilgi, ne kadarıyla, ne karşılığında elde ediliyor.

Bu ders aynı problemi dört kurulumda kurar ve her kurulumun **kaç etiket istediğini** sayar.
Ölçü ve ayrılmış küme dördünde de aynı kalır ki sayılar yan yana okunabilsin.

- **MK8. Denetimli öğrenme (supervised learning)**: her örneğin etiketi bilinir. Yordam
  öznitelikten etikete giden eşlemeyi doğrudan arar.
- **MK9. Denetimsiz öğrenme (unsupervised learning)**: etiket yoktur. Çıktı bir karar değil bir
  **yapıdır**; yapıyı karara çevirmek ayrı bir iştir ve etiket ister.
- **MK10. Yarı denetimli öğrenme (semi-supervised learning)**: az sayıda etiketli örnek, çok
  sayıda etiketsiz örnekle birlikte kullanılır. Etiketsiz satırların katkısı ölçülebilir bir
  sayıdır.
- **MK11. Pekiştirmeli öğrenme (reinforcement learning)**: etiket önceden verilmez, **eylemin
  karşılığında** gelir. Yordam kimi ziyaret edeceğini seçer, yalnız ziyaret ettiğinin etiketini
  görür ve bir sonraki seçimi buna göre yapar.
- **MK12.** Etiket bir bütçedir. Bu derste kurulumların karşılaştırma birimi doğruluk değil,
  **doğruluk başına harcanan etikettir**.
- **MK13.** Pekiştirmeli kurulumun asıl ölçüsü doğruluk değil **getiridir**: harcanan bütçede
  bulunan kaçak sayısı. Doğruluk yine basılır, ama kurulumu tarif eden sayı getiridir.

#### Kurgu Kümenin Yeniden Kurulması

```python
# kurulum.py — 01. dersin kurgu kumesi ayni tohumla yeniden kurulur: okuma
# tablosu, abone ozeti, kurgu etiket, egitim / ayrilmis ayrimi ve agac ogrenici.
import math

TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF
BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26),
         ("bati", 0.14, 14), ("merkez", 0.18, 23)]
OZNITELIK = ["ortalama", "kisi_basi", "dusus", "sifir_okuma", "okuma_sayisi",
             "memnuniyet", "hane_kisi", "en_yuksek", "en_dusuk"]


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


_ab, _el, _seri = [], [], {}
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    k = {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2],
         "hane_kisi": ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05]),
         "memnuniyet": ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17]) + 1}
    (_el if r() < 0.046 else _ab).append(k)
_gecerli = {a["abone_no"] for a in _ab}
for k in _ab + _el:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp(
            (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100
        if k["abone_no"] in _gecerli:
            _seri.setdefault(k["abone_no"], []).append(t)
        r()

ABONE = []
for k in _ab:
    t = _seri.get(k["abone_no"])
    if not t:
        continue
    ort = sum(t) / len(t)
    a = {"abone_no": k["abone_no"], "bolge": k["bolge"], "seri": t,
         "hane_kisi": k["hane_kisi"], "memnuniyet": k["memnuniyet"],
         "okuma_sayisi": len(t), "ortalama": ort, "en_yuksek": max(t),
         "en_dusuk": min(t), "sifir_okuma": sum(1 for v in t if v == 0),
         "kisi_basi": ort / max(1, k["hane_kisi"]),
         "dusus": (t[0] - t[-1]) / t[0] if len(t) > 1 and t[0] > 0 else 0.0}
    r = uretec(TOHUM + 31000 + a["abone_no"])
    a["suphe"] = 1 if (1.30 * a["sifir_okuma"] + 1.25 * (a["dusus"] > 0.45)
                       + 1.05 * (a["kisi_basi"] > 12.0) + 0.65 * (a["okuma_sayisi"] < 3)
                       + 0.45 * (a["memnuniyet"] <= 2) - 1.55
                       + (r() + r() - 1.0) * 1.1) > 0 else 0
    ABONE.append(a)

r = uretec(TOHUM + 90001)
EGITIM, AYRILMIS = [], []
for a in ABONE:
    (EGITIM if r() < 0.70 else AYRILMIS).append(a)
poz = lambda k: sum(a["suphe"] for a in k)
dogruluk = lambda f, k: sum(1 for a in k if f(a) == a["suphe"]) / len(k)
_saf = lambda k: 2 * (poz(k) / len(k)) * (1 - poz(k) / len(k)) if k else 0.0


def ogren(k, derinlik=3, en_az=40):
    """01. dersin acgozlu karar agaci: bolme olcutu ve durma kurali orada."""
    en, secim = _saf(k) * len(k), None
    if derinlik and len(k) >= en_az:
        for oz in OZNITELIK:
            for e in sorted({a[oz] for a in k})[1:]:
                sol = [a for a in k if a[oz] < e]
                sag = [a for a in k if a[oz] >= e]
                m = _saf(sol) * len(sol) + _saf(sag) * len(sag)
                if m < en - 1e-9:
                    en, secim = m, (oz, e, sol, sag)
    if secim is None:
        return 1 if 2 * poz(k) > len(k) else 0
    s, g = ogren(secim[2], derinlik - 1, en_az), ogren(secim[3], derinlik - 1, en_az)
    return s if s == g else (secim[0], secim[1], s, g)


def uygula(d, a):
    while isinstance(d, tuple):
        d = d[2] if a[d[0]] < d[1] else d[3]
    return d


print(f"kurgu kume (tohum {TOHUM}): {len(ABONE)} abone, {len(EGITIM)} egitim, "
      f"{len(AYRILMIS)} ayrilmis, {poz(ABONE)} supheli")
```

```
kurgu kume (tohum 20260218): 1260 abone, 883 egitim, 377 ayrilmis, 327 supheli
```

#### Denetimli: Etiket Bütçesi Küçüldükçe

Denetimli kurulumda değişen tek şey kaç etiket verildiğidir. Küçük bütçelerde tek çekim
yanıltıcı olur, bu yüzden her bütçe için beş ayrı altküme çekilir ve sayılar ortalanır.

```python
# denetimli.py — etiket sayisi bir butcedir: ayni yordam artan etiketle kurulur.
# Her butce icin bes ayri rastgele altkume cekilir ve iki sayi ortalanir.
import statistics
from collections import Counter

BUTCE, CEKIM = [30, 60, 150, 400, 883], 5
en_sik = Counter(a["suphe"] for a in EGITIM).most_common(1)[0][0]
TABAN_E, TABAN_A = dogruluk(lambda a: en_sik, EGITIM), dogruluk(lambda a: en_sik, AYRILMIS)
E = [20, 10, 12, 12]
y = lambda h: str(h[0]).ljust(E[0]) + "".join(str(v).rjust(E[i + 1])
                                              for i, v in enumerate(h[1:]))
print(y(["etiket", "egitimde", "ayrilmista", "tabana gore"]))
print(y(["taban (0 etiket)", f"{TABAN_E:.4f}", f"{TABAN_A:.4f}", "0.0000"]))
for n in BUTCE:
    ic, dis = [], []
    for j in range(CEKIM):
        r = uretec(TOHUM + 4100 + j)
        alt = sorted(EGITIM, key=lambda a: r())[:n]
        d = ogren(alt, 3, max(12, n // 20))
        ic.append(dogruluk(lambda a: uygula(d, a), alt))
        dis.append(dogruluk(lambda a: uygula(d, a), AYRILMIS))
    o = statistics.fmean(dis)
    print(y([n, f"{statistics.fmean(ic):.4f}", f"{o:.4f}", f"{o - TABAN_A:+.4f}"]))
```

```
etiket                egitimde  ayrilmista tabana gore
taban (0 etiket)        0.7350      0.7533      0.0000
30                      0.9400      0.7745     +0.0212
60                      0.9267      0.7841     +0.0308
150                     0.8947      0.7873     +0.0340
400                     0.8725      0.8419     +0.0886
883                     0.8709      0.8594     +0.1061
```

Tabanın üstündeki fark bütçeyle birlikte eriyor: 883 etikette 0,1061, 400'de 0,0886, 30'da
0,0212. Otuz etiketle kurulan bir model tabanı geçiyor, ama geçtiği pay 883 etiketlinin beşte
biri kadar.

İki sütun ters yönde hareket ediyor. Etiket azaldıkça ayrılmış küme sayısı düşerken **eğitim
sayısı yükseliyor**: 30 etikette 0,9400, 883 etikette 0,8709. Otuz satırlık bir kümede ağaç
neredeyse her satırı doğru sınıflandırabilir; ayrılmış kümede aynı ağaç 0,7745'te kalır. Bu ters
hareket Genelleme konusunun konusudur; burada yalnız kayda geçirilir.

#### Denetimsiz: Etiketsiz Yapı ve Adlandırma Bedeli

Denetimsiz kurulumda etiket sütunu hiç okunmaz. Yordam yalnız öznitelik uzayına bakar ve
birbirine yakın aboneleri kümelere ayırır. Ölçekler farklı olduğu için her öznitelik ortalaması
çıkarılıp kendi değişkenliğine bölünür; yoksa metreküp cinsinden bir sütun küçük ölçekli
sütunları ezer.

Bu kurulumun çıktısı bir karar değildir. "Bu abone dördüncü kümede" cümlesi saha ekibine bir şey
söylemez; kümenin **adı** gerekir. Adlandırma etiket ister: her kümeden bir abone ziyaret edilir,
kümenin adı o abonenin etiketi olur, maliyet K etikettir.

```python
# denetimsiz.py — etiket hic kullanilmadan kume yapisi cikarilir. Cikti bir
# karar degil bir yapidir; karara cevirmek icin her kumeden bir abone ziyaret
# edilir ve kumenin adi o abonenin etiketi olur: maliyet K etiket.
ORT = {o: statistics.fmean(a[o] for a in EGITIM) for o in OZNITELIK}
SAP = {o: statistics.pstdev(a[o] for a in EGITIM) or 1.0 for o in OZNITELIK}
r = uretec(TOHUM + 4100)
KARISIK = sorted(EGITIM, key=lambda a: r())
vek = lambda a: [(a[o] - ORT[o]) / SAP[o] for o in OZNITELIK]
uzak = lambda v, m: sum((x - y) ** 2 for x, y in zip(v, m))


def kumele(K):
    """K merkez rastgele secilir, yirmi turda uyeliklerin ortalamasina cekilir."""
    r = uretec(TOHUM + 4202)
    mk = [vek(KARISIK[int(r() * len(KARISIK))]) for _ in range(K)]
    for _ in range(20):
        gr = [[] for _ in range(K)]
        for a in EGITIM:
            v = vek(a)
            gr[min(range(K), key=lambda i: uzak(v, mk[i]))].append(v)
        for i in range(K):
            if gr[i]:
                mk[i] = [sum(c) / len(c) for c in zip(*gr[i])]
    return lambda a: min(range(K), key=lambda i: uzak(vek(a), mk[i]))


print(y(["kume sayisi", "etiket", "egitimde", "ayrilmista"]))
KUME = {}
for K in (2, 6):
    hangi, isim = kumele(K), {}
    for a in KARISIK:
        isim.setdefault(hangi(a), a["suphe"])
    f = lambda a, h=hangi, i=isim: i[h(a)]
    KUME[K] = (hangi, f, isim)
    print(y([K, K, f"{dogruluk(f, EGITIM):.4f}", f"{dogruluk(f, AYRILMIS):.4f}"]))
hangi6 = KUME[6][0]
print("K=6 kume boylari",
      sorted(Counter(hangi6(a) for a in EGITIM).values(), reverse=True),
      "supheli adlandirilan kumenin boyu",
      sum(1 for a in EGITIM if KUME[6][2][hangi6(a)] == 1))
```

```
kume sayisi             etiket    egitimde  ayrilmista
2                            2      0.7350      0.7533
6                            6      0.7780      0.8117
K=6 kume boylari [268, 157, 147, 131, 102, 78] supheli adlandirilan kumenin boyu 78
```

İki kümeli bölme tabanın **tam üstüne** oturuyor: 0,7533, farkı sıfır. İki küme de temiz diye
adlandırılmış, yani yordam herkese "temiz" diyen taban çizgisiyle aynı kararı vermiştir.
Kümeleme şüpheye göre bölmez; en büyük değişkenliğe göre böler ve bu kümede en büyük
değişkenlik tüketim büyüklüğündedir, kaçakta değil.

Altı kümeli bölmede tablo değişiyor: 0,8117, tabanın 0,0584 üstünde. 78 abonelik en küçük küme
şüpheli diye adlandırılmış ve altı etiketten biri bunu belirlemeye yetmiştir. Küme sayısı bir
karardır ve etkisi 0,0584'tür — kümelemenin değil, **kaç küme** denmesinin ürettiği bir fark.

#### Yarı Denetimli: Etiketsiz Satırların Katkısı

Yarı denetimli kurulumda 60 abonenin etiketi bilinir, 823'ünki bilinmez. Etiketsiz satırlar
atılmaz: kümeleme yapısına göre her birine bir **atanmış etiket (pseudo-label)** verilir ve ağaç
60 gerçek etiketle 823 atanmış etiketin toplamı üzerinde kurulur.

```python
# yari.py — 60 etiket + 823 etiketsiz satir: etiketsiz satirlar kume yapisindan
# atanmis etiket alir, agac 60 gercek ve 823 atanmis etiketle kurulur.
ETIKETLI, ETIKETSIZ = KARISIK[:60], KARISIK[60:]
isim60 = {}
for i in range(6):
    alt = [x["suphe"] for x in ETIKETLI if hangi6(x) == i]
    isim60[i] = 1 if alt and 2 * sum(alt) > len(alt) else 0
ATANMIS = [{**a, "suphe": isim60[hangi6(a)]} for a in ETIKETSIZ]
d60, dyari = ogren(ETIKETLI, 3, 12), ogren(ETIKETLI + ATANMIS, 3, 40)
f60, fyari = lambda a: uygula(d60, a), lambda a: uygula(dyari, a)
uyan = sum(1 for p, a in zip(ATANMIS, ETIKETSIZ) if p["suphe"] == a["suphe"])
print(f"atanmis etiket {len(ATANMIS)}, gercek etiketle uyusan {uyan}, "
      f"oran {uyan / len(ATANMIS):.4f}")
print(y(["kurulum", "etiket", "egitimde", "ayrilmista"]))
for ad, f in [("yalniz 60 etiket", f60), ("60 + 823 etiketsiz", fyari)]:
    print(y([ad, 60, f"{dogruluk(f, EGITIM):.4f}", f"{dogruluk(f, AYRILMIS):.4f}"]))
```

```
atanmis etiket 823, gercek etiketle uyusan 633, oran 0.7691
kurulum                 etiket    egitimde  ayrilmista
yalniz 60 etiket            60      0.7792      0.7905
60 + 823 etiketsiz          60      0.7780      0.8090
```

Aynı 60 etiket, iki kurulum, iki sayı. Etiketsiz 823 satır eklendiğinde ayrılmış küme sayısı
0,7905'ten 0,8090'a çıkıyor: **0,0185**. Atanmış etiketlerin yalnız yüzde 76,91'i gerçek
etiketle uyuşmaktadır, yani dörtte birine yakını yanlıştır ve buna rağmen katkı artıdır.
Etiketsiz
satırların taşıdığı şey etiket değil, **yoğunluk bilgisidir**: hangi öznitelik bileşimlerinin
sık, hangilerinin seyrek olduğu.

#### Pekiştirmeli: Etiketi Eylemle Kazanmak

Dördüncü kurulumda etiket sütunu kapalıdır. Yordam bir abone seçer, o abone ziyaret edilir ve
yalnız o abonenin etiketi açılır. Bütçe altı turda yirmişer ziyarettir. İlk tur rastgeledir,
sonraki turlarda seçim o ana kadar görülen etiketlerle kurulan beş ağacın oyuna göre yapılır.

```python
# pekistirmeli.py — etiket ancak ziyaret edilince goruluyor. Alti turda yirmiser
# ziyaret; her tur, o ana kadar gorulenlerle kurulan bes agacin oyuna gore secilir.
TUR, ADIM = 6, 20
r = uretec(TOHUM + 4404)
HAVUZ = sorted(EGITIM, key=lambda a: r())
ziyaret, gorulen = [], set()
print(y(["tur", "ziyaret", "bulunan", "toplam"]))
for t in range(TUR):
    if not ziyaret:
        sec = HAVUZ[:ADIM]
    else:
        top = [ogren([ziyaret[int(r() * len(ziyaret))] for _ in ziyaret], 3, 10)
               for _ in range(5)]
        sec = sorted((a for a in HAVUZ if a["abone_no"] not in gorulen),
                     key=lambda a: (-sum(uygula(d, a) for d in top),
                                    a["abone_no"]))[:ADIM]
    gorulen.update(a["abone_no"] for a in sec)
    ziyaret += sec
    print(y([t + 1, ADIM, poz(sec), poz(ziyaret)]))
dpek, dtam = ogren(ziyaret, 3, 20), ogren(EGITIM)
print(f"\n{len(ziyaret)} ziyarette bulunan kacak {poz(ziyaret)}; "
      f"ayni butce rastgele harcansa {poz(HAVUZ[:TUR * ADIM])}")
print(y(["kurulum", "etiket", "egitimde", "ayrilmista"]))
SON = [("denetimli", 883, lambda a: uygula(dtam, a)), ("denetimsiz", 6, KUME[6][1]),
       ("yari denetimli", 60, fyari),
       ("pekistirmeli", TUR * ADIM, lambda a: uygula(dpek, a))]
for ad, n, f in SON:
    print(y([ad, n, f"{dogruluk(f, EGITIM):.4f}", f"{dogruluk(f, AYRILMIS):.4f}"]))
```

```
tur                    ziyaret     bulunan      toplam
1                           20           4           4
2                           20          11          15
3                           20           8          23
4                           20          11          34
5                           20          19          53
6                           20          20          73

120 ziyarette bulunan kacak 73; ayni butce rastgele harcansa 25
kurulum                 etiket    egitimde  ayrilmista
denetimli                  883      0.8709      0.8594
denetimsiz                   6      0.7780      0.8117
yari denetimli              60      0.7780      0.8090
pekistirmeli               120      0.7973      0.8090
```

Bulunan sütunu turdan tura dalgalanıyor — 4, 11, 8, 11, 19, 20 — ama getiri, yani toplam,
birikerek yükseliyor: 4, 15, 23, 34, 53, 73. Altıncı turda seçilen yirmi abonenin
yirmisi de kaçaktır. Toplamda 120 ziyarette 73 kaçak bulunmuştur; aynı bütçe rastgele harcansaydı
25 bulunurdu. **Taban çizgisi burada en sık sınıf değil rastgele ziyarettir**, çünkü ölçülen şey
sınıflandırma doğruluğu değil bütçenin getirisidir ve rastgele ziyaret öğrenmeyen yordamın bu
ölçüdeki karşılığıdır. Fark 48 kaçaktır.

Son tablo dört kurulumu yan yana koyuyor. Doğruluk sütununda üç kurulum çok yakın duruyor —
0,8117, 0,8090, 0,8090 — ama etiket sütunları 6, 60 ve 120'dir. Aynı sayıyı yirmi kat farklı
bütçeyle üretmek aynı şey değildir. Pekiştirmeli kurulumun 120 etiketinin 73'ü sahada bulunmuş
kaçak olarak geri dönmüştür; onun sayısı getiri satırında okunur.

#### Özet

- Dört kurulum aynı problemi çözer ve dördü de aynı ayrılmış kümede ölçülür: denetimli 883
  etiketle 0,8594, denetimsiz 6 etiketle 0,8117, yarı denetimli 60 etiketle 0,8090, pekiştirmeli
  120 ziyaretle 0,8090; taban çizgisi 0,7533'tür.
- Etiket bütçesi küçüldükçe tabanın üstündeki fark eriyor: 883 etikette 0,1061, 400'de 0,0886,
  30'da 0,0212. Aynı düşüşte eğitim sayısı ters yönde, 0,8709'dan 0,9400'e çıkıyor.
- Denetimsiz kurulumun çıktısı karar değil yapıdır; yapıyı karara çevirmek küme başına bir
  ziyaret ister. İki kümeli bölme tabanın tam üstüne oturur, altı kümeli bölme 0,0584 kazandırır.
- Yarı denetimli kurulumda etiketsiz 823 satır, aynı 60 etiketle kurulan modeli 0,7905'ten
  0,8090'a taşır; atanmış etiketlerin yalnız yüzde 76,91'i doğrudur.
- Pekiştirmeli kurulumun ölçüsü getiridir: 120 ziyarette 73 kaçak, rastgele ziyaretle 25;
  fark 48 kaçaktır ve bu sayı doğruluk sütununda görünmez.

#### Sonraki Adım

Dört kurulumun üçü etikete para ödedi, dördüncüsü etiketi ziyaretle kazandı. Hiçbiri şunu
sormadı: etiket **veriden türetilebilir mi**. Okuma tablosunda kimsenin etiketlemediği bir yapı
vardır — her abonenin dönemler boyunca izlediği yol. Bir dönemin okumasından sonrakini kestirmek
etiket istemez, çünkü cevap zaten tablodadır. Sonraki ders bu kurulumu kurar: etiketsiz bir vekil
görevle bir gösterim öğrenilir, o gösterim asıl göreve öznitelik olarak verilir ve vekil görevin
asıl görevde taban çizgisi üzerine kaç puan kattığı ölçülür.

### Kendi Kendine Denetimli Öğrenme

Source: https://academia.sh/tr/kurslar/makine-ogrenmesine-giris/kendi-kendine-denetimli-ogrenme

Etiket veriden türetilir: her abonenin son okuması gizlenir ve önceki okumalardan kestirilir. Vekil görevde taban çizgisi ayrılmış kümede 6,3776 m³ ortalama mutlak hata verir, en küçük kareler modeli 5,9661 m³ — kazanç 0,4115 m³ ve sıfır etiketle elde edilmiştir. Vekil görevin ürettiği üç sayı asıl göreve taşındığında yalnız kayıt öznitelikleriyle ölçülen 0,7851 sayısı 0,8037'ye çıkar. Aynı gösterim vekil görevin taban çizgisinden kurulduğunda 0,8064 çıkar, yani öğrenilen kısmın katkısı 0,0027 eksidir: fark vekil görevin öğrendiğinden değil, taşınan ham okumadan gelmektedir. Elle çıkarılmış dokuz öznitelik hâlâ 0,8594 vermektedir.

Önceki ders dört kurulumun kaç etiket istediğini saydı. Üçü etiket için ödeme yaptı, dördüncüsü
etiketi ziyaretle kazandı. Hiçbiri şunu sormadı: etiket **veriden türetilebilir mi**. Okuma
tablosunda kimsenin etiketlemediği bir yapı vardır — her abonenin dönemler boyunca bıraktığı iz.
Bir dönemin okumasını kapatıp onu kalanlardan kestirmek etiket istemez, çünkü cevap zaten
tablodadır.

Bu ders o kurulumu kurar ve iki ayrı görevin iki ayrı taban çizgisi olduğunu gösterir.

- **MK14. Kendi kendine denetimli öğrenme (self-supervised learning)**: etiket dışarıdan
  verilmez, verinin kendisinden türetilir. Yordam denetimli çalışır, ama denetimi veri sağlar.
- **MK15. Vekil görev (pretext task)**: cevabı zaten veride bulunan bir görev. Amaç o görevi
  çözmek değil, çözerken bir şey öğrenmektir.
- **MK16. Gösterim (representation)**: vekil görevin ürettiği ve asıl göreve öznitelik olarak
  taşınan sayılar. Bu derste üç sayı taşınır.
- **MK17.** Vekil görevin **kendi taban çizgisi** vardır ve o taban da bir gösterim üretir.
  İki gösterim aynı yerde karşılaştırılmadan vekil görevin katkısı ölçülmüş sayılmaz.
- **MK18.** Vekil görev sayısal bir değeri kestirir; bu tür göreve **bağlanım (regression)**
  denir. Terim, İstatistiksel Analiz kursunda değişkenler arası ilişkiyi modellemek için
  kullanılan regresyondan ayrı tutulur: burada amaç ilişkiyi açıklamak değil, görülmemiş bir
  değeri kestirmektir.
- **MK19.** Bağlanımın ölçüsü **ortalama mutlak hata**, sınıflandırmanınki doğruluktur. Bu ders
  iki ölçü kullanır ve her birinin tabanını ayrı seçer.

#### Kurgu Kümenin Yeniden Kurulması

```python
# kurulum.py — 01. dersin kurgu kumesi ayni tohumla yeniden kurulur: okuma
# tablosu, abone ozeti, kurgu etiket, egitim / ayrilmis ayrimi ve agac ogrenici.
import math

TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF
BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26),
         ("bati", 0.14, 14), ("merkez", 0.18, 23)]
OZNITELIK = ["ortalama", "kisi_basi", "dusus", "sifir_okuma", "okuma_sayisi",
             "memnuniyet", "hane_kisi", "en_yuksek", "en_dusuk"]


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


_ab, _el, _seri = [], [], {}
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    k = {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2],
         "hane_kisi": ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05]),
         "memnuniyet": ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17]) + 1}
    (_el if r() < 0.046 else _ab).append(k)
_gecerli = {a["abone_no"] for a in _ab}
for k in _ab + _el:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp(
            (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100
        if k["abone_no"] in _gecerli:
            _seri.setdefault(k["abone_no"], []).append(t)
        r()

ABONE = []
for k in _ab:
    t = _seri.get(k["abone_no"])
    if not t:
        continue
    ort = sum(t) / len(t)
    a = {"abone_no": k["abone_no"], "bolge": k["bolge"], "seri": t,
         "hane_kisi": k["hane_kisi"], "memnuniyet": k["memnuniyet"],
         "okuma_sayisi": len(t), "ortalama": ort, "en_yuksek": max(t),
         "en_dusuk": min(t), "sifir_okuma": sum(1 for v in t if v == 0),
         "kisi_basi": ort / max(1, k["hane_kisi"]),
         "dusus": (t[0] - t[-1]) / t[0] if len(t) > 1 and t[0] > 0 else 0.0}
    r = uretec(TOHUM + 31000 + a["abone_no"])
    a["suphe"] = 1 if (1.30 * a["sifir_okuma"] + 1.25 * (a["dusus"] > 0.45)
                       + 1.05 * (a["kisi_basi"] > 12.0) + 0.65 * (a["okuma_sayisi"] < 3)
                       + 0.45 * (a["memnuniyet"] <= 2) - 1.55
                       + (r() + r() - 1.0) * 1.1) > 0 else 0
    ABONE.append(a)

r = uretec(TOHUM + 90001)
EGITIM, AYRILMIS = [], []
for a in ABONE:
    (EGITIM if r() < 0.70 else AYRILMIS).append(a)
poz = lambda k: sum(a["suphe"] for a in k)
dogruluk = lambda f, k: sum(1 for a in k if f(a) == a["suphe"]) / len(k)
_saf = lambda k: 2 * (poz(k) / len(k)) * (1 - poz(k) / len(k)) if k else 0.0


def ogren(k, derinlik=3, en_az=40):
    """01. dersin acgozlu karar agaci: bolme olcutu ve durma kurali orada."""
    en, secim = _saf(k) * len(k), None
    if derinlik and len(k) >= en_az:
        for oz in OZNITELIK:
            for e in sorted({a[oz] for a in k})[1:]:
                sol = [a for a in k if a[oz] < e]
                sag = [a for a in k if a[oz] >= e]
                m = _saf(sol) * len(sol) + _saf(sag) * len(sag)
                if m < en - 1e-9:
                    en, secim = m, (oz, e, sol, sag)
    if secim is None:
        return 1 if 2 * poz(k) > len(k) else 0
    s, g = ogren(secim[2], derinlik - 1, en_az), ogren(secim[3], derinlik - 1, en_az)
    return s if s == g else (secim[0], secim[1], s, g)


def uygula(d, a):
    while isinstance(d, tuple):
        d = d[2] if a[d[0]] < d[1] else d[3]
    return d


print(f"kurgu kume (tohum {TOHUM}): {len(ABONE)} abone, {len(EGITIM)} egitim, "
      f"{len(AYRILMIS)} ayrilmis, {poz(ABONE)} supheli")
```

```
kurgu kume (tohum 20260218): 1260 abone, 883 egitim, 377 ayrilmis, 327 supheli
```

#### Vekil Görev ve Kendi Taban Çizgisi

Vekil görev şudur: her abonenin son okuması gizlenir ve önceki okumalardan, okuma sayısından ve
kayıt bilgilerinden kestirilir. Bu görev bir kapı ziyareti gerektirmez; cevabı zaten tabloda
duruyor, yalnız modele gösterilmiyor.

Görev sayısal bir değeri kestirdiği için tabanı da sayısal olmalıdır. Öğrenmeyen yordam burada
"herkese kümenin genel ortalamasını söylemek"tir; sınıflandırmadaki en sık sınıfın bağlanımdaki
karşılığı budur. Model tarafında en küçük kareler kullanılır ve normal denklemler eleme ile
çözülür.

```python
# vekil.py — etiketsiz bir gorev: her abonenin son okumasi gizlenir ve onceki
# okumalardan kestirilir. Cevap zaten tablodadir, hicbir etiket harcanmaz.
import statistics
from collections import Counter


def coz(A, b):
    """Dogrusal denklem takimi: kismi pivotlamali eleme."""
    n = len(b)
    M = [A[i][:] + [b[i]] for i in range(n)]
    for i in range(n):
        p = max(range(i, n), key=lambda s: abs(M[s][i]))
        M[i], M[p] = M[p], M[i]
        if abs(M[i][i]) < 1e-12:  # tekil sutun: katsayi sifir birakilir
            continue
        for s in range(n):
            if s != i and M[s][i]:
                f = M[s][i] / M[i][i]
                for c in range(i, n + 1):
                    M[s][c] -= f * M[i][c]
    return [M[i][n] / M[i][i] if abs(M[i][i]) > 1e-12 else 0.0 for i in range(n)]


def en_kucuk_kareler(X, y):
    k = len(X[0])
    return coz([[sum(x[i] * x[j] for x in X) for j in range(k)] for i in range(k)],
               [sum(x[i] * t for x, t in zip(X, y)) for i in range(k)])


GENEL = statistics.fmean(v for a in EGITIM for v in a["seri"])


def girdi(a):
    onceki = a["seri"][:-1]
    return [1.0, statistics.fmean(onceki) if onceki else GENEL,
            float(len(a["seri"])), float(a["hane_kisi"]), float(a["memnuniyet"])]


hedef = lambda k: [a["seri"][-1] for a in k]
AGIRLIK = en_kucuk_kareler([girdi(a) for a in EGITIM], hedef(EGITIM))
kestir = lambda a: sum(c * v for c, v in zip(AGIRLIK, girdi(a)))
hata = lambda f, k: statistics.fmean(abs(f(a) - a["seri"][-1]) for a in k)
E = [26, 12, 12]
y = lambda h: str(h[0]).ljust(E[0]) + str(h[1]).rjust(E[1]) + str(h[2]).rjust(E[2])
print("vekil gorev: son okumanin kestirimi, olcu ortalama mutlak hata (m3)")
print(y(["yordam", "egitimde", "ayrilmista"]))
print(y(["taban: hep genel ortalama", f"{hata(lambda a: GENEL, EGITIM):.4f}",
         f"{hata(lambda a: GENEL, AYRILMIS):.4f}"]))
print(y(["en kucuk kareler", f"{hata(kestir, EGITIM):.4f}",
         f"{hata(kestir, AYRILMIS):.4f}"]))
print("katsayilar", [round(v, 4) for v in AGIRLIK])
```

```
vekil gorev: son okumanin kestirimi, olcu ortalama mutlak hata (m3)
yordam                        egitimde  ayrilmista
taban: hep genel ortalama       5.9664      6.3776
en kucuk kareler                5.6979      5.9661
katsayilar [18.2859, 0.262, -1.5773, -0.0497, -0.1704]
```

Vekil görev kendi ölçüsünde tabanı geçiyor: ayrılmış kümede hata 6,3776 m³'ten 5,9661 m³'e
iniyor, kazanç 0,4115 m³. Bu kazanç **sıfır etiketle** elde edilmiştir; harcanan tek şey
tablonun kendisidir.

Katsayılar modelin ne öğrendiğini söylüyor. Önceki okumaların ortalamasının katsayısı 0,2620'dir:
bir abonenin geçmiş tüketimi son okumasını kısmen belirler, ama zayıf biçimde. Okuma sayısının
katsayısı -1,5773'tür; üç dönemi tam olan abonelerin son okuması sistematik olarak daha
düşüktür, çünkü kurgu kümede her dönem bir öncekinin altına iner. Hane kişi sayısı ve
memnuniyetin katsayıları sıfıra yakındır.

#### Gösterimin Asıl Göreve Katkısı

Vekil görevden asıl göreve taşınacak şey kestirimin kendisi değil, kestirimle gerçek arasındaki
ilişkidir. Üç sayı taşınır: modelin beklediği değer, gerçekle arasındaki fark ve bu farkın
beklenene oranı.

Karşılaştırma dürüst olsun diye asıl görev bu kez **dar bir öznitelik kümesiyle** kurulur:
yalnız abone kaydından gelen üç sütun. Okuma tablosuna dokunmadan elde edilebilen tek bilgi
budur; gösterimin katkısı bu darlığın üstüne eklenen fark olarak okunur.

```python
# gosterim.py — vekil gorevin cikardigi uc sayi asil goreve oznitelik olarak
# tasinir. Gosterim sifir etiketle ogrenildi; asil gorev 883 etiket kullanir.
for a in ABONE:
    b = kestir(a)
    a["beklenen"], a["sapma"] = b, a["seri"][-1] - b
    a["bagil_sapma"] = (a["seri"][-1] - b) / (abs(b) + 1.0)
KAYIT = ["hane_kisi", "memnuniyet", "okuma_sayisi"]
GOSTERIM = ["beklenen", "sapma", "bagil_sapma"]
ELLE = OZNITELIK[:]
en_sik = Counter(a["suphe"] for a in EGITIM).most_common(1)[0][0]
TABAN_A = dogruluk(lambda a: en_sik, AYRILMIS)


def olc(ad, oz):
    global OZNITELIK
    OZNITELIK = oz
    d = ogren(EGITIM)
    ic, dis = dogruluk(lambda a: uygula(d, a), EGITIM), dogruluk(
        lambda a: uygula(d, a), AYRILMIS)
    OZNITELIK = ELLE
    print(str(ad).ljust(28) + str(len(oz)).rjust(4)
          + f"{ic:.4f}".rjust(12) + f"{dis:.4f}".rjust(12)
          + f"{dis - TABAN_A:+.4f}".rjust(13))


print("asil gorev: kacak suphesi, olcu dogruluk")
print("oznitelik kumesi".ljust(28) + "kac".rjust(4) + "egitimde".rjust(12)
      + "ayrilmista".rjust(12) + "tabana gore".rjust(13))
print("taban: hep en sik sinif".ljust(28) + "0".rjust(4)
      + f"{dogruluk(lambda a: en_sik, EGITIM):.4f}".rjust(12)
      + f"{TABAN_A:.4f}".rjust(12) + "+0.0000".rjust(13))
olc("yalniz kayit", KAYIT)
olc("kayit + gosterim", KAYIT + GOSTERIM)
olc("elle cikarilmis dokuz", ELLE)
```

```
asil gorev: kacak suphesi, olcu dogruluk
oznitelik kumesi             kac    egitimde  ayrilmista  tabana gore
taban: hep en sik sinif        0      0.7350      0.7533      +0.0000
yalniz kayit                   3      0.7939      0.7851      +0.0318
kayit + gosterim               6      0.8313      0.8037      +0.0504
elle cikarilmis dokuz          9      0.8709      0.8594      +0.1061
```

Üç satır üç ayrı bilgi kaynağını temsil ediyor. Yalnız abone kaydıyla tabanın 0,0318 üstüne
çıkılıyor. Vekil görevin ürettiği üç sayı eklendiğinde fark 0,0504'e yükseliyor; katkı 0,0186
ve bu katkı için hiç etiket harcanmadı. Elle çıkarılmış dokuz öznitelik ise hâlâ 0,1061
vermektedir — kendi kendine denetim alan bilgisinin yerine geçmemiş, açığın dörtte birini
kapatmıştır.

Etiket muhasebesi de yazılır. Vekil görevin modeli yalnız eğitim kümesinin okumalarıyla
kurulmuştur; ayrılmış kümedeki 377 abonenin hiçbir satırı katsayıların hesabına girmemiştir.
Asıl görevde her üç satır da aynı 883 etiketi kullanır, yani satırlar arasındaki fark etiket
sayısından değil yalnız öznitelik kümesinden gelir. Gösterimin bedeli sıfır etikettir ve bu, onu
elle çıkarılmış dokuz öznitelikten ayıran şeydir: o dokuz sütunu yazmak için birinin tüketim
serisine bakıp hangi özetin işe yarayacağına karar vermesi gerekmiştir.

#### Katkı Nereden Geliyor

Buraya kadar okunan tablo şunu söylüyor gibi durur: vekil görev bir şey öğrendi ve öğrendiği şey
asıl göreve taşındı. Bu iddia sınanabilir, çünkü vekil görevin taban çizgisi de bir gösterim
üretir. Kestirim yerine genel ortalama konur, aynı üç sayı yeniden hesaplanır ve aynı yerde
ölçülür. Öğrenilmiş hiçbir şey taşımayan bu gösterim, öğrenilenin ne kadarının gerçekten
öğrenmeden geldiğini gösterir.

```python
# denetim.py — vekil gorevin taban cizgisi de bir gosterim uretir: kestirim
# yerine genel ortalama konur. Iki gosterim ayni yerde karsilastirilir.
for a in ABONE:
    a["beklenen_t"], a["sapma_t"] = GENEL, a["seri"][-1] - GENEL
    a["bagil_sapma_t"] = (a["seri"][-1] - GENEL) / (GENEL + 1.0)
TABAN_GOSTERIM = ["beklenen_t", "sapma_t", "bagil_sapma_t"]
print("oznitelik kumesi".ljust(28) + "kac".rjust(4) + "egitimde".rjust(12)
      + "ayrilmista".rjust(12) + "tabana gore".rjust(13))
olc("kayit", KAYIT)
olc("kayit + taban gosterimi", KAYIT + TABAN_GOSTERIM)
olc("kayit + ogrenilen gosterim", KAYIT + GOSTERIM)
```

```
oznitelik kumesi             kac    egitimde  ayrilmista  tabana gore
kayit                          3      0.7939      0.7851      +0.0318
kayit + taban gosterimi        6      0.8301      0.8064      +0.0531
kayit + ogrenilen gosterim     6      0.8313      0.8037      +0.0504
```

İddia çürüdü. Taban çizgisinden kurulan gösterim 0,8064, öğrenilen gösterim 0,8037 veriyor;
öğrenilmiş kısmın katkısı **0,0027 eksidir**. Asıl göreve gerçekten katkı yapan şey vekil
görevin öğrendiği ilişki değil, gösterimin yanında taşıdığı **ham gözlemdir**. Genel ortalama
sabit olduğu için ikinci satırdaki üç sütun aslında son okumanın üç ayrı yazılışıdır ve karar
ağacına yeni bir sütun olarak son okumayı vermek, katkının tamamını açıklamaktadır.

Bunun sonucu müfredat düzeyindedir. Vekil görevde kazanılan 0,4115 m³, asıl görevde kazanılan
sayı değildir. İki görevin iki ayrı ölçüsü, iki ayrı taban çizgisi ve iki ayrı sonucu vardır;
birinde tabanı geçmek diğerinde tabanı geçmeyi getirmez. Bir vekil görevin işe yaradığını
söylemek için kendi ölçüsündeki kazancı değil, **asıl görevde tabanın gösterimi üzerine kattığı
farkı** yazmak gerekir.

Kurgu kümenin niçin böyle davrandığı da yazılabilir. Bu kümede aynı abonenin dönemleri
birbirinden büyük ölçüde bağımsız üretilir; bir dönemin okuması sonrakini zayıf belirler ve
önceki ortalamanın katsayısı 0,2620'de kalır. Zamanla güçlü biçimde bağlı bir kümede aynı vekil
görev başka bir sayı verirdi. Ölçülen şey yöntemin kendisi değil, yöntemin **bu veri
üzerindeki** katkısıdır.

#### Özet

- Kendi kendine denetimli kurulumda etiket dışarıdan gelmez, veriden türetilir: son okuma
  gizlenir ve önceki okumalardan kestirilir.
- Vekil görev kendi ölçüsünde tabanı geçiyor: ayrılmış kümede ortalama mutlak hata 6,3776 m³'ten
  5,9661 m³'e iniyor, kazanç 0,4115 m³ ve harcanan etiket sıfır.
- Vekil görevin ürettiği üç sayı asıl göreve taşındığında yalnız kayıt öznitelikleriyle ölçülen
  0,7851 sayısı 0,8037'ye çıkıyor; elle çıkarılmış dokuz öznitelik ise 0,8594 veriyor.
- Aynı gösterim vekil görevin **taban çizgisinden** kurulduğunda 0,8064 çıkıyor: öğrenilmiş
  kısmın katkısı 0,0027 eksidir ve fark taşınan ham gözlemden gelmektedir.
- Vekil görevde tabanı geçmek asıl görevde tabanı geçmeyi getirmez; iki görevin iki ayrı ölçüsü
  ve iki ayrı tabanı vardır.

#### Sonraki Adım

Üç derste tek bir soru soruldu: bu abone şüpheli mi. Soru ikili olduğu için taban çizgisi de hep
aynı kaldı — en sık sınıfı söylemek. Oysa aynı tablo başka soruları da kaldırır: bu abonenin
gelecek dönem tüketimi kaç metreküp olacak, aboneler kaç doğal öbeğe ayrılıyor, sahaya bugün
çıkacak ekip hangi yüz aboneyi hangi sırayla gezmeli. Sonraki ders aynı veriye dört ayrı soru
sorar ve her sorunun kendi taban çizgisini ayrı ayrı seçer: sınıflandırma, bağlanım, kümeleme ve
sıralama için dört ayrı öğrenmeyen yordam yazılır, seçimlerinin gerekçesi kaydedilir ve dört
tabanın dört ayrı sayı verdiği gösterilir.

### Uygulama Alanları

Source: https://academia.sh/tr/kurslar/makine-ogrenmesine-giris/uygulama-alanlari

Aynı kurgu abone tablosuna dört soru sorulur ve dört ayrı taban çizgisi seçilir: sınıflandırmada en sık sınıf ayrılmış kümede 0,7533 verir, ağaç 0,8594; bağlanımda genel ortalama 5,2255 m³ ortalama mutlak hata verir, en küçük kareler 4,1275 m³; kümelemede rastgele dört gruplama 2,7683 küme içi uzaklık verir, öğrenilen dört merkez 2,1551; sıralamada rastgele sıra ilk 100 ziyarette 20 kaçak bulur, en yüksek tüketimden başlayan sıra 30, dokuz ağaçlık topluluk 71. Dört ölçünün ikisinde büyük sayı iyi, ikisinde küçük sayı iyidir; sayılar birbiriyle değil yalnız kendi tabanlarıyla karşılaştırılabilir.

Üç derste tek bir soru soruldu: bu abone şüpheli mi. Soru ikili olduğu için taban çizgisi de hep
aynı kaldı — en sık sınıfı söylemek. Aynı tablo başka soruları da kaldırır. Bu abone önümüzdeki
dönem kaç metreküp tüketir. Aboneler kaç doğal öbeğe ayrılıyor. Sahaya bugün çıkacak ekip
hangi yüz aboneyi hangi sırayla gezmeli.

Bu ders aynı veriye dört soru sorar. Ders boyunca değişmeyen tek şey tablodur; değişen şey
soru, sorunun ölçüsü ve **sorunun taban çizgisidir**. Dördü de aynı ayrılmış kümede ölçülür.

- **MK20.** Bir veri kümesi tek bir problem tanımlamaz. Problemi belirleyen şey veri değil,
  sorulan sorudur; aynı tabloda hangi sütunun etiket olduğu soruyla birlikte değişir.
- **MK21. Sınıflandırma (classification)**: çıktı sonlu bir etiket kümesinden bir değerdir.
  Tabanı **en sık sınıftır**, çünkü hiç bakmadan verilebilecek en iyi tek karar odur.
- **MK22. Bağlanım (regression)**: çıktı sayısal bir değerdir. Tabanı **genel ortalamadır**;
  ortalama mutlak hata ölçülüyorsa ortanca daha iyi bir taban olur ve seçim yazılır.
- **MK23. Kümeleme (clustering)**: etiket yoktur, çıktı bir gruplamadır. Tabanı **rastgele
  gruplamadır**, çünkü aynı sayıda grup üretir ve hiçbir yapı kullanmaz.
- **MK24. Sıralama (ranking)**: çıktı tek bir karar değil bir **sıradır** ve ölçü sıranın
  başındaki bütçeye bakar. Tabanı **rastgele sıradır**; yanına öğrenmeyen bir sezgisel sıra da
  konur, çünkü sahada gerçekten kullanılan yordam odur.
- **MK25.** Dört ölçünün ikisinde büyük sayı, ikisinde küçük sayı iyidir. Modellerin sayıları
  birbiriyle değil, yalnız kendi tabanlarıyla karşılaştırılabilir.

#### Kurgu Kümenin Yeniden Kurulması

```python
# kurulum.py — 01. dersin kurgu kumesi ayni tohumla yeniden kurulur: okuma
# tablosu, abone ozeti, kurgu etiket, egitim / ayrilmis ayrimi ve agac ogrenici.
import math

TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF
BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26),
         ("bati", 0.14, 14), ("merkez", 0.18, 23)]
OZNITELIK = ["ortalama", "kisi_basi", "dusus", "sifir_okuma", "okuma_sayisi",
             "memnuniyet", "hane_kisi", "en_yuksek", "en_dusuk"]


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


_ab, _el, _seri = [], [], {}
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    k = {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2],
         "hane_kisi": ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05]),
         "memnuniyet": ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17]) + 1}
    (_el if r() < 0.046 else _ab).append(k)
_gecerli = {a["abone_no"] for a in _ab}
for k in _ab + _el:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp(
            (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100
        if k["abone_no"] in _gecerli:
            _seri.setdefault(k["abone_no"], []).append(t)
        r()

ABONE = []
for k in _ab:
    t = _seri.get(k["abone_no"])
    if not t:
        continue
    ort = sum(t) / len(t)
    a = {"abone_no": k["abone_no"], "bolge": k["bolge"], "seri": t,
         "hane_kisi": k["hane_kisi"], "memnuniyet": k["memnuniyet"],
         "okuma_sayisi": len(t), "ortalama": ort, "en_yuksek": max(t),
         "en_dusuk": min(t), "sifir_okuma": sum(1 for v in t if v == 0),
         "kisi_basi": ort / max(1, k["hane_kisi"]),
         "dusus": (t[0] - t[-1]) / t[0] if len(t) > 1 and t[0] > 0 else 0.0}
    r = uretec(TOHUM + 31000 + a["abone_no"])
    a["suphe"] = 1 if (1.30 * a["sifir_okuma"] + 1.25 * (a["dusus"] > 0.45)
                       + 1.05 * (a["kisi_basi"] > 12.0) + 0.65 * (a["okuma_sayisi"] < 3)
                       + 0.45 * (a["memnuniyet"] <= 2) - 1.55
                       + (r() + r() - 1.0) * 1.1) > 0 else 0
    ABONE.append(a)

r = uretec(TOHUM + 90001)
EGITIM, AYRILMIS = [], []
for a in ABONE:
    (EGITIM if r() < 0.70 else AYRILMIS).append(a)
poz = lambda k: sum(a["suphe"] for a in k)
dogruluk = lambda f, k: sum(1 for a in k if f(a) == a["suphe"]) / len(k)
_saf = lambda k: 2 * (poz(k) / len(k)) * (1 - poz(k) / len(k)) if k else 0.0


def ogren(k, derinlik=3, en_az=40):
    """01. dersin acgozlu karar agaci: bolme olcutu ve durma kurali orada."""
    en, secim = _saf(k) * len(k), None
    if derinlik and len(k) >= en_az:
        for oz in OZNITELIK:
            for e in sorted({a[oz] for a in k})[1:]:
                sol = [a for a in k if a[oz] < e]
                sag = [a for a in k if a[oz] >= e]
                m = _saf(sol) * len(sol) + _saf(sag) * len(sag)
                if m < en - 1e-9:
                    en, secim = m, (oz, e, sol, sag)
    if secim is None:
        return 1 if 2 * poz(k) > len(k) else 0
    s, g = ogren(secim[2], derinlik - 1, en_az), ogren(secim[3], derinlik - 1, en_az)
    return s if s == g else (secim[0], secim[1], s, g)


def uygula(d, a):
    while isinstance(d, tuple):
        d = d[2] if a[d[0]] < d[1] else d[3]
    return d


print(f"kurgu kume (tohum {TOHUM}): {len(ABONE)} abone, {len(EGITIM)} egitim, "
      f"{len(AYRILMIS)} ayrilmis, {poz(ABONE)} supheli")
```

```
kurgu kume (tohum 20260218): 1260 abone, 883 egitim, 377 ayrilmis, 327 supheli
```

#### İkili Karar ve Sayısal Değer

İlk iki soru etiketlidir ve birbirinden yalnız çıktının türüyle ayrılır. Birincisi bir sınıf
ister: bu abone şüpheli mi. İkincisi bir sayı ister: bu abone ortalama kaç metreküp tüketir.
İkinci soru saha ekibi için değil şebeke planlaması içindir ve okuma gelmeden önce
yanıtlanabilmesi gerekir; bu yüzden bağlanım modeline yalnız abone kaydından gelen sütunlar ve
bölge verilir.

Tabanlar ayrı seçilir çünkü ölçüler ayrıdır. Doğruluk için en sık sınıf, ortalama mutlak hata
için genel ortalama. İkinci seçim tartışmalıdır: ortalama mutlak hata ölçülüyorsa öğrenmeyen en
iyi tek sayı ortalama değil ortancadır. Burada ortalama seçilmiştir, çünkü sonraki kurslarda
kare hata da kullanılacak ve iki ölçü arasında tek bir taban tutulacaktır; seçim tartışmalı
olduğu için yazılır.

```python
# iki_problem.py — ayni tabloya iki soru: ikili bir karar ve sayisal bir deger.
# Her sorunun tabani ayri secilir; ikili soruda en sik sinif, sayisal soruda
# genel ortalama, cunku olculer farklidir.
import statistics
from collections import Counter

SONUC = []
BASLIK = ["problem", "olcu", "taban eg.", "taban ayr.", "model eg.", "model ayr."]
E = [16, 26, 11, 11, 11, 11]
y = lambda h: str(h[0]).ljust(E[0]) + str(h[1]).ljust(E[1]) + "".join(
    str(v).rjust(E[i + 2]) for i, v in enumerate(h[2:]))


def kaydet(ad, olcu, te, ta, me, ma, bicim="{:.4f}"):
    SONUC.append([ad, olcu] + [bicim.format(v) for v in (te, ta, me, ma)])
    print(y(SONUC[-1]))


en_sik = Counter(a["suphe"] for a in EGITIM).most_common(1)[0][0]
AGAC = ogren(EGITIM)
BOLGE_AD = [b[0] for b in BOLGE]


def gx(a):
    return ([1.0, float(a["hane_kisi"]), float(a["memnuniyet"]),
             float(a["okuma_sayisi"])]
            + [1.0 if a["bolge"] == b else 0.0 for b in BOLGE_AD[1:]])


def coz(A, b):
    n = len(b)
    M = [A[i][:] + [b[i]] for i in range(n)]
    for i in range(n):
        p = max(range(i, n), key=lambda s: abs(M[s][i]))
        M[i], M[p] = M[p], M[i]
        if abs(M[i][i]) < 1e-12:
            continue
        for s in range(n):
            if s != i and M[s][i]:
                f = M[s][i] / M[i][i]
                for c in range(i, n + 1):
                    M[s][c] -= f * M[i][c]
    return [M[i][n] / M[i][i] if abs(M[i][i]) > 1e-12 else 0.0 for i in range(n)]


k = len(gx(EGITIM[0]))
X, t = [gx(a) for a in EGITIM], [a["ortalama"] for a in EGITIM]
W = coz([[sum(x[i] * x[j] for x in X) for j in range(k)] for i in range(k)],
        [sum(x[i] * v for x, v in zip(X, t)) for i in range(k)])
GENEL = statistics.fmean(t)
kestir = lambda a: sum(c * v for c, v in zip(W, gx(a)))
hata = lambda f, s: statistics.fmean(abs(f(a) - a["ortalama"]) for a in s)
print(y(BASLIK))
kaydet("siniflandirma", "dogruluk (buyuk iyi)",
       dogruluk(lambda a: en_sik, EGITIM), dogruluk(lambda a: en_sik, AYRILMIS),
       dogruluk(lambda a: uygula(AGAC, a), EGITIM),
       dogruluk(lambda a: uygula(AGAC, a), AYRILMIS))
kaydet("baglanim", "mutlak hata m3 (kucuk)", hata(lambda a: GENEL, EGITIM),
       hata(lambda a: GENEL, AYRILMIS), hata(kestir, EGITIM), hata(kestir, AYRILMIS))
```

```
problem         olcu                        taban eg. taban ayr.  model eg. model ayr.
siniflandirma   dogruluk (buyuk iyi)           0.7350     0.7533     0.8709     0.8594
baglanim        mutlak hata m3 (kucuk)         4.8767     5.2255     3.7226     4.1275
```

İki satır iki ayrı yönde okunur. Sınıflandırmada model tabanın 0,1061 **üstündedir**;
bağlanımda 1,0980 m³ **altındadır** ve iyi olan budur. Sayıların büyüklüğü de kıyaslanamaz:
0,8594 birimsizdir, 4,1275 metreküptür.

#### Etiketsiz Gruplama ve Sıra

Üçüncü soru etiketi hiç kullanmaz: aboneler kaç doğal öbeğe ayrılıyor. Ölçü, her abonenin kendi
grubunun merkezine uzaklığının ortalamasıdır; küçük olması grupların sıkı olduğunu gösterir.
Öğrenmeyen yordam burada aboneleri **rastgele dört gruba** dağıtır ve her grubun merkezini kendi
üyelerinden hesaplar; böylece aynı sayıda grup üretilir ama hiçbir yapı kullanılmaz.

Dördüncü soru bir sıra ister. Saha ekibinin günlük kapasitesi yüz ziyarettir ve ölçü, sıranın
ilk yüzünde kaç kaçak bulunduğudur. Burada iki taban yazılır. Rastgele sıra öğrenmeyen yordamın
kendisidir; en yüksek ortalama tüketimden başlayan sıra ise sahada gerçekten kullanılan
sezgisel yordamdır ve model onu da geçmek zorundadır.

```python
# iki_problem_daha.py — ucuncu soru etiketsizdir, dorduncusu bir sayi degil bir
# sira ister. Ucuncunun tabani rastgele gruplama, dorduncununki rastgele siradir.
ORT = {o: statistics.fmean(a[o] for a in EGITIM) for o in OZNITELIK}
SAP = {o: statistics.pstdev(a[o] for a in EGITIM) or 1.0 for o in OZNITELIK}
vek = lambda a: [(a[o] - ORT[o]) / SAP[o] for o in OZNITELIK]
uzak = lambda v, m: math.sqrt(sum((x - y) ** 2 for x, y in zip(v, m)))
ic_uzaklik = lambda s, M: statistics.fmean(min(uzak(vek(a), m) for m in M) for a in s)

K = 4
MERKEZ = [vek(a) for a in EGITIM[:K]]
for _ in range(25):
    gr = [[] for _ in range(K)]
    for a in EGITIM:
        gr[min(range(K), key=lambda i: uzak(vek(a), MERKEZ[i]))].append(vek(a))
    for i in range(K):
        if gr[i]:
            MERKEZ[i] = [sum(c) / len(c) for c in zip(*gr[i])]
r = uretec(TOHUM + 6104)
rasgele_gr = [[] for _ in range(K)]
for a in EGITIM:
    rasgele_gr[int(r() * K)].append(vek(a))
RASGELE = [[sum(c) / len(c) for c in zip(*g)] for g in rasgele_gr]

UST = 100
r = uretec(TOHUM + 6205)
TOPLULUK = [ogren([EGITIM[int(r() * len(EGITIM))] for _ in EGITIM]) for _ in range(9)]
puan = lambda a: sum(uygula(d, a) for d in TOPLULUK)
r = uretec(TOHUM + 6206)
kura = {a["abone_no"]: r() for a in ABONE}
ilk = lambda f, s: poz(sorted(s, key=f)[:UST])

print(y(BASLIK))
kaydet("kumeleme", "kume ici uzaklik (kucuk)", ic_uzaklik(EGITIM, RASGELE),
       ic_uzaklik(AYRILMIS, RASGELE), ic_uzaklik(EGITIM, MERKEZ),
       ic_uzaklik(AYRILMIS, MERKEZ))
kaydet("siralama", f"ilk {UST}'de kacak (buyuk)",
       ilk(lambda a: kura[a["abone_no"]], EGITIM),
       ilk(lambda a: kura[a["abone_no"]], AYRILMIS),
       ilk(lambda a: (-puan(a), a["abone_no"]), EGITIM),
       ilk(lambda a: (-puan(a), a["abone_no"]), AYRILMIS), "{:.0f}")
print(f"\nsiralamada ikinci taban — en yuksek ortalama tuketimden basla: "
      f"egitimde {ilk(lambda a: (-a['ortalama'], a['abone_no']), EGITIM)}, "
      f"ayrilmista {ilk(lambda a: (-a['ortalama'], a['abone_no']), AYRILMIS)}")
print(f"karsilastirma icin: egitimde {poz(EGITIM)} supheli / {len(EGITIM)} abone, "
      f"ayrilmista {poz(AYRILMIS)} supheli / {len(AYRILMIS)} abone")
```

```
problem         olcu                        taban eg. taban ayr.  model eg. model ayr.
kumeleme        kume ici uzaklik (kucuk)       2.7237     2.7683     2.1678     2.1551
siralama        ilk 100'de kacak (buyuk)           29         20         86         71

siralamada ikinci taban — en yuksek ortalama tuketimden basla: egitimde 38, ayrilmista 30
karsilastirma icin: egitimde 234 supheli / 883 abone, ayrilmista 93 supheli / 377 abone
```

Kümelemede öğrenilen dört merkez, rastgele dört grubun 2,7683'lük uzaklığını 2,1551'e indiriyor;
kazanç 0,6132. Bu sayının yanında bir uyarı durur: kümelemenin ölçüsü etikete hiç bakmaz, yani
"iyi" bir kümeleme kaçağı bulan bir kümeleme değildir. Önceki derste altı kümeli bir bölmenin
kaçak sorusunda tabana ne kadar yaklaştığı ayrıca ölçülmüştü; bu iki sayı aynı şeyin iki ölçüsü
değil, iki ayrı problemin iki ayrı ölçüsüdür.

Sıralamada üç sayı yan yana duruyor. Rastgele sıra ayrılmış kümedeki ilk yüz ziyarette 20 kaçak
buluyor — 377 abonenin 93'ü şüpheli olduğuna göre beklenen budur. En yüksek tüketimden başlayan
sezgisel sıra 30 buluyor; alan bilgisi rastgeleyi 10 kaçak geçiyor. Dokuz ağaçlık topluluğun
sırası 71 buluyor. Model sezgiselin 41, rastgelenin 51 kaçak üstündedir ve **hangi tabanın
yazıldığına göre modelin kazancı 41 mi 51 mi olduğu değişir**. Taban seçimi bir ölçüm kararıdır.

#### Dört Problem, Dört Taban

```python
# dort_taban.py — dort problem, dort ayri taban, dort ayri olcu ve iki ayri yon.
print(y(BASLIK))
for s in SONUC:
    print(y(s))
```

```
problem         olcu                        taban eg. taban ayr.  model eg. model ayr.
siniflandirma   dogruluk (buyuk iyi)           0.7350     0.7533     0.8709     0.8594
baglanim        mutlak hata m3 (kucuk)         4.8767     5.2255     3.7226     4.1275
kumeleme        kume ici uzaklik (kucuk)       2.7237     2.7683     2.1678     2.1551
siralama        ilk 100'de kacak (buyuk)           29         20         86         71
```

Tablo tek bir veri kümesinden çıktı ve dört ayrı satır verdi. Model sütunları birbirleriyle
karşılaştırılamaz: 0,8594 ile 4,1275'i yan yana koyup birini büyük saymanın hiçbir anlamı
yoktur, çünkü biri oran biri metreküptür ve birinde büyük sayı iyi, diğerinde kötüdür.
Karşılaştırılabilir olan tek şey her satırın kendi içindeki iki sütun arasındaki farktır.

Taban sütunlarının kendisi de bilgi taşıyor. Sınıflandırmada taban zaten 0,7533'tür; modelin
kazanabileceği en fazla pay 0,2467'dir ve 0,1061 bunun yüzde 43,0'ıdır. Sıralamada taban
yalnız 20'dir ve tavan 93'tür; model 71 ile aradaki açığın yüzde 69,9'unu kapatmıştır. Aynı
model, aynı veri, aynı gün — ama iki soruda iki ayrı başarı öyküsü.

#### Özet

- Bir veri kümesi tek bir problem tanımlamaz; aynı kurgu abone tablosu sınıflandırma, bağlanım,
  kümeleme ve sıralama sorularının dördünü de kaldırır.
- Dört sorunun dört ayrı tabanı vardır: en sık sınıf 0,7533, genel ortalama 5,2255 m³, rastgele
  dört gruplama 2,7683 küme içi uzaklık, rastgele sıra ilk 100 ziyarette 20 kaçak.
- Modellerin ayrılmış küme sayıları sırasıyla 0,8594, 4,1275 m³, 2,1551 ve 71 kaçaktır; ikisinde
  büyük sayı, ikisinde küçük sayı iyidir.
- Sıralamada ikinci bir taban yazıldı: en yüksek tüketimden başlayan sezgisel sıra 30 kaçak
  buluyor, yani modelin kazancı yazılan tabana göre 41 ya da 51 kaçaktır.
- Model sayıları birbiriyle karşılaştırılamaz; karşılaştırılabilir olan tek şey her satırın
  kendi tabanına olan uzaklığıdır.

#### Sonraki Adım

Dört problem de tek bir noktadan okundu: hazır bir tablo, hazır bir öznitelik kümesi, hazır bir
ayrım ve tek bir ölçüm. Bu dersler bir modelin nasıl kurulduğunu gösterdi, bir işin nasıl
yürüdüğünü değil. Gerçekte problem tanımı ölçümden sonra değişir, öznitelik kümesi
değerlendirmeden sonra genişler, eşik dağıtımdan sonra kaydırılır ve akış hiçbir zaman baştan
sona bir kez akmaz. Sonraki ders bu akışı yedi adım olarak kurar ve ölçtüğü şey adımların
kendisi değil **geri dönüşlerdir**: hangi adımda hangi adıma dönüldüğü sayılır ve her dönüşün
ayrılmış küme sayısını ne kadar oynattığı basılır.

### Makine Öğrenmesi İş Akışı

Source: https://academia.sh/tr/kurslar/makine-ogrenmesine-giris/makine-ogrenmesi-is-akisi

Yedi adımlık akış üç geri dönüş üretir ve her dönüşün oynattığı sayı basılır. Beşinci adımdaki kapı tabana göre farkı 0,0500 eşiğiyle sınar: üç sütunla kurulan model 0,0318 verip kapıda kalır, dokuz sütunla 0,1061 verip geçer. Altıncı adımda model 1.260 abonenin 240'ını işaretler, günlük kapasite 40 ziyarettir ve liste altı güne yayılır; kısıt problemi sınıflandırmadan sıralamaya çevirir, sıralama ilk 40 ziyarette 30 kaçak bulur, rastgele sıra 14. Yedinci adımda ölçüm politikası değişir, etiket değişmediği hâlde aynı model 23'e düşer ve kayan veriyle yeniden kurulduğunda 30'a döner. Yedi adımlık akış toplam 22 adım ziyaretiyle tamamlanır.

Dört ders bir modelin nasıl kurulduğunu gösterdi: hazır bir tablo, hazır bir öznitelik kümesi,
hazır bir ayrım ve tek bir ölçüm. Gerçek bir işte hiçbiri hazır gelmez. Problem tanımı ölçümden
sonra değişir, öznitelik kümesi değerlendirmeden sonra genişler ve akış hiçbir zaman baştan sona
bir kez akmaz.

Bu ders akışı yedi adım olarak kurar ve **adımları değil geri dönüşleri** sayar. Veri
Analitiğine Giriş kursundaki analiz iş akışı dersi de dönüşleri saymıştı; orada dönüşün nedeni
bir kararın ait olduğu adımdan sonra görülmesiydi. Burada dönüşü tetikleyen şey bir karar değil
bir **ölçümdür**: akış, bir sayı eşiğin altında kaldığı için geri döner.

- **MK26.** Akış yedi adımdır: problem tanımı, veri hazırlama, öznitelik seçimi, model kurma,
  değerlendirme, dağıtım, izleme. Ölçülen şey adım sayısı değil **geri dönüş sayısıdır**.
- **MK27. Kapı**, akışın ilerleme kararını bir sayıya bağlayan denetimdir. Kapının eşiği
  ölçümden **önce** yazılır; sonra yazılırsa eşik bir karar değil bir gerekçe olur.
- **MK28.** Bu koşumda dönüşün üç ayrı kaynağı vardır: ölçümün eşiği tutturamaması, dağıtım
  kısıtı ve izlemede verinin kayması.
- **MK29.** Dağıtım kısıtı problem tanımını değiştirebilir. Sınıflandırmanın çıktısı bir
  **kümedir**, sıralamanınki bir **kuyruktur**; sınırlı kapasiteyle çalışan bir ekibin istediği
  şey kuyruktur.
- **MK30.** İzleme, model hiç değişmediği hâlde sayının değişebildiği tek adımdır. Kayan şey
  modelin kendisi değil, modele gelen veridir.
- **MK31.** Dağıtımdan sonra modelin ürettiği karara **çıkarım (inference)** denir. Terim,
  Görselleştirme ve Raporlama kursunda okuyucunun bir grafikten çıkardığı sonuç anlamında
  kullanılan çıkarımdan ayrıdır: burada çıkarımı yapan okuyucu değil modeldir.

#### Kurgu Kümenin Yeniden Kurulması

```python
# kurulum.py — 01. dersin kurgu kumesi ayni tohumla yeniden kurulur: okuma
# tablosu, abone ozeti, kurgu etiket, egitim / ayrilmis ayrimi ve agac ogrenici.
import math

TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF
BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26),
         ("bati", 0.14, 14), ("merkez", 0.18, 23)]
OZNITELIK = ["ortalama", "kisi_basi", "dusus", "sifir_okuma", "okuma_sayisi",
             "memnuniyet", "hane_kisi", "en_yuksek", "en_dusuk"]


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


_ab, _el, _seri = [], [], {}
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    k = {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2],
         "hane_kisi": ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05]),
         "memnuniyet": ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17]) + 1}
    (_el if r() < 0.046 else _ab).append(k)
_gecerli = {a["abone_no"] for a in _ab}
for k in _ab + _el:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp(
            (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100
        if k["abone_no"] in _gecerli:
            _seri.setdefault(k["abone_no"], []).append(t)
        r()

ABONE = []
for k in _ab:
    t = _seri.get(k["abone_no"])
    if not t:
        continue
    ort = sum(t) / len(t)
    a = {"abone_no": k["abone_no"], "bolge": k["bolge"], "seri": t,
         "hane_kisi": k["hane_kisi"], "memnuniyet": k["memnuniyet"],
         "okuma_sayisi": len(t), "ortalama": ort, "en_yuksek": max(t),
         "en_dusuk": min(t), "sifir_okuma": sum(1 for v in t if v == 0),
         "kisi_basi": ort / max(1, k["hane_kisi"]),
         "dusus": (t[0] - t[-1]) / t[0] if len(t) > 1 and t[0] > 0 else 0.0}
    r = uretec(TOHUM + 31000 + a["abone_no"])
    a["suphe"] = 1 if (1.30 * a["sifir_okuma"] + 1.25 * (a["dusus"] > 0.45)
                       + 1.05 * (a["kisi_basi"] > 12.0) + 0.65 * (a["okuma_sayisi"] < 3)
                       + 0.45 * (a["memnuniyet"] <= 2) - 1.55
                       + (r() + r() - 1.0) * 1.1) > 0 else 0
    ABONE.append(a)

r = uretec(TOHUM + 90001)
EGITIM, AYRILMIS = [], []
for a in ABONE:
    (EGITIM if r() < 0.70 else AYRILMIS).append(a)
poz = lambda k: sum(a["suphe"] for a in k)
dogruluk = lambda f, k: sum(1 for a in k if f(a) == a["suphe"]) / len(k)
_saf = lambda k: 2 * (poz(k) / len(k)) * (1 - poz(k) / len(k)) if k else 0.0


def ogren(k, derinlik=3, en_az=40):
    """01. dersin acgozlu karar agaci: bolme olcutu ve durma kurali orada."""
    en, secim = _saf(k) * len(k), None
    if derinlik and len(k) >= en_az:
        for oz in OZNITELIK:
            for e in sorted({a[oz] for a in k})[1:]:
                sol = [a for a in k if a[oz] < e]
                sag = [a for a in k if a[oz] >= e]
                m = _saf(sol) * len(sol) + _saf(sag) * len(sag)
                if m < en - 1e-9:
                    en, secim = m, (oz, e, sol, sag)
    if secim is None:
        return 1 if 2 * poz(k) > len(k) else 0
    s, g = ogren(secim[2], derinlik - 1, en_az), ogren(secim[3], derinlik - 1, en_az)
    return s if s == g else (secim[0], secim[1], s, g)


def uygula(d, a):
    while isinstance(d, tuple):
        d = d[2] if a[d[0]] < d[1] else d[3]
    return d


print(f"kurgu kume (tohum {TOHUM}): {len(ABONE)} abone, {len(EGITIM)} egitim, "
      f"{len(AYRILMIS)} ayrilmis, {poz(ABONE)} supheli")
```

```
kurgu kume (tohum 20260218): 1260 abone, 883 egitim, 377 ayrilmis, 327 supheli
```

#### Yedi Adım ve Birinci Kapı

Akış birinci adımda tanımlanır: soru "bu abone şüpheli mi", ölçü doğruluk, taban çizgisi en sık
sınıf. Beşinci adımdaki kapının eşiği de burada yazılır: model, ayrılmış kümede tabanı en az
0,0500 geçmelidir. Bu sayı bir mühendislik kararıdır ve ölçümden önce yazıldığı için bir
karardır; ölçümden sonra yazılsaydı sonucu meşrulaştıran bir gerekçe olurdu.

İkinci adımda veri hazırlanır. Birinci geçişte okuma tablosunun özetleri henüz hazır değildir,
bu yüzden üçüncü adım yalnız abone kaydından gelen üç sütunu seçer.

```python
# akis.py — yedi adim ve iki kapi. Kapilar sayiya bakar: besinci adimdaki kapi
# tabana gore farki, altincidaki gunluk saha kapasitesini olcer.
import statistics
from collections import Counter

ADIM = ["1 problem tanimi", "2 veri hazirlama", "3 oznitelik secimi", "4 model kurma",
        "5 degerlendirme", "6 dagitim", "7 izleme"]
KABUL_FARK, KAPASITE = 0.05, 40
DONUS, TAM = [], OZNITELIK[:]
KAYIT = ["hane_kisi", "memnuniyet", "okuma_sayisi"]
en_sik = Counter(a["suphe"] for a in EGITIM).most_common(1)[0][0]
TABAN_E, TABAN_A = dogruluk(lambda a: en_sik, EGITIM), dogruluk(lambda a: en_sik, AYRILMIS)


def agacla(oz, kume):
    global OZNITELIK
    OZNITELIK = oz
    d = ogren(kume)
    OZNITELIK = TAM
    return d


E = [8, 16, 11, 11, 11, 11, 22]
y = lambda h: str(h[0]).ljust(E[0]) + str(h[1]).ljust(E[1]) + "".join(
    str(v).rjust(E[i + 2]) for i, v in enumerate(h[2:6])) + "  " + str(h[6])
print(y(["gecis", "oznitelik", "taban", "egitimde", "ayrilmista", "fark", "kapi"]))
AGAC = {}
for gecis, oz in ((1, KAYIT), (2, TAM)):
    d = AGAC[gecis] = agacla(oz, EGITIM)
    ic, dis = dogruluk(lambda a: uygula(d, a), EGITIM), dogruluk(
        lambda a: uygula(d, a), AYRILMIS)
    fark = dis - TABAN_A
    gecti = fark >= KABUL_FARK
    print(y([gecis, f"{len(oz)} sutun", f"{TABAN_A:.4f}", f"{ic:.4f}", f"{dis:.4f}",
             f"{fark:+.4f}", "gecti" if gecti else f"kapali, esik {KABUL_FARK:.2f}"]))
    if not gecti:
        DONUS.append([ADIM[4], ADIM[2], "fark esigin altinda", f"{fark:+.4f}", None])
    else:
        DONUS[-1][4] = f"{fark:+.4f}"

isaret = sum(1 for a in ABONE if uygula(AGAC[2], a))
print(f"\n6. adim: model {len(ABONE)} abonenin {isaret} tanesini isaretliyor; "
      f"gunluk kapasite {KAPASITE} ziyaret, yani liste "
      f"{-(-isaret // KAPASITE)} gune yayiliyor ve icinde sira yok")
DONUS.append([ADIM[5], ADIM[0], "kapasiteye sigmiyor", f"{isaret} isaret", None])
```

```
gecis   oznitelik             taban   egitimde ayrilmista       fark  kapi
1       3 sutun              0.7533     0.7939     0.7851    +0.0318  kapali, esik 0.05
2       9 sutun              0.7533     0.8709     0.8594    +0.1061  gecti

6. adim: model 1260 abonenin 240 tanesini isaretliyor; gunluk kapasite 40 ziyaret, yani liste 6 gune yayiliyor ve icinde sira yok
```

Birinci geçiş kapıda kaldı: 0,0318 eşiğin altındadır. Akış beşinci adımdan üçüncü adıma döner ve
öznitelik kümesi okuma tablosunun özetleriyle dokuz sütuna çıkar. İkinci geçişte fark 0,1061'dir
ve kapı açılır. Dönüşün oynattığı sayı budur: 0,0318 yerine 0,1061.

Altıncı adımda ikinci kapı devreye giriyor ve model başarımını değil **işin kısıtını** ölçüyor.
Model 1.260 abonenin 240'ını işaretliyor. Günlük kapasite 40 ziyarettir, yani liste altı güne
yayılır ve sınıflandırma çıktısı liste içinde kimin önce gezileceğini söylemez. Model kapıyı
başarımla geçti, kısıtla geçemedi.

#### Kısıt Problemi Değiştirir, İzleme Veriyi

Altıncı adımdan birinci adıma dönülür. Bu, akışın en uzun dönüşüdür ve modeli değil **soruyu**
değiştirir: karar isteyen bir soru yerine sıra isteyen bir soru yazılır. Ölçü de değişir —
doğruluk yerine ilk 40 ziyarette bulunan kaçak sayısı — ve tabanı da yeniden seçilir: rastgele
sıra.

Yedinci adımda model sahadadır ve izlenir. İzlemenin ölçtüğü şey modelin kendisi değildir,
çünkü model değişmemektedir. Değişen şey modele gelen veridir: şebeke okuma politikasını
değiştirir, sıfır okumalar kestirimle doldurulur ve eksik dönemler tamamlanır. Aboneler aynıdır,
gerçek kaçak durumu aynıdır, yalnız tabloya yazılma biçimi değişmiştir.

```python
# siralama_ve_izleme.py — problem yeniden tanimlanir: karar degil sira istenir.
# Dagitimdan sonra olcum politikasi degisir ve ayni model yeniden olculur.
r = uretec(TOHUM + 7205)
TOPLULUK = [ogren([EGITIM[int(r() * len(EGITIM))] for _ in EGITIM]) for _ in range(9)]
r = uretec(TOHUM + 7206)
kura = {a["abone_no"]: r() for a in ABONE}
ilk = lambda f, s: poz(sorted(s, key=f)[:KAPASITE])
sira = lambda T: (lambda a: (-sum(uygula(d, a) for d in T), a["abone_no"]))
rastgele = lambda a: kura[a["abone_no"]]


def kayan(a):
    """Okuma politikasi degisti: sifir okumalar kestirimle dolduruluyor, eksik
    donemler tamamlaniyor. Gercek kacak durumu, yani etiket, degismiyor."""
    dolu = [v for v in a["seri"] if v > 0]
    tem = round(statistics.fmean(dolu), 2) if dolu else 0.0
    t = [v if v > 0 else tem for v in a["seri"]] + [tem] * (3 - len(a["seri"]))
    ort = sum(t) / len(t)
    return {**a, "seri": t, "okuma_sayisi": 3, "ortalama": ort, "en_yuksek": max(t),
            "en_dusuk": min(t), "sifir_okuma": sum(1 for v in t if v == 0),
            "kisi_basi": ort / max(1, a["hane_kisi"]),
            "dusus": (t[0] - t[-1]) / t[0] if t[0] > 0 else 0.0}


KAYAN_E, KAYAN_A = [kayan(a) for a in EGITIM], [kayan(a) for a in AYRILMIS]
r = uretec(TOHUM + 7305)
YENI = [ogren([KAYAN_E[int(r() * len(KAYAN_E))] for _ in KAYAN_E]) for _ in range(9)]
D = [30, 14, 12, 12]
z = lambda h: str(h[0]).ljust(D[0]) + "".join(str(v).rjust(D[i + 1])
                                              for i, v in enumerate(h[1:]))
print(z([f"ilk {KAPASITE} ziyarette kacak", "veri", "egitimde", "ayrilmista"]))
print(z(["taban: rastgele sira", "eski", ilk(rastgele, EGITIM), ilk(rastgele, AYRILMIS)]))
print(z(["model: dokuz agacli sira", "eski", ilk(sira(TOPLULUK), EGITIM),
         ilk(sira(TOPLULUK), AYRILMIS)]))
print(z(["taban: rastgele sira", "kayan", ilk(rastgele, KAYAN_E), ilk(rastgele, KAYAN_A)]))
print(z(["ayni model", "kayan", ilk(sira(TOPLULUK), KAYAN_E),
         ilk(sira(TOPLULUK), KAYAN_A)]))
print(z(["kayan veriyle kurulan model", "kayan", ilk(sira(YENI), KAYAN_E),
         ilk(sira(YENI), KAYAN_A)]))
print(f"\netiket degismedi: eskide {poz(AYRILMIS)}, kayanda {poz(KAYAN_A)} supheli")
print(f"bozulan iki oznitelik: sifir okuma toplami "
      f"{sum(a['sifir_okuma'] for a in AYRILMIS)} -> {sum(a['sifir_okuma'] for a in KAYAN_A)}, "
      f"eksik donemli abone {sum(1 for a in AYRILMIS if a['okuma_sayisi'] < 3)} -> "
      f"{sum(1 for a in KAYAN_A if a['okuma_sayisi'] < 3)}")
DONUS[1][4] = f"ilk {KAPASITE}'ta {ilk(sira(TOPLULUK), AYRILMIS)} kacak"
DONUS.append([ADIM[6], ADIM[1], "olcum politikasi degisti",
              f"{ilk(sira(TOPLULUK), KAYAN_A)} kacak",
              f"{ilk(sira(YENI), KAYAN_A)} kacak"])
```

```
ilk 40 ziyarette kacak                  veri    egitimde  ayrilmista
taban: rastgele sira                    eski          10          14
model: dokuz agacli sira                eski          30          30
taban: rastgele sira                   kayan          10          14
ayni model                             kayan          33          23
kayan veriyle kurulan model            kayan          39          30

etiket degismedi: eskide 93, kayanda 93 supheli
bozulan iki oznitelik: sifir okuma toplami 39 -> 3, eksik donemli abone 117 -> 0
```

Aynı model, aynı aboneler, aynı etiketler ve düşen bir sayı: ilk 40 ziyarette 30 kaçak yerine 23.
Rastgele sıranın tabanı 14'te sabit kaldığı için düşüş modelindir, sorunun zorlaşması değildir.
Nedeni son satırda yazılı: modelin dayandığı iki öznitelik silinmiştir. Sıfır okuma toplamı
39'dan 3'e, eksik dönemli abone sayısı 117'den 0'a inmiştir. Model bu iki sütunun taşıdığı
bilgiyle karar veriyordu ve o bilgi artık tabloya yazılmıyor.

Yedinci adımdan ikinci adıma dönülür. Veri yeni politikaya göre yeniden hazırlanır, model kayan
veriyle yeniden kurulur ve sayı 30'a döner. Kayıp kapanmıştır, ama kapanma bedeli bir dönüştür
ve dönüş ancak izleme adımı varsa görülür. İzleme olmasaydı sahadaki liste yedi kaçak eksik
üretmeye devam eder ve bunu kimse fark etmezdi.

#### Dönüşlerin Muhasebesi

```python
# donusler.py — akisin olcusu adim sayisi degil geri donus sayisidir.
F = [18, 20, 28, 16, 16]
w = lambda h: "".join(str(v).ljust(F[i]) for i, v in enumerate(h))
print(w(["nereden", "nereye", "sebep", "donus oncesi", "donus sonrasi"]))
for d in DONUS:
    print(w(d))
print(f"\n{len(ADIM)} adimlik akis {len(DONUS)} geri donus uretti; "
      f"toplam adim ziyareti {sum(int(x[0][0]) - int(x[1][0]) + 1 for x in DONUS) + len(ADIM)}")
```

```
nereden           nereye              sebep                       donus oncesi    donus sonrasi   
5 degerlendirme   3 oznitelik secimi  fark esigin altinda         +0.0318         +0.1061         
6 dagitim         1 problem tanimi    kapasiteye sigmiyor         240 isaret      ilk 40'ta 30 kacak
7 izleme          2 veri hazirlama    olcum politikasi degisti    23 kacak        30 kacak        

7 adimlik akis 3 geri donus uretti; toplam adim ziyareti 22
```

Üç dönüşün üçü de farklı bir adımdan çıkıyor ve farklı bir adıma iniyor. Beşinci adımdan üçüncüye
dönüş kısadır ve üç adım yeniden ziyaret edilir; altıncıdan birinciye dönüş altı adımı, yedinciden
ikinciye dönüş yine altı adımı yeniden ziyaret ettirir. Doğrusal okunduğunda yedi adımlık olan
akış 22 adım ziyaretiyle tamamlanmıştır, yani her adım ortalama 3,1 kez ziyaret edilmiştir.

Muhasebenin kendisi de bir karardır. Burada bir dönüş, hedef adımdan çıkış adımına kadarki
bütün adımların yeniden yürütülmesi sayılmıştır. Bazı adımların gerçekten tekrarlanması
gerekmeyebilir — altıncıdan birinciye dönüşte veri hazırlama değişmemiştir — ve o durumda sayı
daha küçük çıkardı. Hangi muhasebeyle üretildiği yazılmadan 22 okunamaz.

Dönüş sayısı bir kusur ölçüsü değildir. Sıfır dönüşlü bir akış, kapılarının hiçbir şeyi
sınamadığı bir akıştır; birinci geçişte kapı olmasaydı 0,0318'lik bir model sahaya çıkardı ve
kimse bunu ölçmemiş olurdu. Dönüş, kapının çalıştığının kanıtıdır.

#### Özet

- Akış yedi adımdır ve doğrusal değildir; bu koşumda üç geri dönüş üretmiş, 22 adım ziyaretiyle
  tamamlanmıştır.
- Beşinci adımdaki kapı tabana göre farkı 0,0500 eşiğiyle sınar: üç sütunlu model 0,0318 verip
  kapıda kalır, dokuz sütunlu model 0,1061 verip geçer.
- Altıncı adımdaki kapı başarımı değil kısıtı ölçer: model 240 abone işaretler, günlük kapasite
  40'tır ve kısıt problemi sınıflandırmadan sıralamaya çevirir; sıralama ilk 40 ziyarette 30
  kaçak bulur, rastgele sıra 14.
- Yedinci adımda model değişmeden sayı düşer: ölçüm politikası değişince aynı model 23 kaçak
  bulur, çünkü dayandığı iki öznitelik silinmiştir; kayan veriyle yeniden kurulunca 30'a döner.
- Dönüş sayısı bir kusur ölçüsü değil, kapıların çalıştığının kanıtıdır; sıfır dönüş kapıların
  hiçbir şeyi sınamadığı anlamına gelir.

#### Sonraki Adım

Bu ders akışı tek bir masadan yürüttü: bir kişi soruyu yazdı, öznitelikleri seçti, modeli kurdu,
eşiği koydu ve sahayı izledi. Gerçekte bu adımlar farklı iş tanımları arasında bölünür ve
bölünme yalnız işi paylaştırmakla kalmaz, **teslim edilen şeyi** de değiştirir. Veri Analitiğine
Giriş kursu üç analist rolünü kabul ölçütleriyle ayırmıştı; sonraki ders aynı ayrımı makine
öğrenmesi tarafında yapar. Aynı kaçak problemi üç rolde üç ayrı çıktıya dönüşür ve üçü **üç ayrı
taban çizgisi** seçer: bir rol için taban sahanın bugünkü yordamı, bir diğeri için hâlihazırda
çalışan model, üçüncüsü için modelsiz kurulan sistemin kendisidir.

### Roller

Source: https://academia.sh/tr/kurslar/makine-ogrenmesine-giris/roller

Aynı kaçak problemi üç iş tanımında üç ayrı çıktıya ve üç ayrı taban çizgisine dönüşür. Veri bilimcinin tabanı sahanın bugünkü yordamıdır ve ilk 40 ziyarette 13 kaçak bulur, teslim ettiği model sırası 30 bulur, fark 17. Makine öğrenmesi mühendisinin tabanı bugün çalışan modeldir ve kayan veride 23 bulur, yeniden kurulan yordam 30 bulur, fark 7. Yapay zekâ mühendisinin tabanı modelsiz sistemdir ve en kötü durumda 21 bulur, sinyalli sistem 30 bulur, fark 9. Aynı teslim sayısı üç rolde 17, 7 ve 9 üretir; sayıyı belirleyen model değil seçilen tabandır. Yedeğe düşen sistem kayan veride 21 verir, hiç düşmeyen 23.

Önceki ders akışı tek bir masadan yürüttü: bir kişi soruyu yazdı, öznitelikleri seçti, modeli
kurdu, eşiği koydu ve sahayı izledi. Gerçekte bu adımlar farklı iş tanımları arasında bölünür ve
bölünme yalnız işi paylaştırmakla kalmaz, **teslim edilen şeyi** de değiştirir.

Veri Analitiğine Giriş kursu üç analist rolünü kabul ölçütleriyle ayırmıştı: ölçen rol sayıyı,
kararı bağlayan rol eşiği, genelleyen rol varsayımıyla birlikte bir genellemeyi teslim ediyordu.
Bu ders aynı ayrımı makine öğrenmesi tarafında yapar ve ölçtüğü şey teslimin kendisi değil,
**her rolün seçtiği taban çizgisidir**.

- **MK32.** Rol adları burada bir unvan değil bir **iş tanımıdır**: ne teslim edildiği ve hangi
  ölçüyle kabul edildiği. Hiçbir şirket, unvan standardı ya da belge anılmaz.
- **MK33. Veri bilimci** bir **bulgu** teslim eder: problem öngörülebilir mi ve ne kadar. Tabanı
  **sahanın bugünkü yordamıdır**, çünkü kanıtlaması gereken şey işin bugünkü hâlinden daha
  iyisinin mümkün olduğudur.
- **MK34. Makine öğrenmesi mühendisi** her gün çalışan bir **yordam** teslim eder. Tabanı
  **bugün çalışan modeldir**, çünkü işi bir şeyi baştan kanıtlamak değil, ayakta tutmaktır.
- **MK35. Yapay zekâ mühendisi** uçtan uca bir **sistem** teslim eder. Tabanı **modelsiz kurulan
  aynı sistemdir** ve ölçüsü ortalama değil **en kötü durumdur**, çünkü bir sistem en kötü
  gününde ne verdiği kadar güvenilirdir.
- **MK36.** Üç rol aynı ölçüyü kullanır ve üçü de 30 teslim eder, ama üç ayrı kazanç sayısı
  üretir. Sayıyı belirleyen model
  değil, seçilen taban çizgisidir.
- **MK37.** Bir yedek yol, ölçülmeden iyileştirme sayılmaz. Bu koşumda yedeğe düşen sistem kayan
  veride hiç düşmeyenden daha az kaçak bulmaktadır.

#### Kurgu Kümenin Yeniden Kurulması

```python
# kurulum.py — 01. dersin kurgu kumesi ayni tohumla yeniden kurulur: okuma
# tablosu, abone ozeti, kurgu etiket, egitim / ayrilmis ayrimi ve agac ogrenici.
import math

TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF
BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26),
         ("bati", 0.14, 14), ("merkez", 0.18, 23)]
OZNITELIK = ["ortalama", "kisi_basi", "dusus", "sifir_okuma", "okuma_sayisi",
             "memnuniyet", "hane_kisi", "en_yuksek", "en_dusuk"]


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


_ab, _el, _seri = [], [], {}
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    k = {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2],
         "hane_kisi": ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05]),
         "memnuniyet": ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17]) + 1}
    (_el if r() < 0.046 else _ab).append(k)
_gecerli = {a["abone_no"] for a in _ab}
for k in _ab + _el:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp(
            (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100
        if k["abone_no"] in _gecerli:
            _seri.setdefault(k["abone_no"], []).append(t)
        r()

ABONE = []
for k in _ab:
    t = _seri.get(k["abone_no"])
    if not t:
        continue
    ort = sum(t) / len(t)
    a = {"abone_no": k["abone_no"], "bolge": k["bolge"], "seri": t,
         "hane_kisi": k["hane_kisi"], "memnuniyet": k["memnuniyet"],
         "okuma_sayisi": len(t), "ortalama": ort, "en_yuksek": max(t),
         "en_dusuk": min(t), "sifir_okuma": sum(1 for v in t if v == 0),
         "kisi_basi": ort / max(1, k["hane_kisi"]),
         "dusus": (t[0] - t[-1]) / t[0] if len(t) > 1 and t[0] > 0 else 0.0}
    r = uretec(TOHUM + 31000 + a["abone_no"])
    a["suphe"] = 1 if (1.30 * a["sifir_okuma"] + 1.25 * (a["dusus"] > 0.45)
                       + 1.05 * (a["kisi_basi"] > 12.0) + 0.65 * (a["okuma_sayisi"] < 3)
                       + 0.45 * (a["memnuniyet"] <= 2) - 1.55
                       + (r() + r() - 1.0) * 1.1) > 0 else 0
    ABONE.append(a)

r = uretec(TOHUM + 90001)
EGITIM, AYRILMIS = [], []
for a in ABONE:
    (EGITIM if r() < 0.70 else AYRILMIS).append(a)
poz = lambda k: sum(a["suphe"] for a in k)
dogruluk = lambda f, k: sum(1 for a in k if f(a) == a["suphe"]) / len(k)
_saf = lambda k: 2 * (poz(k) / len(k)) * (1 - poz(k) / len(k)) if k else 0.0


def ogren(k, derinlik=3, en_az=40):
    """01. dersin acgozlu karar agaci: bolme olcutu ve durma kurali orada."""
    en, secim = _saf(k) * len(k), None
    if derinlik and len(k) >= en_az:
        for oz in OZNITELIK:
            for e in sorted({a[oz] for a in k})[1:]:
                sol = [a for a in k if a[oz] < e]
                sag = [a for a in k if a[oz] >= e]
                m = _saf(sol) * len(sol) + _saf(sag) * len(sag)
                if m < en - 1e-9:
                    en, secim = m, (oz, e, sol, sag)
    if secim is None:
        return 1 if 2 * poz(k) > len(k) else 0
    s, g = ogren(secim[2], derinlik - 1, en_az), ogren(secim[3], derinlik - 1, en_az)
    return s if s == g else (secim[0], secim[1], s, g)


def uygula(d, a):
    while isinstance(d, tuple):
        d = d[2] if a[d[0]] < d[1] else d[3]
    return d


print(f"kurgu kume (tohum {TOHUM}): {len(ABONE)} abone, {len(EGITIM)} egitim, "
      f"{len(AYRILMIS)} ayrilmis, {poz(ABONE)} supheli")
```

```
kurgu kume (tohum 20260218): 1260 abone, 883 egitim, 377 ayrilmis, 327 supheli
```

#### Ortak Ölçü, Beş Sıralayıcı

Üç rolün karşılaştırılabilmesi için ölçü ortak olmalıdır. Ortak ölçü önceki dersten gelir:
günlük kapasite 40 ziyarettir ve sayılan şey ilk 40 ziyarette bulunan kaçaktır. Ortak olmayan
şey her rolün bu ölçüyü hangi tabana karşı okuduğudur.

Beş sıralayıcı iki veri düzeninde ölçülür. Birinci düzen dersin başındaki tablodur; ikincisi
önceki derste kurulan kaymadır — ölçüm politikası değişmiş, sıfır okumalar kestirimle
doldurulmuş, eksik dönemler tamamlanmıştır. Etiket iki düzende de aynıdır.

```python
# siralayicilar.py — uc rolun ortak olcusu: gunluk kapasite kadar ziyarette
# bulunan kacak. Bes ayri siralayici ve iki ayri veri duzeni yan yana olculur.
import statistics
from collections import Counter

KAPASITE = 40
r = uretec(TOHUM + 7205)
CALISAN = [ogren([EGITIM[int(r() * len(EGITIM))] for _ in EGITIM]) for _ in range(9)]
r = uretec(TOHUM + 7206)
kura = {a["abone_no"]: r() for a in ABONE}
ilk = lambda f, s: poz(sorted(s, key=f)[:KAPASITE])
sira = lambda T: (lambda a: (-sum(uygula(d, a) for d in T), a["abone_no"]))
saha = lambda a: (-a["ortalama"], a["abone_no"])
elle = lambda a: 1 if (a["sifir_okuma"] >= 1 or a["dusus"] > 0.50
                       or a["kisi_basi"] > 15.0) else 0
kural = lambda a: (-elle(a), -a["ortalama"], a["abone_no"])


def kayan(a):
    """05. dersteki olcum politikasi degisikligi: sifir okumalar kestirimle
    doldurulur, eksik donemler tamamlanir. Etiket degismez."""
    dolu = [v for v in a["seri"] if v > 0]
    tem = round(statistics.fmean(dolu), 2) if dolu else 0.0
    t = [v if v > 0 else tem for v in a["seri"]] + [tem] * (3 - len(a["seri"]))
    ort = sum(t) / len(t)
    return {**a, "seri": t, "okuma_sayisi": 3, "ortalama": ort, "en_yuksek": max(t),
            "en_dusuk": min(t), "sifir_okuma": sum(1 for v in t if v == 0),
            "kisi_basi": ort / max(1, a["hane_kisi"]),
            "dusus": (t[0] - t[-1]) / t[0] if t[0] > 0 else 0.0}


KAYAN_E, KAYAN_A = [kayan(a) for a in EGITIM], [kayan(a) for a in AYRILMIS]
r = uretec(TOHUM + 7305)
GUNCEL = [ogren([KAYAN_E[int(r() * len(KAYAN_E))] for _ in KAYAN_E]) for _ in range(9)]
isaret = lambda s: sum(1 for a in s if a["sifir_okuma"] > 0 or a["okuma_sayisi"] < 3) / len(s)

E = [33, 12, 12, 12, 12]
y = lambda h: str(h[0]).ljust(E[0]) + "".join(str(v).rjust(E[i + 1])
                                              for i, v in enumerate(h[1:]))
SIRALAYICI = [("rastgele sira", lambda a: kura[a["abone_no"]]),
              ("sahanin yordami: en cok tuketen", saha),
              ("elle yazilmis kural sirasi", kural),
              ("calisan model sirasi", sira(CALISAN)),
              ("kayan veriyle kurulan model", sira(GUNCEL))]
print(f"ilk {KAPASITE} ziyarette bulunan kacak")
print(y(["siralayici", "eski eg.", "eski ayr.", "kayan eg.", "kayan ayr."]))
SAYI = {}
for ad, f in SIRALAYICI:
    SAYI[ad] = [ilk(f, EGITIM), ilk(f, AYRILMIS), ilk(f, KAYAN_E), ilk(f, KAYAN_A)]
    print(y([ad] + SAYI[ad]))
print(f"\nveri kalitesi sinyali (sifir okumasi ya da eksik donemi olan abone payi): "
      f"eskide {isaret(AYRILMIS):.4f}, kayanda {isaret(KAYAN_A):.4f}")
print(f"ayrilmis kumede {poz(AYRILMIS)} supheli var; {KAPASITE} ziyaretin tavani {KAPASITE}")
```

```
ilk 40 ziyarette bulunan kacak
siralayici                           eski eg.   eski ayr.   kayan eg.  kayan ayr.
rastgele sira                              10          14          10          14
sahanin yordami: en cok tuketen            17          13          18          14
elle yazilmis kural sirasi                 25          21          26          21
calisan model sirasi                       30          30          33          23
kayan veriyle kurulan model                40          30          39          30

veri kalitesi sinyali (sifir okumasi ya da eksik donemi olan abone payi): eskide 0.3740, kayanda 0.0027
ayrilmis kumede 93 supheli var; 40 ziyaretin tavani 40
```

Tablo beş satırda beş ayrı yordam gösteriyor. Rastgele sıra 14 kaçak buluyor ve iki düzende de
sabit; sorunun zorluğu değişmemiştir. Sahanın bugünkü yordamı — en çok tüketenden başlamak —
ayrılmış kümede 13 buluyor, yani rastgele sıradan bile bir kaçak geride. Elle yazılmış kural
sırası 21 buluyor. Çalışan model 30 buluyor, kayan veride 23'e düşüyor. Kayan veriyle yeniden
kurulan model iki düzende de 30 veriyor.

Son satırdaki veri kalitesi sinyali kaymanın nereden geldiğini söylüyor: sıfır okuması ya da
eksik dönemi olan abone payı 0,3740'tan 0,0027'ye inmiştir. Modelin dayandığı iki sütun
tablodan silinmiştir ve bunu ölçen şey model değil, verinin kendisine bakan bir sayaçtır.

#### Üç Rol, Üç Taban

```python
# roller.py — ayni model, uc is tanimi, uc ayri taban cizgisi. Her rol kendi
# tabanini secer ve teslim ettigi sey o tabanla karsilastirilir.
EN_KOTU = lambda s: min(s[1], s[3])  # iki veri duzeninin ayrilmis kume sayilari
CALISAN_AD = "calisan model sirasi"
GUNCEL_AD = "kayan veriyle kurulan model"
YEDEKLI = [SAYI[CALISAN_AD][0], SAYI[CALISAN_AD][1],
           SAYI["elle yazilmis kural sirasi"][2], SAYI["elle yazilmis kural sirasi"][3]]

ROL = [
    ("veri bilimci", "sahanin bugunku yordami",
     SAYI["sahanin yordami: en cok tuketen"][1], "model sirasi",
     SAYI[CALISAN_AD][1]),
    ("makine ogrenmesi muh.", "bugun calisan model, kayan veride",
     SAYI[CALISAN_AD][3], "yeniden kurulan yordam", SAYI[GUNCEL_AD][3]),
    ("yapay zeka muhendisi", "modelsiz sistem, en kotu durum",
     EN_KOTU(SAYI["elle yazilmis kural sirasi"]), "sinyalli sistem, en kotu durum",
     EN_KOTU(SAYI[GUNCEL_AD])),
]
D = [24, 34, 10, 32, 10, 8]
z = lambda h: str(h[0]).ljust(D[0]) + str(h[1]).ljust(D[1]) + str(h[2]).rjust(D[2]) \
    + "  " + str(h[3]).ljust(D[3]) + str(h[4]).rjust(D[4]) + str(h[5]).rjust(D[5])
print(z(["rol", "sectigi taban cizgisi", "taban", "teslim ettigi", "teslim", "fark"]))
for ad, tb_ad, tb, ts_ad, ts in ROL:
    print(z([ad, tb_ad, tb, ts_ad, ts, f"{ts - tb:+d}"]))
print(f"\nyedege dusen sistem (sinyal dustugunde kural sirasina gecer): "
      f"eski veride {YEDEKLI[1]}, kayan veride {YEDEKLI[3]}, en kotu {min(YEDEKLI[1], YEDEKLI[3])}")
print(f"hic dusmeyen sistem: eski {SAYI[CALISAN_AD][1]}, kayan {SAYI[CALISAN_AD][3]}, "
      f"en kotu {EN_KOTU(SAYI[CALISAN_AD])}")
```

```
rol                     sectigi taban cizgisi                  taban  teslim ettigi                       teslim    fark
veri bilimci            sahanin bugunku yordami                   13  model sirasi                            30     +17
makine ogrenmesi muh.   bugun calisan model, kayan veride         23  yeniden kurulan yordam                  30      +7
yapay zeka muhendisi    modelsiz sistem, en kotu durum            21  sinyalli sistem, en kotu durum          30      +9

yedege dusen sistem (sinyal dustugunde kural sirasina gecer): eski veride 30, kayan veride 21, en kotu 21
hic dusmeyen sistem: eski 30, kayan 23, en kotu 23
```

Aynı ölçü, aynı teslim sayısı — ve üç ayrı kazanç: 17, 7 ve 9 kaçak. Üç sayı da doğrudur ve
hiçbiri diğerinin yerine yazılamaz.

Veri bilimcinin 17'si bir kanıttır: sahanın bugünkü yordamı 40 ziyarette 13 kaçak buluyorsa ve
bir model 30 buluyorsa, bu problem öğrenilebilir bir problemdir. Bu sayının ömrü kısadır; bir kez
kanıtlandıktan sonra kimse aynı tabanı ikinci kez yazmaz.

Makine öğrenmesi mühendisinin 7'si bir bakım sayısıdır. Sahada zaten bir model çalışmaktadır ve
o model kayan veride 23 vermektedir; teslim edilen yordam 30 verir. Yedi kaçak küçük görünür ama
tabanı 13 değil 23'tür — mühendisin işi sıfırdan bir kazanç üretmek değil, üretilmiş kazancı
kaybetmemektir.

Yapay zekâ mühendisinin 9'u bir dayanıklılık sayısıdır ve tek bir sayı değil **iki düzenin en
kötüsüdür**. Modelsiz sistem her iki düzende de 21 verir; sinyalli sistem en kötü durumda 30
verir. Aradaki 9, ortalama bir kazanç değil, garanti edilen en düşük değerin farkıdır.

#### Yedek Yolun Ölçülmesi

Son iki satır bir tasarım kararını çürütüyor. Sinyal düştüğünde modeli bırakıp elle yazılmış
kural sırasına geçen bir sistem, kayan veride 21 kaçak buluyor. Hiç düşmeyen, yani bozuk
öznitelikle çalışmayı sürdüren sistem 23 buluyor. Yedeğe düşmek sayıyı **iki kaçak
kötüleştiriyor**.

Bunun anlamı yedek yolun gereksiz olduğu değildir. Sinyalin değeri yedeğe geçmekte değil,
**haber vermektedir**: 0,3740'tan 0,0027'ye inen bir sayaç, önceki dersteki yedinci adımdan
ikinci adıma dönüşü tetikleyen şeydir ve o dönüş sonucunda kurulan model 30 vermektedir. Sinyal
olmasaydı saha listesi yedi kaçak eksik üretmeye devam eder, yedeğe düşen sistemde ise dokuz
kaçak eksik üretirdi.

Üç rolün ortak yanı burada görünüyor. Üçü de bir sayı teslim ediyor, üçü de o sayının yanına
kendi tabanını yazıyor ve üçünün tabanı da bir seçimdir. Taban yazılmadığında üç rol de aynı
cümleyi kurabilir: "sistem 40 ziyarette 30 kaçak buluyor." Bu cümle üç kez doğru, üç kez
ölçülmemiştir.

#### Özet

- Rol adları burada iş tanımıdır: ne teslim edildiği ve hangi ölçüyle kabul edildiği. Ölçü
  üçünde de aynıdır — ilk 40 ziyarette bulunan kaçak — tabanları farklıdır.
- Veri bilimcinin tabanı sahanın bugünkü yordamıdır ve 13 kaçak bulur; teslim ettiği model
  sırası 30 bulur, fark 17.
- Makine öğrenmesi mühendisinin tabanı bugün çalışan modeldir ve kayan veride 23 bulur; teslim
  ettiği yeniden kurulan yordam 30 bulur, fark 7.
- Yapay zekâ mühendisinin tabanı modelsiz sistemdir ve en kötü durumda 21 bulur; sinyalli
  sistemin en kötü durumu 30'dur, fark 9.
- Yedeğe düşen sistem kayan veride 21, hiç düşmeyen 23 bulur: bir yedek yol ölçülmeden
  iyileştirme sayılmaz ve sinyalin değeri yedekte değil haber vermektedir.
- Aynı teslim sayısı üç rolde 17, 7 ve 9 üretir; sayıyı belirleyen model değil seçilen tabandır.

#### Sonraki Adım

Altı ders boyunca her tablonun üç sütunu vardı: taban çizgisi, eğitimde ölçülen ve ayrılmış
kümede ölçülen. Üçüncü sütun her seferinde basıldı ve hiçbir derste sorgulanmadı. Ayrımın
niçin yapıldığı, hangi oranla yapıldığı, aynı ayrılmış kümeye kaç kez bakılabileceği, iki sayının
niçin ayrıştığı bir kez bile sorulmadı. Sayı basıldı, yanından geçildi.

Oysa bu konuda o sütun birkaç kez konuşmaya çalıştı. Elle yazılmış kural eğitimde tabanı geçip
ayrılmış kümede altında kaldı. Otuz etiketle kurulan model eğitimde 0,9400, ayrılmış kümede
0,7745 verdi ve etiket arttıkça iki sayı birbirine yaklaştı. Kayan veriyle kurulan model eğitim
kümesinde 40 ziyaretin 40'ını da kaçakla doldurdu, ayrılmış kümede 30'da kaldı. Üç durumda da
aynı şey oldu: modelin **gördüğü** veride ölçülen sayı, **görmediği** veride ölçülenden yüksek
çıktı ve aradaki açık hiç açıklanmadı.

Sonraki konu bu açığı ele alır. Ayrımın gerekçesi yazılır, eğitim, doğrulama ve sınama kümeleri
birbirinden ayrılır, model karmaşıklığı adım adım artırıldığında iki sayının hangi noktada
ayrışmaya başladığı sayılır, aynı yordamın farklı örneklemlerde ne kadar oynadığı ölçülür ve
ayrılmış kümede ölçülen sayıyı gerçekte olduğundan büyük gösteren dört ayrı yol tek tek
uygulanır.

## Genelleme

Modelin görmediği veride ne yapacağının ölçülmesi ve bu ölçünün nasıl bozulduğu: eğitim, doğrulama ve sınama kümelerinin ayrım gerekçesi ile sınama kümesine kaç kez bakılabileceği, kapasite arttıkça eğitim ve ayrılmış küme sayılarının ayrıştığı nokta, aynı yordamın farklı eğitim örneklemlerinde ne kadar oynadığı, ceza katsayısı artarken iki sayının ters yönde hareket etmesi ve en iyi noktanın doğrulama kümesinden okunması, dört sızıntı türünün ayrılmış küme sayısını ne kadar şişirdiği.

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

Source: https://academia.sh/tr/kurslar/makine-ogrenmesine-giris/egitim-dogrulama-ve-test-kumeleri

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: kırk sekiz adayın ortalama doğrulaması 0,7875,
ortalama sınaması 0,7657 ve bu fark hiç seçim yapılmadan da duruyor. Yani 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. Kırk sekiz 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.

### Aşırı ve Eksik Uyum

Source: https://academia.sh/tr/kurslar/makine-ogrenmesine-giris/asiri-ve-eksik-uyum

Kapasite adım adım artırılırken eğitim ve ayrılmış küme sayılarının ayrışmasının ölçülmesi: karar ağacının derinliği 1'den 14'e çıkarken eğitim doğruluğu 0,7778'den 0,9352'ye yükselir, ayrılmış küme doğruluğu 0,8214'te tepe yapıp 0,7302'ye iner ve iki sayı arasındaki fark -0,0357'den +0,2050'ye açılır. On bir kapasitenin yalnız dördü ayrılmış kümede 0,8135'lik tabanı tutturabiliyor. Eğitim kümesi 100'den 756 satıra çıkarıldığında fark 0,2219'dan 0,1680'e iner, yaprak alt sınırı 2'den 80'e çıkarıldığında 0,1680'den -0,0198'e iner ve model tam olarak taban çizgisine dönüşür.

Önceki ders bir karar ağacını üç kümede ölçtü ve üç sayı buldu, ama ağacın derinliğini gerekçesiz
seçti. Derinlik 6 bir tercih değil bir boşluktu. Derinlik ağacın **kapasitesidir**: kaç ayrı kural
öğrenebileceğini, kümeyi kaç parçaya bölebileceğini belirler. Kapasite tek başına iyi ya da kötü
değildir; iki sayıyı birden oynatır ve **ters yönlerde** oynatır.

Bu ders kapasiteyi 1'den 14'e çıkarır, her adımda eğitim ve ayrılmış küme sayısını yan yana basar
ve ikisinin ayrıştığı noktayı yazar. Ayrışmanın iki ucu iki ayrı bozulmadır: kapasite yetmediğinde
**eksik uyum**, kapasite fazla geldiğinde **aşırı uyum**. Sınama kümesine bu derste hiç
bakılmayacak; ayrılmış küme olarak doğrulama kümesi kullanılır.

- **GE9.** Küme, etiket ve bölme önceki dersten aynen sürer: 1.260 abone, 756 eğitim, 252
  doğrulama, 252 sınama, tohum 20260218. Etiket kurgudur.
- **GE10.** Kapasitenin ölçüsü iki sayıdır: ağacın derinliği ve yaprak sayısı. Yaprak sayısı,
  modelin kümeyi kaç ayrı bölgeye ayırdığını verir.
- **GE11.** Taban çizgisi tek yapraklı bir ağaçtır: hiç bölmeyen, herkese eğitim kümesinin en sık
  sınıfını söyleyen yordam. Kapasite dizisinin sıfırıncı adımıdır.
- **GE12.** Ayrılmış küme doğrulama kümesidir. Sınama kümesi bu derste açılmaz; önceki dersin
  kuralı gereği ona kapanışta bir kez bakılır.
- **GE13.** Yaprak alt sınırı ikinci bir kapasite düğmesidir: bir yaprağın altına düşebilecek en az
  gözlem sayısı. Varsayılan 2'dir.
- **GE14.** Öğrenme eğrisi çizilmez, sayı olarak basılır: eğitim kümesi büyütülürken iki sayının
  aldığı değerler tablodur.
- **GE15.** Ayrılmış küme 252 satırlıktır; bir abone 0,0040 doğruluk eder. İki puanın altındaki
  farklar bu yüzden bir sıralama kanıtı sayılmaz.

#### Kapasite Arttıkça İki Sayı Ayrışır

Kurulum önceki dersle aynıdır ve aynı tohumla aynı kümeyi üretir. Üzerine tek bir ekleme yapılır:
yaprak sayacı.

```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"]


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, 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)


def yaprak(d):
    return 1 if "tahmin" in d else yaprak(d["sol"]) + yaprak(d["sag"])


print(f"{'kapasite':>10} {'yaprak':>7} {'egitim':>8} {'ayrilmis':>9} {'fark':>8}")
print(f"{'taban':>10} {1:>7} {taban(EGT, EGT):>8.4f} {taban(EGT, DOG):>9.4f} "
      f"{taban(EGT, EGT) - taban(EGT, DOG):>+8.4f}")
for dr in (1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14):
    m = agac(EGT, dr)
    e, a = dogruluk(m, EGT), dogruluk(m, DOG)
    print(f"{'derinlik ' + str(dr):>10} {yaprak(m):>7} {e:>8.4f} {a:>9.4f} {e - a:>+8.4f}")
```

```
  kapasite  yaprak   egitim  ayrilmis     fark
     taban       1   0.7778    0.8135  -0.0357
derinlik 1       2   0.7778    0.8135  -0.0357
derinlik 2       4   0.8016    0.8214  -0.0198
derinlik 3       8   0.8135    0.8135  +0.0000
derinlik 4      16   0.8201    0.8175  +0.0026
derinlik 5      30   0.8360    0.8095  +0.0265
derinlik 6      46   0.8466    0.7897  +0.0569
derinlik 7      64   0.8611    0.7698  +0.0913
derinlik 8      81   0.8770    0.7778  +0.0992
derinlik 10     112   0.9061    0.7698  +0.1362
derinlik 12     133   0.9299    0.7619  +0.1680
derinlik 14     139   0.9352    0.7302  +0.2050
```

Üçüncü sütun tek yönlüdür: kapasite arttıkça eğitim doğruluğu 0,7778'den 0,9352'ye kesintisiz
yükseliyor. Bu sütun bir başarı ölçüsü değil, bir kapasite ölçüsüdür — modele daha çok bölme izni
verildikçe gördüğü veriyi daha çok ezberler ve sütun her koşulda yükselir.

Dördüncü sütun iki yönlüdür. Ayrılmış küme doğruluğu derinlik 2'de 0,8214 ile tepe yapıyor, sonra
düşmeye başlıyor ve derinlik 14'te 0,7302'ye iniyor. Beşinci sütun ikisinin farkıdır ve
ayrışmanın nerede başladığını verir: fark derinlik 3'te sıfırı geçiyor, derinlik 5'ten sonra hiç
geri dönmeden büyüyor ve derinlik 14'te 0,2050'ye ulaşıyor. **Ayrışmanın başladığı nokta derinlik
4 ile 5 arasındadır**: dördüncü adımda fark hâlâ 0,0026 iken beşincide 0,0265'e, altıncıda
0,0569'a çıkıyor.

Taban çizgisiyle birlikte okununca tablo daha sert bir şey söylüyor. Ayrılmış kümede taban 0,8135.
On bir kapasitenin yalnız **dördü** — derinlik 1, 2, 3 ve 4 — bu sayıya erişiyor ya da onu
geçiyor; ikisi tam eşitliyor, ikisi geçiyor ve
en iyisi tabanı 0,0079 geçiyor. Derinlik 5'ten itibaren **her model tabanın altındadır**, üstelik
eğitim sütunu hâlâ yükselmektedir. Derinlik 14'te modelin eğitim kümesinde 0,9352 okuduğu anda
ayrılmış kümede "hiçbiri şüpheli değil" demekten 8,3 puan kötüdür.

Yaprak sütunu ezberin nasıl büyüdüğünü gösteriyor. Derinlik 14'te ağacın 139 yaprağı var ve eğitim
kümesi 756 satır: yaprak başına ortalama 5,4 abone. Beş aboneye bakarak kurulmuş bir kural, o beş
aboneyi doğru sınıflandırır ve başka hiçbir şey hakkında bir şey söylemez.

#### Ağacın Kurduğu Kural

Ayrışmanın nereden geldiği, modelin ne öğrendiğine bakınca görünür. Aşağıdaki kod tepedeki ağacın
kurallarını açıkça yazıyor ve dipteki ağacın yapraklarının kaç aboneye baktığını sayıyor.

```python
def kurallar(d, s, yol=""):
    if "tahmin" in d:
        print(f"  {yol or '(bolme yok)':<44} {len(s):>4} abone -> {d['tahmin']}")
        return
    a, v = d["alan"], d["esik"]
    kurallar(d["sol"], [x for x in s if x[a] < v], f"{yol}{a} < {v} ")
    kurallar(d["sag"], [x for x in s if x[a] >= v], f"{yol}{a} >= {v} ")


print("derinlik 2 agacinin kurallari")
kurallar(agac(EGT, 2), EGT)


def boyutlar(d, s, c):
    if "tahmin" in d:
        c.append(len(s))
        return
    a, v = d["alan"], d["esik"]
    boyutlar(d["sol"], [x for x in s if x[a] < v], c)
    boyutlar(d["sag"], [x for x in s if x[a] >= v], c)


c = []
boyutlar(agac(EGT, 14), EGT, c)
c.sort()
print(f"\nderinlik 14: {len(c)} yaprak, en kucuk {c[0]}, ortanca {c[len(c) // 2]}, "
      f"en buyuk {c[-1]} abone")
print(f"5 aboneden az gorup kural kuran yaprak: {sum(1 for n in c if n < 5)}")
print(f"bu yapraklarin kapsadigi egitim abonesi: {sum(n for n in c if n < 5)}")
```

```
derinlik 2 agacinin kurallari
  oynaklik < 11.69 ort_tuketim < 18.54          262 abone -> 0
  oynaklik < 11.69 ort_tuketim >= 18.54         249 abone -> 0
  oynaklik >= 11.69 b_dogu < 1                  185 abone -> 0
  oynaklik >= 11.69 b_dogu >= 1                  60 abone -> 1

derinlik 14: 139 yaprak, en kucuk 2, ortanca 3, en buyuk 141 abone
5 aboneden az gorup kural kuran yaprak: 112
bu yapraklarin kapsadigi egitim abonesi: 300
```

Tepedeki ağacın dört yaprağından **üçü taban çizgisiyle aynı şeyi söylüyor**. Modelin tabandan
ayrıldığı tek yer, oynaklığı 11,69 m³'ün üstünde olan doğu abonelerinden oluşan 60 satırlık
yapraktır. Ayrılmış kümedeki 0,0079'luk kazancın tamamı bu tek kuraldan geliyor. Bir modelin
tabanı geçmesi, çoğu zaman tabanı her yerde geçmesi değil, tabanın yanıldığı dar bir bölgeyi
bulmasıdır.

Dipteki ağaç bunun tersidir. Yüz otuz dokuz yaprağın ortancası **üç aboneye** bakıyor, 112 yaprak
beşten az abone görmüş ve bu yapraklar eğitim kümesinin 300 satırını, yani yüzde 40'ını
kapsıyor. Eğitim sütunundaki 0,9352'nin büyük bölümü, üç aboneden çıkarılmış kurallarla o üç
aboneyi doğru bilmekten ibarettir. Ayrılmış kümede bu kuralların karşılığı yoktur.

#### İki Bozulmanın İmzaları Ayrıdır

Tablonun iki ucu iki ayrı bozulmadır ve belirtileri karışmaz.

**Eksik uyum** üstteki satırlardadır. Derinlik 1 ağacı iki yaprak kuruyor, ama iki yaprak da aynı
sınıfı söylüyor: ağaç bölünmüş, model bölünmemiştir. Sayıları taban çizgisiyle birebir aynıdır
(0,7778 ve 0,8135). İmzası şudur: **eğitim sayısı kendi tabanına yapışıktır.** Model gördüğü veriyi
bile açıklayamıyorsa görmediğini hiç açıklayamaz ve bunu anlamak için ayrılmış kümeye bakmak bile
gerekmez.

**Aşırı uyum** alttaki satırlardadır. İmzası iki sayının birden okunmasını gerektirir: eğitim
sayısı yüksek, ayrılmış küme sayısı düşük, fark büyük. Tek başına 0,9352 hiçbir şey söylemez —
ne iyidir ne kötüdür, çünkü hangi kapasiteyle üretildiği yazılmadıkça yorumlanamaz.

Farkın işareti tek başına da yetmez. Derinlik 1'de fark -0,0357 ile "güvenli" görünüyor, oysa o
satır modelin hiçbir şey öğrenmediği satırdır. Negatif fark iyi haber değil, çoğu zaman eksik uyum
haberidir. Üç sayı birlikte okunur: taban, eğitim, ayrılmış küme.

#### Düzeltmenin Ölçüsü

Aşırı uyumun iki bilinen düzeltmesi var: eğitim kümesini büyütmek ve kapasiteyi kısmak. İkisi de
ölçülebilir. Aşağıdaki kod derinliği 12'de sabitleyip önce eğitim kümesini, sonra yaprak alt
sınırını değiştiriyor.

```python
print("egitim kumesi buyutulur, kapasite sabit (derinlik 12)")
print(f"{'egitim satiri':>13} {'yaprak':>7} {'egitim':>8} {'ayrilmis':>9} {'fark':>8}")
for n in (100, 200, 400, 756):
    m = agac(EGT[:n], 12)
    e, a = dogruluk(m, EGT[:n]), dogruluk(m, DOG)
    print(f"{n:>13} {yaprak(m):>7} {e:>8.4f} {a:>9.4f} {e - a:>+8.4f}")

print("\nkapasite kisilir, egitim kumesi sabit (derinlik 12, yaprak alt siniri)")
print(f"{'yaprak enaz':>13} {'yaprak':>7} {'egitim':>8} {'ayrilmis':>9} {'fark':>8}")
for z in (2, 5, 10, 20, 40, 80):
    m = agac(EGT, 12, z)
    e, a = dogruluk(m, EGT), dogruluk(m, DOG)
    print(f"{z:>13} {yaprak(m):>7} {e:>8.4f} {a:>9.4f} {e - a:>+8.4f}")
```

```
egitim kumesi buyutulur, kapasite sabit (derinlik 12)
egitim satiri  yaprak   egitim  ayrilmis     fark
          100      15   0.9600    0.7381  +0.2219
          200      34   0.9500    0.7500  +0.2000
          400      68   0.9450    0.7659  +0.1791
          756     133   0.9299    0.7619  +0.1680

kapasite kisilir, egitim kumesi sabit (derinlik 12, yaprak alt siniri)
  yaprak enaz  yaprak   egitim  ayrilmis     fark
            2     133   0.9299    0.7619  +0.1680
            5      81   0.8624    0.7540  +0.1085
           10      44   0.8307    0.7937  +0.0370
           20      23   0.8148    0.7500  +0.0648
           40      13   0.8042    0.7897  +0.0146
           80       7   0.7937    0.8135  -0.0198
```

Birinci tablo öğrenme eğrisidir ve yönü doğru, gücü sınırlıdır. Eğitim kümesi 100'den 756 satıra,
yani 7,6 katına çıkarıldığında fark 0,2219'dan 0,1680'e iniyor: başlangıçtaki açıklığın yalnız
dörtte biri kapanmış. Ayrılmış küme sayısı 0,7381'den 0,7619'a yükseliyor ama 0,8135'lik tabanın
hâlâ 5,2 puan altında. **Veri eklemek, fazla seçilmiş bir kapasitenin borcunun bir kısmını öder,
tamamını ödemez.** Aynı eğrinin ikinci okuması eğitim sütunudur: 0,9600'den 0,9299'a düşüyor, çünkü
aynı kapasiteyle daha çok satır ezberlemek daha zordur.

İkinci tablo doğrudan kapasiteye dokunuyor ve iki ucu nettir. Yaprak alt sınırı 2'den 80'e
çıkarıldığında yaprak sayısı 133'ten 7'ye, fark 0,1680'den -0,0198'e iniyor. Son satır dikkat
çekicidir: kapasite yeterince kısıldığında model ayrılmış kümede tam olarak 0,8135 okuyor, yani
**taban çizgisinin kendisine dönüşüyor**. Aşırı uyumu düzeltmek için kapasiteyi kısmak, yeterince
ileri götürüldüğünde eksik uyuma çıkar. İki bozulma kullanılabilir bölgeyi iki yandan sınırlar.

Aradaki satırlar dikkatle okunur. Ayrılmış küme sütunu 0,7937'den 0,7500'e inip 0,7897'ye
dönüyor; bu 11 ve 10 abonelik oynamalardır ve M26/K05'te ölçülen oynama payının içinde kalır. Bu
sütunun ortasındaki sıralamayı bir kapasite kanıtı saymak, bir kez daha, seçilmiş bir sayıyı
başarım sanmak olur. Güvenilir okuma iki uçtadır ve fark sütunundadır.

#### Özet

- Kapasite arttıkça eğitim doğruluğu tek yönlü yükseliyor (0,7778'den 0,9352'ye), ayrılmış küme
  doğruluğu derinlik 2'de 0,8214 ile tepe yapıp 0,7302'ye iniyor; iki sayının farkı -0,0357'den
  +0,2050'ye açılıyor ve ayrışma derinlik 4 ile 5 arasında başlıyor.
- On bir kapasiteden yalnız dördü ayrılmış kümede 0,8135'lik tabanı tutturuyor; derinlik 5'ten
  sonra her model tabanın altındadır, üstelik eğitim sütunu yükselmeye devam etmektedir.
- Eksik uyumun imzası eğitim sayısının kendi tabanına yapışık olmasıdır ve ayrılmış kümeye bakmadan
  görülür; aşırı uyumun imzası ancak iki sayı birlikte okununca görünür.
- Eğitim kümesini 7,6 katına çıkarmak farkı 0,2219'dan 0,1680'e indiriyor, yani açıklığın dörtte
  birini kapatıyor; veri eklemek fazla seçilmiş kapasitenin borcunun tamamını ödemez.
- Yaprak alt sınırını 2'den 80'e çıkarmak yaprak sayısını 133'ten 7'ye, farkı -0,0198'e indiriyor
  ve model ayrılmış kümede tam olarak taban çizgisine dönüşüyor: aşırı uyumun düzeltmesi yeterince
  ileri gidince eksik uyuma çıkar.

#### Sonraki Adım

Bu derste fark tek bir eğitim kümesi üzerinde ölçüldü. Oysa 756 satırlık o küme, 1.260 abone
arasından çekilmiş **bir** örneklemdir; başka bir çekimde başka bir ağaç kurulurdu. Aşırı uyumun
altında bu yatıyor: yüksek kapasiteli bir yordamın ürettiği model, eğitim örneklemi değiştiğinde
çok oynar; düşük kapasiteli bir yordam ise hep aynı yerde durur ama hep aynı yerde yanılır. Sonraki
ders hatayı bu iki bileşene ayırır — sistemli olarak sapma ile örneklemden örnekleme oynama — ve
geri koyarak örneklemeyle birden çok eğitim kümesi kurup her ikisini ayrı ayrı sayar.

### Yanlılık–Değişkenlik Dengesi

Source: https://academia.sh/tr/kurslar/makine-ogrenmesine-giris/yanlilik-degiskenlik-dengesi

Ayrılmış kümedeki hatanın iki bileşene ayrılması: 30 geri koyarak örneklemle kurulan eğitim kümeleri üzerinde toplam kare hata taban çizgisinde 41,242, derinlik 3 ağacında 29,768 ve derinlik 12 ağacında 33,810 m³ kare çıkar; değişkenlik bileşeni 0,040'tan 4,409'a yükselirken yanlılık ve gürültü bileşeni 41,202'den 28,448'e iner ve orada durur. Kapasitenin sökebildiği yanlılık 12,754 m³ karedir, geri kalan 28,4 m³ kareyi hiçbir kapasite sökemez. Aynı abone için 30 modelin verdiği tahminin ortalama açıklığı derinlik 1'de 3,587 m³, derinlik 12'de 8,172 m³'tür.

Önceki ders kapasiteyi artırıp iki sayının ayrıştığını gösterdi, ama ölçümün tamamı **tek bir**
eğitim kümesi üzerinde yapıldı. Oysa o 756 satır, 1.260 abone arasından çekilmiş bir örneklemdir.
Başka bir çekimde başka bir ağaç kurulur, başka eşikler seçilir ve aynı abone için başka bir yanıt
üretilir. Ayrılmış kümedeki hatanın bir kısmı işte buradan gelir: modelin **yanıldığından** değil,
modelin **oynadığından**.

Bu ders hatayı iki bileşene ayırır. Birincisi aynı yordamın eğitim örneklemi değiştikçe ne kadar
oynadığı — **değişkenlik**. İkincisi bütün örneklemler üzerinden alınan ortalama tahminin gerçek
değerden ne kadar saptığı — **yanlılık**. İkisi aynı düğmeye, kapasiteye, ters yönlerde bağlıdır ve
toplamları ortada en küçüktür.

- **GE16.** Bu derste problem **bağlanımdır** (regression): sayısal bir değeri kestirmek. M26'nın
  İstatistiksel Analiz ve Keşifsel Veri Analizi kursunda "regresyon" bir ilişkinin katsayısını
  yorumlamak için kullanılmıştı; burada ölçü katsayı değil, görülmemiş bir abone için üretilen
  sayının hatasıdır.
- **GE17.** Hedef abonenin ortalama tüketimidir (m³) ve okumalardan türetilir. Öznitelikler
  okumalardan türetilen hiçbir alanı içermez: bölge, hane büyüklüğü, memnuniyet, dönem sayısı.
- **GE18.** Ölçü kök ortalama kare hatadır (m³). Bileşenlere ayırma kare birimde yapılır, çünkü
  toplanabilirlik yalnız orada geçerlidir.
- **GE19.** Küme, bölme ve tohum önceki derslerden aynen sürer: 1.260 abone, 756 eğitim, 252
  ayrılmış küme. Sınama kümesi yine açılmaz.
- **GE20.** Geri koyarak örnekleme M26'nın aynı kursunda kurulmuştur ve yöntemi burada
  tekrarlanmaz. Tek kullanımı, elde bir eğitim kümesi varken otuz eğitim kümesi varmış gibi ölçüm
  yapabilmektir.
- **GE21.** Sabit bir abone ve $B$ model için şu eşitlik tamdır: ortalama kare hata, tahminlerin
  kendi arasındaki saçılması ile ortalama tahminin gerçek değerden uzaklığının karesinin
  toplamıdır. Tablodaki üç sütun bu eşitliktir.
- **GE22.** Üçüncü sütun yanlılığı **ve indirgenemez gürültüyü birlikte** taşır; tek bir gözlemle
  ikisi ayrılamaz. Gürültü kapasiteden bağımsız olduğu için o sütundaki **farklar** yanlılık
  farkıdır.

#### Bağlanımda Aynı İki Sayı

Kurulum aynı kurgu ağı aynı tohumla üretir, hedefi abonenin ortalama tüketimi olarak alır ve bir
bağlanım ağacı kurar. Ağaç sınıflandırma ağacıyla aynı yapıdadır; tek farkı, yaprakta çoğunluk
sınıfı yerine **ortalama** söylemesi ve bölmeyi sınıf saflığına göre değil kare sapmaya göre
seçmesidir.

```python
# baglanim.py — MODELDIR. M26'nin kurgu olcum agi ayni tohumla uretilir; hedef
# abonenin ortalama tuketimidir ve okumalardan turetilir.
import math

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


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})
VERI = []
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
    x = {"no": k["no"], "hane": k["hane"], "memnuniyet": k["memnuniyet"],
         "donem": len(v), "hedef": round(sum(v) / len(v), 2)}
    for b in BOLGE:
        x["b_" + b[0]] = int(k["bolge"][0] == b[0])
    VERI.append(x)

ALAN = ["hane", "memnuniyet", "donem",
        "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]


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 = K[:756], K[756:1008]


def sapma(s):
    m = sum(x["hedef"] for x in s) / len(s)
    return sum((x["hedef"] - m) ** 2 for x in s) / len(s)


def bagac(s, derinlik, enaz=5):
    en = None
    if derinlik and len(s) >= 2 * enaz:
        for a in ALAN:
            d = sorted({x[a] for x in s})
            for v in (d[1:] if len(d) < 9 else
                      [d[int(i * len(d) / 9)] for i in range(1, 9)]):
                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 = sapma(s) - (len(sol) * sapma(sol) + len(sag) * sapma(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": sum(x["hedef"] for x in s) / len(s)}
    return {"alan": en[1], "esik": en[2], "sol": bagac(en[3], derinlik - 1, enaz),
            "sag": bagac(en[4], derinlik - 1, enaz)}


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


def kok(f, s):
    return math.sqrt(sum((f(x) - x["hedef"]) ** 2 for x in s) / len(s))


ORT = sum(x["hedef"] for x in EGT) / len(EGT)
print(f"egitim {len(EGT)}, ayrilmis {len(DOG)}, egitim ortalamasi {ORT:.3f} m3")
print(f"\n{'yordam':<14} {'egitimde':>9} {'ayrilmis':>9}")
print(f"{'taban':<14} {kok(lambda x: ORT, EGT):>9.3f} {kok(lambda x: ORT, DOG):>9.3f}")
for dr in (1, 3, 12):
    m = bagac(EGT, dr)
    print(f"{'derinlik ' + str(dr):<14} {kok(lambda x: tah(m, x), EGT):>9.3f} "
          f"{kok(lambda x: tah(m, x), DOG):>9.3f}")
```

```
egitim 756, ayrilmis 252, egitim ortalamasi 19.767 m3

yordam          egitimde  ayrilmis
taban              6.200     6.419
derinlik 1         5.696     5.979
derinlik 3         5.105     5.380
derinlik 12        4.639     5.594
```

Taban çizgisi burada "ortalamayı söylemektir": her aboneye eğitim kümesinin ortalaması olan 19,767
m³ atanır. Ayrılmış kümede 6,419 m³ hata veriyor. Derinlik 3 ağacı bunu 5,380 m³'e indiriyor.
Derinlik 12 ağacı eğitim kümesinde 4,639 m³ ile en iyisidir ama ayrılmış kümede 5,594 m³'e
çıkıyor — önceki dersin şekli, bu kez metre küp cinsinden.

Tablo neyin bozulduğunu söylemiyor. Derinlik 12 ağacı yanlış bir yeri mi hedefliyor, yoksa doğru
yeri hedefleyip her seferinde başka bir yere mi düşüyor. İki durumun düzeltmesi farklıdır ve
ayrılmaları gerekir.

#### Hatayı İkiye Ayırmak

Ayırmanın yolu tek eğitim kümesini çoğaltmaktır. Geri koyarak örnekleme aynı eğitim kümesinden 30
farklı 756 satırlık küme kuruyor; her birinde aynı yordam çalıştırılıp aynı ayrılmış kümedeki
abonelere 30 ayrı yanıt üretiliyor.

```python
B = 30
ORNEK = []
for b in range(B):
    r = uretec(TOHUM + 61000 + b * 13)
    ORNEK.append([EGT[int(r() * len(EGT))] for _ in range(len(EGT))])


def coz(ad, egit, tahminci):
    MOD = [egit(o) for o in ORNEK]
    T = [[tahminci(m, x) for x in DOG] for m in MOD]
    top = deg = yan = 0.0
    for i, x in enumerate(DOG):
        p = [T[b][i] for b in range(B)]
        m = sum(p) / B
        top += sum((q - x["hedef"]) ** 2 for q in p) / B
        deg += sum((q - m) ** 2 for q in p) / B
        yan += (m - x["hedef"]) ** 2
    n = len(DOG)
    print(f"{ad:<14} {top / n:>9.3f} {deg / n:>9.3f} {yan / n:>9.3f} "
          f"{math.sqrt(top / n):>7.3f}")


print(f"{B} geri koyarak ornek, her biri {len(EGT)} satir")
print(f"\n{'yordam':<14} {'toplam':>9} {'degisken':>9} {'yanlilik':>9} {'kok':>7}")
coz("taban", lambda o: sum(y["hedef"] for y in o) / len(o), lambda m, x: m)
for dr in (1, 2, 3, 5, 8, 12):
    coz(f"derinlik {dr}", lambda o, dr=dr: bagac(o, dr), tah)
```

```
30 geri koyarak ornek, her biri 756 satir

yordam            toplam  degisken  yanlilik     kok
taban             41.242     0.040    41.202   6.422
derinlik 1        36.158     2.138    34.020   6.013
derinlik 2        31.840     2.218    29.622   5.643
derinlik 3        29.768     1.321    28.448   5.456
derinlik 5        30.745     2.274    28.471   5.545
derinlik 8        32.922     3.983    28.939   5.738
derinlik 12       33.810     4.409    29.400   5.815
```

İkinci ve üçüncü sütun her satırda birinciyi tam olarak veriyor; eşitlik bir yaklaşıklık değil,
tanımın kendisidir. Sütunlar ters yönlerde hareket ediyor. Değişkenlik 0,040'tan 4,409'a, yani
yüz katından fazlasına çıkıyor. Yanlılık ve gürültü 41,202'den 28,448'e iniyor ve orada duruyor:
derinlik 3'ten sonra bu sütun düşmüyor, hafifçe yükseliyor.

Taban çizgisi dengenin bir ucudur ve tablodaki yeri bunu gösteriyor. Değişkenliği 0,040 ile
neredeyse sıfırdır — hangi örneklemle eğitilirse eğitilsin neredeyse aynı sayıyı söyler. Karşılığı
41,202'lik yanlılıktır: hep aynı yerde durur ve hep aynı yerde yanılır. Kararlılık kendi başına bir
erdem değildir.

Üçüncü sütunun **tabanı** dersin en önemli sayısıdır. Kapasite ne yapılırsa yapılsın bu sütun 28,4
m³ karenin altına inmiyor; bu, hiçbir öznitelikle açıklanamayan kalan gürültüdür. Kapasitenin
gerçekten söktüğü yanlılık 41,202 ile 28,448 arasındaki 12,754 m³ karedir, yani taban çizgisinin
hatasının yüzde 30,9'u. Geri kalan yüzde 69,1 ne daha derin bir ağaçla ne daha çok veriyle sökülür;
ölçüm ağının kendi saçılmasıdır.

Üçüncü sütunun ikinci bir okuması var ve bir yöntem ailesinin gerekçesini veriyor. O sütun,
otuz modelin **ortalamasını** alan bir yordamın ayrılmış kümedeki hatasıdır: ortalama alındığında
tanım gereği değişkenlik bileşeni kaybolur ve geriye yalnız üçüncü sütun kalır. Derinlik 12 için
tek bir ağaç 33,810 m³ kare hata yaparken otuz ağacın ortalaması 29,400 yapar, yani hatanın yüzde
13,0'ü yalnız ortalama alarak silinir; kök ölçüsünde 5,815 m³ yerine 5,422 m³. Bu sayı tek bir
derinlik 3 ağacının 5,456 m³'ünden de küçüktür. **Topluluk yöntemleri** tam olarak bunu yapar:
yanlılığı düşürmeye çalışmak yerine yüksek kapasiteli ve oynak modelleri çoğaltıp değişkenliği
ortalamaya bırakır. Kapasite düğmesine hiç dokunmadan hata düşürmenin yolu buradan geçer.

Değişkenlik sütunu kapasitenin tek yönlü bir işlevi değil ve bunun sebebi okunabilir. Derinlik
3'te değişkenlik 1,321 ile derinlik 2'nin 2,218'inin altındadır. Derinlik 1 ve 2'de ağaç beş bölgeyi
tek ya da iki bölmeyle ayırmak zorunda ve **hangi bölgeyi ayıracağı** örneklemden örnekleme
değişiyor; derinlik 3'te beş bölge hemen her örneklemde kendi yaprağını alıyor ve otuz model
birbirine benziyor. Kapasite yetersizken oynama, modelin öğrendiğinden değil, **seçmek zorunda
kaldığı şeyden** gelir.

#### Aynı Abone, Otuz Model

Bileşenler ortalamalardır; tek bir abonede ne göründükleri ayrıca sorulur.

```python
print(f"{'kapasite':<12} {'ortalama acikli':>16} {'en genis abone':>16}")
MODEL = {}
for dr in (1, 3, 12):
    MODEL[dr] = [bagac(o, dr) for o in ORNEK]
    a = [max(t) - min(t) for t in
         ([tah(m, x) for m in MODEL[dr]] for x in DOG)]
    print(f"{'derinlik ' + str(dr):<12} {sum(a) / len(a):>16.3f} {max(a):>16.3f}")

print(f"\n{'abone':>7} {'bolge':<8} {'gercek':>7}", end="")
for dr in (1, 3, 12):
    print(f" {'d' + str(dr) + ' ortalama':>12} {'acikli':>7}", end="")
print()
for x in (DOG[3], DOG[11], DOG[40]):
    b = [k for k in ("kuzey", "guney", "dogu", "bati", "merkez") if x["b_" + k]][0]
    print(f"{x['no']:>7} {b:<8} {x['hedef']:>7.2f}", end="")
    for dr in (1, 3, 12):
        p = [tah(m, x) for m in MODEL[dr]]
        print(f" {sum(p) / len(p):>12.2f} {max(p) - min(p):>7.2f}", end="")
    print()
```

```
kapasite      ortalama acikli   en genis abone
derinlik 1              3.587            5.246
derinlik 3              4.595           16.362
derinlik 12             8.172           24.236

  abone bolge     gercek  d1 ortalama  acikli  d3 ortalama  acikli d12 ortalama  acikli
  10227 kuzey      18.92        20.25    2.87        20.52    2.92        21.36    6.54
  10683 bati       11.99        15.66    5.25        13.80    5.16        13.72    5.48
  10424 guney      26.22        20.25    2.87        16.94    4.05        16.15    9.17
```

Birinci satırda yanlılık çıplak duruyor. Derinlik 1'de kuzeyli 10227 ile güneyli 10424 **aynı
sayıyı** alıyor: 20,25 m³. İki abonenin gerçek değerleri 18,92 ve 26,22 m³ olduğu halde model
ikisini ayıramıyor, çünkü tek bölmesi bu iki bölgeyi aynı yaprakta bırakıyor. Açıklığı 2,87 ile
dardır — kararlı biçimde yanlıştır.

Derinlik 3'te 10424'ün tahmini 16,94 m³'e düşüyor ve bu **daha kötü değil, daha doğru** bir sayıdır:
güney bölgesinin gerçek ortalamasına yakındır. Abonenin kendi değerinin 26,22 m³ olması bir yanlılık
belirtisi değil, gürültünün ta kendisidir — o abonenin okumaları bölgesinin üstünde çıkmıştır ve
kümedeki hiçbir öznitelik bunu haber vermez. Bir modelden bunu bilmesini beklemek, üçüncü sütunun
tabanını sökmesini beklemektir.

Derinlik 12'de ortalama tahmin 16,15 ile neredeyse aynı kalıyor ama açıklık 4,05'ten 9,17 m³'e
çıkıyor. Bütün ayrılmış küme üzerinde aynı şey oluyor: ortalama açıklık derinlik 1'de 3,587,
derinlik 12'de 8,172 m³. En geniş abonede otuz modelin yanıtı 24,236 m³'lük bir aralığa yayılıyor
ve bu, hedefin kendi ortalaması olan 19,767 m³'ten büyüktür. Yüksek kapasitenin verdiği yanıt
yanlış değil, **rastgeledir**; hangi eğitim örnekleminin çekildiğine bağlıdır.

#### Özet

- Ayrılmış kümedeki ortalama kare hata iki bileşenin tam toplamıdır: tahminlerin örneklemden
  örnekleme saçılması ve ortalama tahminin gerçek değerden uzaklığı.
- Kapasite arttıkça değişkenlik 0,040'tan 4,409'a yükseliyor, yanlılık ve gürültü 41,202'den
  28,448'e iniyor; toplam derinlik 3'te 29,768 ile en küçüktür ve kök ölçüsü 5,456 m³'tür.
- Üçüncü sütunun tabanı 28,4 m³ karedir ve indirgenemez gürültüdür; kapasitenin söktüğü yanlılık
  12,754 m³ kare, yani taban çizgisi hatasının yüzde 30,9'udur. Aynı sütun, otuz modelin
  ortalamasını alan bir topluluk yönteminin hatasıdır ve derinlik 12'de 33,810'u 29,400'e indirir.
- Taban çizgisi dengenin bir ucudur: değişkenliği 0,040 ile neredeyse sıfır, yanlılığı 41,202 ile
  en büyüktür; kararlılık tek başına bir erdem değildir.
- Değişkenlik kapasitenin tek yönlü işlevi değildir; derinlik 1 ve 2'de ağacın hangi bölgeyi
  ayıracağı örneklemden örnekleme değiştiği için oynama derinlik 3'tekinden büyüktür.
- Tek abone düzeyinde derinlik 1 iki ayrı bölgenin abonesine 20,25 m³ ile aynı sayıyı veriyor,
  derinlik 12 ise otuz modelde 9,17 m³'lük bir açıklık üretiyor.

#### Sonraki Adım

Denge bulundu ama bulunma biçimi kaba: derinlik tam sayıdır ve 3 ile 5 arasında ara değer yoktur.
Kapasiteyi kesip atmak yerine **cezalandırmak** daha ince bir düğme verir — modelin karmaşıklığı
hata ölçüsüne bir bedel olarak eklenir ve ceza katsayısı sürekli olarak ayarlanır. Sonraki ders
ceza katsayısını adım adım büyütür, eğitim sayısının kesintisiz kötüleştiğini ama ayrılmış küme
sayısının önce iyileşip sonra kötüleştiğini basar ve en iyi noktanın hangi kümeden okunacağını
gösterir.

### Düzenlileştirme Sezgisi

Source: https://academia.sh/tr/kurslar/makine-ogrenmesine-giris/duzenlilestirme-sezgisi

Karmaşıklığın cezalandırılmasının iki sayıyı ters yönde oynatmasının ölçülmesi: 120 satıra 29 sütunlu doğrusal bir modelde ceza katsayısı 0,001'den 1000'e çıkarıldığında ağırlık büyüklüğü 10,040'tan 0,601'e, eğitim hatası 4,603'ten 5,453 m³'e kötüleşir, doğrulama hatası ise 5,924'ten 5,553'e inip 5,932'ye döner. Geri koyarak örneklemeyle ayrıştırıldığında değişkenlik 12,988'den 0,181'e düşer, yanlılık ise 30,976'da tabana vurup 35,295'e fırlar. Doğrulamadan okunan en iyi ceza 100'dür ve sınamada 5,559 m³ verir; taban 6,556, cezasız model 5,841 m³'tür.

Önceki iki ders kapasiteyi kaba bir düğmeyle kıstı: ağacın derinliği tam sayıdır, 3 ile 5 arasında
ara değer yoktur ve yaprak alt sınırı da öyle. Oysa modelin karmaşıklığı kesip atılmak yerine
**cezalandırılabilir**. Hata ölçüsünün yanına modelin ne kadar iddialı olduğunu ölçen bir terim
eklenir ve model, hatayı düşürmekle iddiasını düşürmek arasında bir anlaşmaya zorlanır. Ceza
katsayısı sürekli bir sayıdır; iki tam sayı arasında istenildiği kadar durak vardır.

Bu ders o katsayıyı 0,001'den 1000'e çıkarır ve her adımda üç şeyi basar: ağırlıkların büyüklüğü,
eğitim hatası ve ayrılmış küme hatası. Beklenen davranış tek yönlü değildir — eğitim hatası
kesintisiz kötüleşir, ayrılmış küme hatası önce iyileşir sonra kötüleşir — ve en iyi noktanın
hangi kümeden okunacağı dersin son sorusudur.

- **GE23.** Model doğrusaldır ve 29 sütunu vardır: beş bölge göstergesi, hane büyüklüğü,
  memnuniyet, dönem sayısı, bunların kareleri, ikişerli çarpımları ve her birinin bölgeyle çarpımı.
- **GE24.** Ceza karesel bir terimdir: hata ölçüsüne ağırlıkların kare toplamının $\lambda$ katı
  eklenir. Sabit terim yerine hedeften eğitim ortalaması çıkarılır, böylece bütün ağırlıklar
  cezalanır ve ceza büyüdükçe model **taban çizgisine** yakınsar.
- **GE25.** Sütunlar eğitim kümesinin ortalaması ve saçılmasıyla ölçeklenir. Ceza ölçeğe duyarlıdır
  ve ölçeğin **hangi kümeden** hesaplandığı bir karardır.
- **GE26.** Eğitim kümesi bilerek 120 satıra düşürülür. Yirmi dokuz sütuna 120 satır, aşırı uyumu
  ölçülebilir kılan orandır.
- **GE27.** Doğrulama ve sınama kümeleri önceki derslerdeki 252'şer satırdır; tohum ve bölme
  aynıdır.
- **GE28.** Ölçü kök ortalama kare hatadır (m³); bileşenlere ayırma kare birimde yapılır.
- **GE29.** Taban çizgisi bütün ağırlıkların sıfır olduğu modeldir: her aboneye eğitim kümesinin
  ortalamasını söylemek.
- **GE30.** Sınama kümesine bu derste bir kez, seçim bittikten sonra bakılır.

#### Ceza İki Sayıyı Ters Yönde Oynatır

Kurulum kümeyi aynı tohumla üretir, doğrusal modeli kurar ve ceza katsayısını on bir adımda
büyütür. Çözüm kapalı biçimdedir: kare hatanın en küçük olduğu ağırlıklar, köşegenine ceza eklenmiş
bir denklem takımının çözümüdür.

```python
# duzenlilestirme.py — MODELDIR. Ayni kurgu olcum agi, ayni tohum. Hedef abonenin
# ortalama tuketimidir; model dogrusal, ceza karesel.
import math

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


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})
VERI = []
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 v:
        VERI.append({"no": k["no"], "bolge": k["bolge"][0], "hane": k["hane"],
                     "memnuniyet": k["memnuniyet"], "donem": len(v),
                     "hedef": round(sum(v) / len(v), 2)})


def sutunlar(x):
    t = [float(x["bolge"] == b[0]) for b in BOLGE]
    h, m, d = float(x["hane"]), float(x["memnuniyet"]), float(x["donem"])
    return (t + [h, m, d, h * h, m * m, d * d, h * m, h * d, m * d]
            + [g * h for g in t] + [g * m for g in t] + [g * d for g in t])


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[:120], K[756:1008], K[1008:]
P = len(sutunlar(EGT[0]))
HAM_EGT = [sutunlar(x) for x in EGT]
ORTS = [sum(s[j] for s in HAM_EGT) / len(HAM_EGT) for j in range(P)]
SAP = [max(1e-9, math.sqrt(sum((s[j] - ORTS[j]) ** 2 for s in HAM_EGT) / len(HAM_EGT)))
       for j in range(P)]
ORT = sum(x["hedef"] for x in EGT) / len(EGT)


def olcek(x):
    s = sutunlar(x)
    return [(s[j] - ORTS[j]) / SAP[j] for j in range(P)]


def coz(A, b):
    n = len(b)
    for i in range(n):
        p = max(range(i, n), key=lambda k: abs(A[k][i]))
        A[i], A[p], b[i], b[p] = A[p], A[i], b[p], b[i]
        for k in range(i + 1, n):
            f = A[k][i] / A[i][i]
            for j in range(i, n):
                A[k][j] -= f * A[i][j]
            b[k] -= f * b[i]
    w = [0.0] * n
    for i in range(n - 1, -1, -1):
        w[i] = (b[i] - sum(A[i][j] * w[j] for j in range(i + 1, n))) / A[i][i]
    return w


def egit(satirlar, ceza):
    X = [olcek(x) for x in satirlar]
    y = [x["hedef"] - ORT for x in satirlar]
    A = [[sum(X[i][a] * X[i][b] for i in range(len(X))) + (ceza if a == b else 0.0)
          for b in range(P)] for a in range(P)]
    return coz(A, [sum(X[i][a] * y[i] for i in range(len(X))) for a in range(P)])


def kok(w, s):
    return math.sqrt(sum((ORT + sum(a * b for a, b in zip(w, olcek(x))) - x["hedef"]) ** 2
                         for x in s) / len(s))


print(f"egitim {len(EGT)}, dogrulama {len(DOG)}, sinama {len(SIN)}, sutun {P}")
print(f"taban: egitim {kok([0.0] * P, EGT):.3f}  dogrulama {kok([0.0] * P, DOG):.3f}  "
      f"sinama {kok([0.0] * P, SIN):.3f}")
print(f"\n{'ceza':>8} {'agirlik':>9} {'egitimde':>9} {'dogrulama':>10} {'sinama':>8}")
for c in (0.001, 0.01, 0.1, 0.3, 1, 3, 10, 30, 100, 300, 1000):
    w = egit(EGT, c)
    print(f"{c:>8} {math.sqrt(sum(v * v for v in w)):>9.3f} {kok(w, EGT):>9.3f} "
          f"{kok(w, DOG):>10.3f} {kok(w, SIN):>8.3f}")
```

```
egitim 120, dogrulama 252, sinama 252, sutun 29
taban: egitim 6.121  dogrulama 6.439  sinama 6.556

    ceza   agirlik  egitimde  dogrulama   sinama
   0.001    10.040     4.603      5.924    5.841
    0.01     9.963     4.603      5.921    5.839
     0.1     9.334     4.604      5.894    5.815
     0.3     8.396     4.606      5.850    5.777
       1     6.687     4.620      5.770    5.704
       3     4.891     4.653      5.693    5.634
      10     3.291     4.716      5.614    5.571
      30     2.222     4.804      5.556    5.534
     100     1.534     4.920      5.553    5.559
     300     1.099     5.089      5.657    5.694
    1000     0.601     5.453      5.932    6.008
```

Ağırlık sütunu cezanın ne yaptığını doğrudan gösteriyor: ağırlıkların büyüklüğü 10,040'tan 0,601'e,
yani on yedide birine iniyor. Ceza modelin ağırlıklarını küçültmekten başka bir şey yapmıyor;
sütunlara dokunmuyor, satır atmıyor, kural silmiyor.

Üçüncü sütun tek yönlüdür ve **kötüleşiyor**: eğitim hatası 4,603'ten 5,453 m³'e çıkıyor. Bu
beklenendir, çünkü cezasız çözüm zaten eğitim kümesindeki kare hatayı en küçük yapan çözümdür;
üzerine konan her ceza o sayıyı ancak bozar. Eğitim hatasının kötüleşmesi düzenlileştirmenin yan
etkisi değil, çalıştığının kanıtıdır.

Dördüncü sütun iki yönlüdür: 5,924'ten 5,553'e iniyor, sonra 5,932'ye dönüyor. En düşük nokta ceza
100'dedir ve cezasız modele göre 0,371 m³ kazanç sağlıyor. İniş ile çıkış arasındaki mesafe dar
değil: ceza 3 ile 300 arasındaki bütün değerler cezasız modelden iyidir, ama 1000'de model cezasız
modelden de kötüdür.

Son satırın yönü dersin sezgisidir. Ceza büyüdükçe ağırlıklar sıfıra yaklaşır ve bütün ağırlıklar
sıfır olduğunda model her aboneye eğitim ortalamasını söyler — yani **taban çizgisinin kendisine**
dönüşür. Düzenlileştirme, modeli sürekli bir düğmeyle taban çizgisine doğru çeken bir kuvvettir.
Ceza 1000'de ağırlık 0,601 ile hâlâ sıfır değildir ve doğrulama hatası 5,932 ile tabanın 6,439'unun
altındadır; o düğme henüz sonuna kadar çevrilmemiştir.

Ağırlıkların kendisine bakınca cezanın neyi kovduğu görünür.

```python
AD = ([b[0] for b in BOLGE] + ["hane", "memnuniyet", "donem", "hane^2",
      "memnuniyet^2", "donem^2", "hane*memnuniyet", "hane*donem",
      "memnuniyet*donem"] + [b[0] + "*hane" for b in BOLGE]
      + [b[0] + "*memnuniyet" for b in BOLGE] + [b[0] + "*donem" for b in BOLGE])
for c in (0.001, 100):
    w = egit(EGT, c)
    en = sorted(range(P), key=lambda j: -abs(w[j]))[:4]
    print(f"ceza {c}: en buyuk dort agirlik")
    for j in en:
        print(f"    {AD[j]:<20} {w[j]:>8.3f}")
    t = sum(abs(w[j]) for j in range(P))
    print(f"    ilk dort agirligin toplam paydaki payi: "
          f"{sum(abs(w[j]) for j in en) / t:.3f}")
```

```
ceza 0.001: en buyuk dort agirlik
    guney                  -4.138
    donem                   2.981
    hane^2                  2.965
    hane                   -2.962
    ilk dort agirligin toplam paydaki payi: 0.303
ceza 100: en buyuk dort agirlik
    bati*donem             -0.574
    dogu*donem              0.553
    bati                   -0.487
    dogu                    0.479
    ilk dort agirligin toplam paydaki payi: 0.302
```

Cezasız çözümdeki `hane` ile `hane^2` ağırlıkları -2,962 ve +2,965: neredeyse birbirini götürüyor.
İki sütun aynı bilginin iki biçimi olduğu için model ikisine büyük ve zıt ağırlıklar verebiliyor;
tahminler değişmiyor, ağırlıklar şişiyor. Ceza tam olarak bunu yasaklar. Ceza 100'de en büyük dört
ağırlık batı ve doğu bölgeleriyle bunların dönem sayısına bağlı terimleridir — kurgudaki gerçek
yapı budur, çünkü bölge taban tüketimini belirler.

Son satır cezanın **nasıl** çalıştığını söylüyor. İlk dört ağırlığın toplam ağırlık payındaki oranı
iki cezada da aynı: 0,303 ve 0,302. Karesel ceza sütun elemiyor, hiçbirini sıfırlamıyor,
dağılımın **biçimini** değiştirmiyor; hepsini birlikte küçültüyor. Kapasite kısmakla arasındaki
fark budur — ağaç budaması bir kuralı siler, ceza bütün kuralları aynı oranda yumuşatır.

#### Ceza Hatanın Hangi Bileşenini Küçültüyor

Önceki dersin ayrıştırması aynen uygulanabilir. Ceza kapasiteyi kısan bir düğmeyse, hatanın
değişkenlik bileşenini düşürüp yanlılık bileşenini yükseltmesi gerekir.

```python
B = 30
ORNEK = []
for b in range(B):
    r = uretec(TOHUM + 61000 + b * 13)
    ORNEK.append([EGT[int(r() * len(EGT))] for _ in range(len(EGT))])

print(f"{B} geri koyarak ornek, her biri {len(EGT)} satir")
print(f"\n{'ceza':>8} {'toplam':>9} {'degisken':>9} {'yanlilik':>9}")
for c in (0.001, 1, 30, 100, 1000):
    T = []
    for o in ORNEK:
        w = egit(o, c)
        T.append([ORT + sum(a * b for a, b in zip(w, olcek(x))) for x in DOG])
    top = deg = yan = 0.0
    for i, x in enumerate(DOG):
        p = [T[b][i] for b in range(B)]
        m = sum(p) / B
        top += sum((q - x["hedef"]) ** 2 for q in p) / B
        deg += sum((q - m) ** 2 for q in p) / B
        yan += (m - x["hedef"]) ** 2
    n = len(DOG)
    print(f"{c:>8} {top / n:>9.3f} {deg / n:>9.3f} {yan / n:>9.3f}")
```

```
30 geri koyarak ornek, her biri 120 satir

    ceza    toplam  degisken  yanlilik
   0.001    47.027    12.988    34.039
       1    38.330     5.133    33.196
      30    32.689     1.622    31.066
     100    32.075     1.098    30.976
    1000    35.476     0.181    35.295
```

Değişkenlik sütunu cezanın asıl hedefidir: 12,988'den 0,181'e, yani yetmiş ikide birine iniyor.
Ceza katsayısı büyüdükçe hangi 120 satırın çekildiği modelin verdiği yanıtı daha az etkiliyor.
Ceza 1000'de otuz model neredeyse aynı şeyi söylüyor, çünkü hepsi taban çizgisine yakın duruyor.

Yanlılık sütunu iki bölgeye ayrılıyor. Cezasız uçtaki 34,039 sayısı beklenenden yüksektir: 120
satıra 29 sütun düşen bir denklem takımı neredeyse tekildir ve çözüm o kadar oynaktır ki otuz
modelin **ortalaması** bile bozulur. Ceza 100'e kadar bu sütun 30,976'ya iniyor. Sonra 35,295'e
fırlıyor: orada ceza artık yalnız gürültüyü değil, kümedeki gerçek bölge yapısını da siliyor.

Toplam sütununun en küçük olduğu nokta ceza 100'dür ve bu, önceki tablodaki doğrulama sütununun en
küçük olduğu noktayla aynıdır. İki bağımsız ölçüm — biri tek bir bölmede kök hata, öbürü otuz
örneklemde bileşen ayrıştırması — aynı katsayıyı gösteriyor.

#### En İyi Nokta Hangi Kümeden Okunur

Ceza 100 tablodan okundu, ama **hangi tablodan** okunduğu kursun birinci dersinin sorusudur.

```python
CEZA = [0.001, 0.01, 0.1, 0.3, 1, 3, 10, 30, 100, 300, 1000]
SKOR = [(c, kok(egit(EGT, c), DOG), kok(egit(EGT, c), SIN)) for c in CEZA]
d = min(SKOR, key=lambda t: t[1])
s = min(SKOR, key=lambda t: t[2])
print(f"dogrulamadan okunan en iyi ceza {d[0]}: dogrulama {d[1]:.3f}, sinama {d[2]:.3f}")
print(f"sinamadan okunsaydi en iyi ceza  {s[0]}: dogrulama {s[1]:.3f}, sinama {s[2]:.3f}")
print(f"secim sinamada yapilsaydi rapor edilecek sayi {s[2]:.3f}, "
      f"durustu {d[2]:.3f}, fark {d[2] - s[2]:.3f} m3")
print(f"\nsinama kumesinde: taban {kok([0.0] * P, SIN):.3f}, cezasiz "
      f"{kok(egit(EGT, 0.001), SIN):.3f}, secilen {d[2]:.3f}")
print(f"cezanin kattigi {kok(egit(EGT, 0.001), SIN) - d[2]:.3f} m3, "
      f"modelin tabana gore kattigi {kok([0.0] * P, SIN) - d[2]:.3f} m3")
```

```
dogrulamadan okunan en iyi ceza 100: dogrulama 5.553, sinama 5.559
sinamadan okunsaydi en iyi ceza  30: dogrulama 5.556, sinama 5.534
secim sinamada yapilsaydi rapor edilecek sayi 5.534, durustu 5.559, fark 0.025 m3

sinama kumesinde: taban 6.556, cezasiz 5.841, secilen 5.559
cezanin kattigi 0.282 m3, modelin tabana gore kattigi 0.997 m3
```

İki küme iki ayrı katsayı seçiyor: doğrulama 100, sınama 30. İkisinin de savunulabilir olması
işin özüdür — aradaki fark gerçek bir kalite farkı değil, 252 satırlık iki kümenin kendi
saçılmasıdır. Ama seçim sınama kümesinde yapılsaydı raporlanacak sayı 5,534 olurdu; dürüst sayı
5,559'dur. Fark 0,025 m³ ile küçüktür ve **işareti sabittir**: seçim yapılan kümedeki sayı hiçbir
zaman daha kötü çıkamaz. Burada on bir aday vardı; birinci derste 48 aday farkı 2 puana çıkarmıştı.
Seçim payı aday sayısıyla büyür, ama sıfır adayla bile sıfır olmaz.

Son iki satır dersin hesabını kapatıyor. Sınama kümesinde taban 6,556 m³, cezasız doğrusal model
5,841 m³, düzenlileştirilmiş model 5,559 m³. Modelin tabana göre kazancı 0,997 m³, yani yüzde
15,2. Bunun 0,282 m³'ü, yani yüzde 28,3'ü yalnız ceza katsayısından geliyor. Düzenlileştirme yeni
bir öznitelik eklemedi, yeni bir kural öğretmedi; öğrenilmiş olanın ne kadarının tutulacağını
seçti ve kazancın dörtte birinden fazlasını oradan çıkardı.

#### Özet

- Ceza katsayısı 0,001'den 1000'e çıkarıldığında ağırlık büyüklüğü 10,040'tan 0,601'e iniyor;
  eğitim hatası 4,603'ten 5,453 m³'e kesintisiz kötüleşiyor ve bu, cezanın çalıştığının kanıtıdır.
- Ayrılmış küme hatası 5,924'ten 5,553'e inip 5,932'ye dönüyor; en düşük nokta ceza 100'dedir ve
  ceza sonsuza götürülseydi model taban çizgisinin kendisine dönüşürdü.
- Ayrıştırma cezanın hedefini gösteriyor: değişkenlik 12,988'den 0,181'e iniyor, yanlılık ise
  30,976'da tabana vurup ceza 1000'de 35,295'e fırlıyor; orada ceza gerçek bölge yapısını siliyor.
- Doğrulama kümesinden okunan en iyi ceza 100, sınama kümesinden okunsaydı 30 olurdu; sınamadan
  seçmek raporlanan sayıyı 5,559'dan 5,534'e indirirdi ve bu farkın işareti hiçbir zaman ters
  dönmez.
- Sınama kümesinde taban 6,556, cezasız model 5,841, düzenlileştirilmiş model 5,559 m³; modelin
  tabana göre kazancı 0,997 m³ ve bunun yüzde 28,3'ü yalnız ceza katsayısından gelir.

#### Sonraki Adım

Dört derste ayrım kuruldu ve her sayının yanına tabanı yazıldı. Bu dersin kurulumunda sessizce
doğru yapılmış bir karar var: sütunların ölçeği **yalnız eğitim kümesinden** hesaplandı. Karar
tersine çevrilebilir ve çevrildiğinde ayrılmış küme sayısı iyileşir — hem de model hiçbir şey
öğrenmeden. Sonraki ders bu türden dört bozulmayı tek tek uygular ve her birinin ayrılmış küme
sayısını ne kadar şişirdiğini basar. Kursun kapanışı da oradadır.

### Veri Sızıntısı

Source: https://academia.sh/tr/kurslar/makine-ogrenmesine-giris/veri-sizintisi

Ayrılmış küme sayısını öğrenme dışındaki kaynakların şişirmesinin ölçülmesi: dürüst çizgi taban 0,7579 karşısında sınamada 0,7778 doğruluk verirken ayrımdan önce ölçekleme bu sayıyı 0,0119, geleceği gören öznitelik 0,0754, yinelenen kayıt 0,0542 ve hedeften türetilmiş öznitelik 0,1429 şişirir; dördünün de işareti aynı yöndedir. Öznitelikleri tümüyle rastgele altı sütunla değiştirilmiş bir model, yinelenen kayıt varken ayrılmış kümede 0,8757 doğruluk okuyup 0,7857'lik tabanı 9 puan geçer; ikizini görmediği satırlarda ise tabanın 9,2 puan altında kalır. Kurs kapanışında on bir dersin taban çizgisi, eğitim ve ayrılmış küme sayıları tek tabloda toplanır.

Önceki dersin kurulumunda sessizce doğru yapılmış bir karar vardı: sütunların ölçeği yalnız eğitim
kümesinden hesaplandı. Karar tersine çevrilebilir. Ölçek bütün kümeden hesaplandığında ayrılmış
kümenin satırları modelin göreceği sayıların üretilmesine katkıda bulunur ve ayrılmış küme, o katkı
kadar ayrılmamış olur.

Bu, **veri sızıntısının** en sessiz biçimidir. Sızıntı, tahmin anında elde olmayacak bir bilginin
eğitim ya da ölçüm yoluna karışmasıdır ve sonucu her zaman aynı yöndedir: ayrılmış küme sayısı
yükselir. Bu ders dört türü tek tek uygular, her birinin şişmesini kendi dürüst karşılığına göre
ölçer ve müfredatın ikinci iddiasını sayar — **fark her zaman öğrenmeden gelmez.**

- **GE31.** Küme, etiket, bölme, tohum ve ölçü kurs boyunca aynıdır. Ayrılmış küme sınama
  kümesidir: 252 satır. Dürüst çizgi birinci dersin modelidir: derinlik 6 karar ağacı, taban
  0,7579, eğitimde 0,8466, sınamada 0,7778.
- **GE32.** Birinci sızıntı bölgeye göre ölçeklemedir: bölge ortalaması ve saçılması dürüst biçimde
  yalnız eğitim kümesinden, sızıntılı biçimde bütün kümeden hesaplanır.
- **GE33.** İkinci sızıntı dördüncü dönem okumasıdır ve **kurgudur**: etiket yazıldıktan sonra
  oluşur, şüphelilerde 0,55 olasılıkla sıfır çıkar, çıkmazsa değeri 1,45 katıdır.
- **GE34.** Üçüncü sızıntı bir birleştirme hatasıdır: her abone kaydı üç kez üretilir, 1.260 abone
  3.780 satıra çıkar ve bölme **satır** düzeyinde yapılır.
- **GE35.** Dördüncü sızıntı denetim ekibi atamasıdır ve **kurgudur**: şüphelilerde 0,88,
  ötekilerde 0,06 olasılıkla birdir ve etiketten sonra kaydedilir.
- **GE36.** Şişme her zaman **kendi dürüst karşılığına** göre ölçülür; birinci sızıntının karşılığı
  aynı özniteliğin dürüst hesaplanmış hâlidir.
- **GE37.** Son bölümde öznitelikler tümüyle rastgele altı sütunla değiştirilir. Bu sütunların
  etiketle hiçbir ilişkisi yoktur ve bir abonenin üç kopyasında aynıdır.

#### Dört Sızıntı, Dört Şişme

Kurulum kursun ilk dersindekiyle aynıdır ve aynı tohumla aynı kümeyi üretir.

```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})
VERI = []
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)}
    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"]


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, SIN = K[:756], 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, 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)
```

Dört sızıntı sırayla kurulur ve her biri kendi dürüst karşılığıyla ölçülür.

```python
TEMEL, SONUC = list(ALAN), []
for x in VERI:
    x["bolge_ad"] = [b[0] for b in BOLGE if x["b_" + b[0]]][0]


def olc(alanlar, egt, ayr, derinlik=6):
    global ALAN
    ALAN = alanlar
    m = agac(egt, derinlik)
    ALAN = TEMEL
    return taban(egt, ayr), dogruluk(m, egt), dogruluk(m, ayr)


def bolge_z(kaynak):
    for b in {x["bolge_ad"] for x in VERI}:
        v = [x["ort_tuketim"] for x in kaynak if x["bolge_ad"] == b]
        o = sum(v) / len(v)
        s = max(1e-6, (sum((q - o) ** 2 for q in v) / len(v)) ** 0.5)
        for x in VERI:
            if x["bolge_ad"] == b:
                x["bolge_z"] = round((x["ort_tuketim"] - o) / s, 3)


DURUST = olc(TEMEL, EGT, SIN)
bolge_z(EGT)
S1D = olc(TEMEL + ["bolge_z"], EGT, SIN)
bolge_z(VERI)
SONUC.append(("1 ayrimdan once olcekleme", S1D, olc(TEMEL + ["bolge_z"], EGT, SIN)))

for x in VERI:
    r, t = uretec(TOHUM + 71000 + x["no"]), 0
    for b in BOLGE:
        t = b[2] if x["bolge_ad"] == b[0] else t
    x["dorduncu"] = 0.0 if (x["supheli"] and r() < 0.55) else round(
        t * math.exp((r() + r() + r() - 1.5) * 0.62) * (1 + 0.45 * x["supheli"]), 2)
SONUC.append(("2 gelecegi goren oznitelik", DURUST, olc(TEMEL + ["dorduncu"], EGT, SIN)))

IKIZ = []
for x in VERI:
    for c in range(3):
        y = dict(x)
        y["kimlik"], y["no"] = x["no"], x["no"] + 50000 * c
        IKIZ.append(y)
D = karistir(IKIZ, TOHUM + 93000)
DE, DS = D[:int(len(D) * 0.6)], D[int(len(D) * 0.8):]
EK = {x["kimlik"] for x in DE}
VAR = [x for x in DS if x["kimlik"] in EK]
YOK = [x for x in DS if x["kimlik"] not in EK]
SONUC.append(("3 yinelenen kayit", DURUST, olc(TEMEL, DE, DS)))

for x in VERI:
    r = uretec(TOHUM + 81000 + x["no"])
    x["denetim"] = int(r() < (0.88 if x["supheli"] else 0.06))
SONUC.append(("4 hedeften turetilmis oznitelik", DURUST,
              olc(TEMEL + ["denetim"], EGT, SIN)))

print(f"{'':<32} {'taban':>7} {'egitimde':>9} {'durust':>8} {'sizintili':>10} {'sisme':>8}")
print(f"{'durust cizgi':<32} {DURUST[0]:>7.4f} {DURUST[1]:>9.4f} {DURUST[2]:>8.4f}")
for ad, d, s in SONUC:
    print(f"{ad:<32} {s[0]:>7.4f} {s[1]:>9.4f} {d[2]:>8.4f} {s[2]:>10.4f} "
          f"{s[2] - d[2]:>+8.4f}")
print(f"\nyinelenmis kume {len(D)} satir; ayrilmis {len(DS)}, ikizi egitimde olan "
      f"{len(VAR)}, olmayan {len(YOK)}")
print(f"3. sizintinin ici: ikizli satirlarda {olc(TEMEL, DE, VAR)[2]:.4f}, "
      f"ikizsizlerde {olc(TEMEL, DE, YOK)[2]:.4f}")
```

```
                                   taban  egitimde   durust  sizintili    sisme
durust cizgi                      0.7579    0.8466   0.7778
1 ayrimdan once olcekleme         0.7579    0.8492   0.7659     0.7778  +0.0119
2 gelecegi goren oznitelik        0.7579    0.9312   0.7778     0.8532  +0.0754
3 yinelenen kayit                 0.7857    0.8646   0.7778     0.8320  +0.0542
4 hedeften turetilmis oznitelik   0.7579    0.9590   0.7778     0.9206  +0.1429

yinelenmis kume 3780 satir; ayrilmis 756, ikizi egitimde olan 626, olmayan 130
3. sizintinin ici: ikizli satirlarda 0.8514, ikizsizlerde 0.7385
```

Şişme sütununun dört değeri de **aynı işaretlidir**: +0,0119, +0,0754, +0,0542, +0,1429. Bu bir
rastlantı değil, sızıntının tanımıdır: ayrılmış kümeye karışan bilgi her zaman modelin işine yarar.
İşaretin sabitliği sızıntıyı gürültüden ayıran ilk işarettir.

İkinci sütun bir tuzağa dikkat çekiyor. Eğitim sayısı da 0,8466'dan 0,9590'a yükseliyor, ama bu
tek başına hiçbir şey söylemez — ikinci ders kapasiteyi artırmanın da aynı sütunu yükselttiğini
gösterdi. Sızıntının imzası **ayrılmış küme sayısının** yükselmesidir.

Sıralama, tehlike sıralamasının tersidir. En büyük şişmeyi hedeften türetilmiş öznitelik üretiyor:
0,1429 ile modeli 0,9206'ya taşıyor. Ama o sütunun adı `denetim` ve birinin "bu sütun ne zaman
yazılıyor" diye sorması olasıdır. En küçük şişme ayrımdan önce ölçeklemeden geliyor: 0,0119, yani
3 abone. Hiçbir sütun eklenmemiştir, kod doğru görünür ve 1,2 puanlık bir fark hiçbir raporda
sorgulanmaz. Sızıntının tehlikesi büyüklüğüyle değil **görünürlüğüyle** ters orantılıdır.

Üçüncü sızıntı kendi içinde okunuyor. Yinelenmiş kümede ayrılmış kümenin 756 satırının 626'sının
ikizi eğitim kümesindedir; model bu satırlarda 0,8514, ikizi olmayan 130 satırda 0,7385 veriyor.
Bölme satırları ayırdı ama **aboneyi** ayırmadı ve bunu bölme oranına bakarak görmek olanaksızdır.

İkinci sızıntıda dördüncü dönem okuması gerçek bir ölçümdür; sorun ölçümün yanlışlığı değil
**zamanıdır**. Kümedeki her sütun için tek bir soru yeter: bu değer, tahminin verileceği anda elde
midir.

#### Hiçbir Şey Öğrenmemiş Bir Model

Dört sızıntı da gerçek bir modeli şişirdi. Sıradaki soru daha serttir: sızıntı, **hiçbir şey
öğrenmemiş** bir modeli taban çizgisinin üstüne taşıyabilir mi. Aşağıdaki kod yinelenmiş kümenin
bütün özniteliklerini atıp yerine tümüyle rastgele altı sütun koyuyor; öğrenilecek hiçbir şey
kalmıyor.

```python
for x in IKIZ:
    r = uretec(TOHUM + 31000 + x["kimlik"])
    for j in range(6):
        x["g" + str(j)] = round(r(), 4)
ALAN = ["g" + str(j) for j in range(6)]
print(f"{'kapasite':>11} {'egitimde':>9} {'ayrilmis':>9} {'ikizli':>8} {'ikizsiz':>8}")
print(f"{'taban':>11} {taban(DE, DE):>9.4f} {taban(DE, DS):>9.4f} "
      f"{taban(DE, VAR):>8.4f} {taban(DE, YOK):>8.4f}")
for dr in (8, 12, 16):
    m = agac(DE, dr)
    print(f"{'derinlik ' + str(dr):>11} {dogruluk(m, DE):>9.4f} {dogruluk(m, DS):>9.4f} "
          f"{dogruluk(m, VAR):>8.4f} {dogruluk(m, YOK):>8.4f}")
ALAN = TEMEL
```

```
   kapasite  egitimde  ayrilmis   ikizli  ikizsiz
      taban    0.7787    0.7857   0.7796   0.8154
 derinlik 8    0.8589    0.8228   0.8419   0.7308
derinlik 12    0.9528    0.8757   0.9073   0.7231
derinlik 16    0.9832    0.9061   0.9377   0.7538
```

Derinlik 12 satırı müfredatın ikinci iddiasının ölçülmüş hâlidir. Model ayrılmış kümede 0,8757
okuyor ve 0,7857'lik tabanı **9,0 puan** geçiyor. Bu sayı bir raporda tek başına durursa
savunulabilir görünür: tabanı geçmiştir, ayrılmış kümede ölçülmüştür, kursun istediği iki koşul da
sağlanmıştır. Oysa modelin baktığı altı sütun rastgele sayılardır.

Fark son iki sütunda görünüyor. İkizi eğitimde olan 626 satırda model 0,9073, ikizi olmayan 130
satırda 0,7231 veriyor ve o 130 satırın kendi tabanı 0,8154'tür. Model ikizini gördüğü satırlarda
ezberini geri çağırıyor, görmediklerinde tabanın 9,2 puan altında kalıyor. Öğrendiği tek şey,
rastgele altı sayının belirli birleşimlerine hangi etiketin yapıştığıdır.

Kapasite sütunu bunu doğruluyor: ayrılmış küme sayısı derinlik 8'de 0,8228, 12'de 0,8757, 16'da
0,9061. İkinci dersin eğrisi burada **ters işaretle** çalışıyor. Kursun verebileceği en kullanışlı
denetim kuralı budur — aşırı uyumun ayrılmış kümede ceza yememesi, o kümenin ayrılmamış olduğunun
en güvenilir işaretidir.

Kursun kuralı burada tamamlanıyor: ayrılmış sanılan bir kümede ölçülen başarım da ezber olabilir.
Ayrımın kendisi denetlenecek bir karardır ve denetimi bölme oranına değil, bölme **birimine** ve
her sütunun **zamanına** bakarak yapılır.

#### Özet

- Dört sızıntı türünün de şişmesi aynı işaretlidir: ayrımdan önce ölçekleme +0,0119, geleceği gören
  öznitelik +0,0754, yinelenen kayıt +0,0542, hedeften türetilmiş öznitelik +0,1429.
- Sızıntının imzası eğitim sayısının değil, ayrılmış küme sayısının yükselmesidir; eğitim sayısını
  kapasite de yükseltir.
- Şişmenin büyüklüğü ile görünürlüğü ters orantılıdır; ve yinelenen kayıtta bölme satırları ayırıp
  aboneyi ayırmadığı için ikizi eğitimde olan 626 satırda doğruluk 0,8514, olmayan 130 satırda
  0,7385'tir.
- Öznitelikleri tümüyle rastgele altı sütunla değiştirilmiş bir model ayrılmış kümede 0,8757 okuyup
  0,7857'lik tabanı 9,0 puan geçiyor, ikizini görmediği satırlarda tabanının 9,2 puan altında kalıyor.
- Kapasite arttıkça sızıntılı ölçüm iyileşiyor (0,8228, 0,8757, 0,9061); aşırı uyumun ayrılmış
  kümede ceza yememesi, o kümenin ayrılmamış olduğunun en güvenilir işaretidir.

#### Kurs Kapanışı

On bir dersin hesabı tek tabloda duruyor ve her sayı kendi dersinden okundu. İlk altı ders 883/377,
son beş ders 756/252/252 bölmesini kullanır; taban çizgisi bu yüzden satırdan satıra değişir.

| Ders | Taban çizgisi | Eğitimde | Ayrılmış kümede |
|---|---|---|---|
| Kavram 01 makine öğrenmesi nedir | en sık sınıf 0,7533 | ağaç 0,8709 | ağaç 0,8594 |
| Kavram 02 öğrenme türleri | en sık sınıf 0,7533 | denetimli 0,8709 | denetimli 0,8594 |
| Kavram 03 kendi kendine denetimli | en sık sınıf 0,7533 | gösterimle 0,8313 | gösterimle 0,8037 |
| Kavram 04 uygulama alanları | en sık sınıf 0,7533 | ağaç 0,8709 | ağaç 0,8594 |
| Kavram 05 makine öğrenmesi iş akışı | rastgele sıra 14 kaçak | sıralama 30 kaçak | sıralama 30 kaçak |
| Kavram 06 roller | saha yordamı 13 kaçak | — | model sırası 30 kaçak |
| Genelleme 01 üç küme | en sık sınıf 0,7579 | derinlik 6 0,8466 | derinlik 6 0,7778 |
| Genelleme 02 aşırı ve eksik uyum | en sık sınıf 0,8135 | derinlik 14 0,9352 | derinlik 14 0,7302 |
| Genelleme 03 yanlılık–değişkenlik | ortalama 6,419 m³ | derinlik 3 5,105 m³ | derinlik 3 5,380 m³ |
| Genelleme 04 düzenlileştirme | ortalama 6,556 m³ | ceza 100 4,920 m³ | ceza 100 5,559 m³ |
| Genelleme 05 veri sızıntısı | en sık sınıf 0,7579 | sızıntılı 0,9590 | sızıntılı 0,9206 |

Kavram 04'ün satırı o dersteki dört sorunun yalnız sınıflandırma olanıdır. Kavram 06'nın satırında
eğitim sütunu boştur: o ders eğitim ile ayrılmış küme ayrımını değil, aynı ayrılmış küme ölçüsünün
üç iş tanımında üç ayrı tabana okunmasını sayar — 13, 23 ve 21 kaçak, kazanç 17, 7 ve 9. Genelleme
05'in satırı bilerek sızıntılıdır.

Üçüncü ile dördüncü sütun arasındaki fark **kursun kuralıdır**: ayrılmış bir kümede ölçülmemiş
başarım, başarım değil ezberdir. Tablodaki hiçbir satırda eğitimde ölçülen sayı ayrılmış kümede
ölçülenden kötü değildir.

İkinci sütun **müfredatın kuralıdır**: bir model, kendisinden daha aptal bir yordamı ne kadar
geçtiği kadar iyidir ve taban çizgisi yazılmayan başarım ölçülmemiş sayılır. Tablonun en yüksek
doğruluğu 0,9206'dır ve hiçbir şey söylemez; en düşüğü 0,7302'dir ve tabanının 8,3 puan altında
kaldığı için bir şey söyler.

On bir derste ayrım kuruldu ve her sayının yanına tabanı yazıldı. Ama modele verilen
**öznitelikler** hep hazır kabul edildi: bölge bir gösterge sütununa, üç okuma bir ortalamaya
baştan çevrilmişti. Hangi sütunun nasıl bir sayıya çevrileceği, o çevirinin tabanla arasındaki
farkı ne kadar oynattığı ve hangi çevirinin bu dersteki gibi sessiz bir sızıntı taşıdığı hiç
sorulmadı. Sonraki kurs, Veri Hazırlama ve Öznitelik Mühendisliği, bu soruları ele alır.

