---
title: 'Model Değerlendirme, Yorumlanabilirlik ve Etik'
source: 'https://academia.sh/tr/kurslar/model-etik-ve-yorum'
language: tr
updated: '2026-08-17T04:42:06+00:00'
license: 'CC BY-SA 4.0'
lessons: 15
outcomes:
    - 'Değerlendirme tasarımını veri sızıntısına ve dağılım kaymasına karşı korur ve tabanı kendisi tasarlar'
    - 'Model kararlarını küresel ve yerel açıklama yöntemleriyle inceler ve açıklamanın sadakatini ölçer'
    - 'Yanlılık ve mahremiyet risklerini alt gruplarda sayar ve adalet tanımlarının çeliştiğini gösterir'
---

# Model Değerlendirme, Yorumlanabilirlik ve Etik

Yedi kurs boyunca araç olan taban çizgisinin burada tasarım nesnesine dönüşmesi ve her sayının kimin için ölçüldüğünün sorulması: grup temelli ayırmanın geri aldığı şişme, bedel yapısının oynattığı işletme noktası, taban seçiminin aynı modeli iki ayrı biçimde okutması, eşleştirilmiş karşılaştırmanın verdiği dar pay, girdi kayması ile etiket kaymasının farklı çözüm istemesi, açıklamanın kapattığı soru sayısı, modelden okunan önem sırasıyla bozarak ölçülen sıranın ayrışması, aynı örneğe iki yöntemin iki ayrı açıklama vermesi, ortalamanın gizlediği ters yönlü etkileşim, kural listesinin uzunluğuyla doğruluk ödünleşimi, veri, etiket ve dağıtım yanlılığının aynı sayıya farklı yollardan vurması, üç adalet ölçütünün birlikte sağlanamaması, tek kaydın çıktıyı oynatması ile gürültünün bedeli, beyanın cevapsız bıraktığı soru ve sabitlenmemiş tek kalemin oynattığı sayı.

## Değerlendirme Tasarımı

Ölçünün kendisinin tasarlanması ve her sayının hangi alt grup için geçerli olduğunun yazılması: aynı abonenin iki kümeye düşmesinin şişirdiği sayı ile grup temelli ayırmanın bunu geri alması, aynı modelin iki bedel yapısında iki ayrı işletme noktası ve iki ayrı karar vermesi, bir problemde kaç taban bulunduğu ve taban seçiminin aynı modeli iki ayrı biçimde okutması, iki modelin farkının eşleştirilmiş karşılaştırmada bağımsız karşılaştırmadan ne kadar dar bir pay vermesi, eğitim ile üretim dağılımı arasındaki farkın bir sayıya inmesi ve girdi kayması ile etiket kaymasının farklı çözüm istemesi.

### Doğrulama Stratejileri

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/dogrulama-stratejileri

Aynı sayının bütünde ve on üç alt grupta ayrı ayrı ölçülmesi ve ayrılmış kümenin gerçekten ayrılmış olup olmadığının sınanması: derinlik 6 karar ağacı sınama kümesinde tabanı 0,0198 geçerken alt grupların beşinde tabanın altında kalıyor ve n değeri 25'in üstündeki on iki alt grup arasındaki açıklık 0,3576 çıkıyor. Aynı abonenin 3.199 satırlık okuma tablosunda iki kümeye birden düşmesi 416 aboneyi paylaştırıyor ve derinlik 12'de tabanın üstündeki farkı 0,0108'den 0,1000'e çıkarıyor; grup temelli ayırma bu 0,0892'lik şişmeyi geri alıyor. Şişme yalnız bütündeki sayıyı değil açıklığı da bozuyor: satır bölmesinde 0,1718 görünen alt grup açıklığı grup temelli ayırmada 0,3846.

Yedi kurs boyunca her sayının yanına tabanı yazıldı: bir model tek başına okunmadı, kendisinden
daha aptal bir yordamın aynı ölçüdeki sayısıyla yan yana konuldu ve son kursta kararı veren
sistemin kendi verisini değiştirdiği de sayıldı. Sorulmayan tek şey **kimin için** ölçüldüğüdür.
Bütün o sayılar abonelerin ortalamasıydı ve bir ortalama altındaki grupların hiçbirine ait
olmayabilir.

Bu kursun kuralı şudur: **bir sayı, kimin için ölçüldüğü yazılmadan okunamaz; alt grubu yazılmayan
başarım ölçülmemiş sayılır.** Kural her derste üç sayıyla ödenir — bütünde ölçülen sayı, alt
gruplarda ölçülen aynı sayı, aralarındaki **alt grup açıklığı** — ve açıklık görüldüğünde raporda
değişen cümleyle. Bu ders üçlüyü ve alt grupları kurar, ama önce daha öncelikli bir soruyu
yanıtlar: ayrılmış küme gerçekten ayrılmış mıydı.

- **DT1.** Küme yedi kurstan aynen sürer ve **kurgudur**: 3.199 satırlık okuma tablosu, 1.329
  abone, üç dönem, beş bölge, tohum 20260218. Etiket de kurgudur — kaçak ya da arıza şüphesi
  taşıyan abone — ve gerçek bir denetim kaydı değildir.
- **DT2.** Abone düzeyinde 1.260 satır kalır ve **756/252/252** bölünür. Bölme, ölçüt (doğruluk)
  ve taban çizgisi (eğitim kümesinin en sık sınıfı) M27/K01'den devralınır; sınama kümesindeki
  taban **0,7579**'dur. Model **derinlik 6 karar ağacıdır**, standart kitaplıkla yazılır.
- **DT3.** Üç kümenin ayrımı ve zaman sıralı bölme M27/K01'in genelleme konusunda ölçüldü, burada
  tekrarlanmaz; eklenen tek şey **grup temelli ayırmadır**.
- **DT4.** Alt gruplar **dört eksende** tanımlanır ve kurs boyunca sabit kalır: **bölge** (beş
  değer), **tarife basamağı** (ortalama tüketimin düştüğü basamak: 10, 25, 40 m³), **hane
  büyüklüğü** (1–2, 3–4, 5 ve üstü), **okuma sayısı** (az: bir ya da iki dönem; tam: üç dönem).
  Toplam **13 alt grup**.
- **DT5.** Alt grup tanımı bir karardır, bir bulgu değil. **Kaç alt gruba bakıldığı her derste
  yazılır**, çünkü çok bakmak gürültüden bulgu üretir — bu M26/K05'te ölçüldü, tekrarlanmaz.
- **DT6.** Her alt grup sayısının yanına **kaç aboneden okunduğu** yazılır; **n değeri 25'in
  altındaki grup açıklık hesabına girmez**, çünkü 25 abonede tek bir yanlış sayıyı 0,04 oynatır.
- **DT7.** Satır düzeyi tabloda her satır bir **(abone, dönem)** okumasıdır, etiket abonenindir ve
  abone düzeyi özetler satırlara da yazılır. Derinlik **altı adayda** süpürülür.

#### Aynı Sayının On Üç Okuması

İlk blok kurguyu üretir, alt grupları tanımlar ve kursun üçlüsünü tek tabloda basar. Ağaç bir
modeldir: her düğümde bir eşik seçer, yaprakta çoğunluk sınıfını söyler.

```python
# 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, OKUMA, VERI = [], {}, []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r = 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()
    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),
         "bolge": k["bolge"][0]}
    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]


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


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


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


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 gruplar(x):                    # dort eksen, on uc alt grup; kurs boyunca sabit
    return [("bolge", x["bolge"]),
            ("tarife", "10" if x["ort_tuketim"] <= 10 else
             ("25" if x["ort_tuketim"] <= 25 else "40")),
            ("hane", "1-2" if x["hane"] <= 2 else ("3-4" if x["hane"] <= 4 else "5+")),
            ("okuma", "az" if x["donem"] <= 2 else "tam")]


ADLAR = sorted({g for x in VERI for g in gruplar(x)})
EGT, DOG, SIN = uce_bol(karistir(VERI, TOHUM + 90000))
M = agac(EGT, 6, ALAN)


def satir(ad, s):
    tb, dg = taban(EGT, s), dogruluk(M, s)
    print(f"{ad:<14} {len(s):>4} {tb:>7.4f} {dg:>7.4f} {dg - tb:>+8.4f}"
          f"{'   n<25, acikliga girmez' if len(s) < 25 else ''}")
    return len(s), tb, dg


print(f"abone {len(VERI)} -- 756/252/252 -- alt grup {len(ADLAR)} (dort eksen)\n"
      f"{'alt grup':<14} {'n':>4} {'taban':>7} {'agac':>7} {'fark':>8}")
satir("BUTUN", SIN)
olcum = {g: satir(" ".join(g), [x for x in SIN if g in gruplar(x)]) for g in ADLAR}
ol = [v[2] for v in olcum.values() if v[0] >= 25]
alti = [" ".join(g) for g, v in olcum.items() if v[2] < v[1]]
print(f"\naciklik ({len(ol)} alt grup): en iyi {max(ol):.4f}, en kotu {min(ol):.4f}, "
      f"aciklik {max(ol) - min(ol):.4f}\ntabanin altinda kalan: {len(alti)}/"
      f"{len(ADLAR)} -- " + ", ".join(alti))
```

```
abone 1260 -- 756/252/252 -- alt grup 13 (dort eksen)
alt grup          n   taban    agac     fark
BUTUN           252  0.7579  0.7778  +0.0198
bolge bati       32  1.0000  0.9688  -0.0312
bolge dogu       36  0.4722  0.6111  +0.1389
bolge guney      58  0.8276  0.8793  +0.0517
bolge kuzey      68  0.8235  0.7794  -0.0441
bolge merkez     58  0.6552  0.6724  +0.0172
hane 1-2         73  0.7534  0.7945  +0.0411
hane 3-4        143  0.7692  0.7762  +0.0070
hane 5+          36  0.7222  0.7500  +0.0278
okuma az         85  0.7882  0.7412  -0.0471
okuma tam       167  0.7425  0.7964  +0.0539
tarife 10        12  0.6667  0.5833  -0.0833   n<25, acikliga girmez
tarife 25       193  0.8394  0.8290  -0.0104
tarife 40        47  0.4468  0.6170  +0.1702

aciklik (12 alt grup): en iyi 0.9688, en kotu 0.6111, aciklik 0.3576
tabanin altinda kalan: 5/13 -- bolge bati, bolge kuzey, okuma az, tarife 10, tarife 25
```

Birinci satır yedi kursun okuduğu satırdır: model tabanı **0,0198** geçiyor. Altındaki on üç satır
aynı modelin aynı ölçüdeki başka sayılarıdır ve en iyisiyle en kötüsü arasındaki **açıklık
0,3576** — bütünde okunan farkın on sekiz katı. Başarım diye rapor edilen 0,7778, doğu
bölgesindeki abone için 0,6111, batıdaki için 0,9688 demektir.

Daha sert olan sayı son satırdadır: model bütünde tabanı geçiyor ama **on üç alt grubun beşinde
tabanın altında** kalıyor. Az okuması olan 85 abonede taban 0,7882, model 0,7412 — model, hiçbir
şey öğrenmeyen yordamdan 4,7 puan kötü. Bütünde ölçülen fark bu grupların hepsini içeriyor ve
hiçbirini göstermiyor.

Taban sütunu niçin böyle olduğunu söylüyor. Batının 32 sınav abonesinin hiçbiri şüpheli değil;
orada "hiçbiri şüpheli değil" demek 1,0000 verir ve hiçbir model bunu geçemez. Doğuda ve tarife 40
basamağında şüpheli oranı yarıyı aştığı için taban 0,50'nin altına düşer ve model tabanı en çok
orada geçer. Alt grup açıklığı grubun kendi zorluğunu da taşır; bu yüzden her sayının yanında
tabanı durur. Tarife 10 basamağı 12 abone taşıdığı için açıklığa girmiyor.

#### Aynı Abone İki Kümede

Bu tablo kümelerin gerçekten ayrılmış olduğunu varsayıyor. Kurgunun ham hâli abone düzeyinde değil
**okuma düzeyindedir**: 1.260 abone için 3.199 satır ve üç dönem okuma üretmiş bir abonenin üç
satırı vardır, üçünün de etiketi aynıdır. Satırlar karıştırılıp bölündüğü anda aynı abonenin bir
satırı eğitim, öbürü sınama kümesine düşer.

```python
SATIR = []
for x in VERI:
    for i, o in enumerate(OKUMA[x["no"]]):
        SATIR.append(dict(x, okuma=o, sira=i))
SALAN = ["okuma", "sira"] + ALAN

SE, SD, SS = uce_bol(karistir(SATIR, TOHUM + 93000))     # satir bolmesi
G = karistir([x["no"] for x in VERI], TOHUM + 93000)     # grup temelli ayirma
a, b = int(len(G) * 0.6), int(len(G) * 0.8)
KM = {n: (0 if i < a else (1 if i < b else 2)) for i, n in enumerate(G)}
GE = [y for y in SATIR if KM[y["no"]] == 0]
GS = [y for y in SATIR if KM[y["no"]] == 2]

print(f"satir {len(SATIR)} -- satir bolmesi: egitim {len(SE)} sinama {len(SS)}, iki "
      f"kumede birden gorunen abone {len({y['no'] for y in SS} & {y['no'] for y in SE})}"
      f"\ngrup temelli ayirma: egitim {len(GE)} sinama {len(GS)}, ortak abone "
      f"{len({y['no'] for y in GS} & {y['no'] for y in GE})}\ntaban: satir bolmesi "
      f"{taban(SE, SS):.4f}, grup temelli ayirma {taban(GE, GS):.4f}\n\n"
      f"{'derinlik':>8} | {'satir':>7} {'fark':>8} | {'grup':>7} {'fark':>8} "
      f"| {'sisme':>7}")
for d in (2, 4, 6, 8, 10, 12):
    ms, mg = agac(SE, d, SALAN), agac(GE, d, SALAN)
    fs, fg = dogruluk(ms, SS) - taban(SE, SS), dogruluk(mg, GS) - taban(GE, GS)
    print(f"{d:>8} | {dogruluk(ms, SS):>7.4f} {fs:>+8.4f} | {dogruluk(mg, GS):>7.4f} "
          f"{fg:>+8.4f} | {fs - fg:>+7.4f}")
```

```
satir 3199 -- satir bolmesi: egitim 1919 sinama 640, iki kumede birden gorunen abone 416
grup temelli ayirma: egitim 1921 sinama 649, ortak abone 0
taban: satir bolmesi 0.7594, grup temelli ayirma 0.7319

derinlik |   satir     fark |    grup     fark |   sisme
       2 |  0.7812  +0.0219 |  0.7411  +0.0092 | +0.0126
       4 |  0.7781  +0.0187 |  0.7689  +0.0370 | -0.0182
       6 |  0.8078  +0.0484 |  0.7535  +0.0216 | +0.0269
       8 |  0.8266  +0.0672 |  0.7458  +0.0139 | +0.0533
      10 |  0.8375  +0.0781 |  0.7396  +0.0077 | +0.0704
      12 |  0.8594  +0.1000 |  0.7427  +0.0108 | +0.0892
```

Satır bölmesinde 640 sınama satırının sahibi abonelerin **416'sı** eğitim kümesinde de duruyor;
grup temelli ayırmada bu sayı sıfır. İki bölmenin eğitim kümeleri neredeyse aynı büyüklükte
(1.919'a karşı 1.921 satır), yani fark veri miktarından gelmiyor.

Şişme kapasiteyle büyüyor. Derinlik 2'de ağacın ezberleyecek yeri yok; derinlik 4'te şişme geçici
olarak eksi işaretli, çünkü sığ ağaçta bölme gürültüsü sızıntıdan büyük. Derinlik 12'de tablo
açılıyor: satır bölmesi tabanın **0,1000** üstünü gösteriyor, grup temelli ayırma **0,0108**.
Aradaki **0,0892** modelin öğrendiği bir şey değil — ağaç bir aboneyi öznitelik değerlerinden
tanıyıp öbür satırından gördüğü etiketi hatırlıyor.

Zaman sıralı bölme M27/K01'de ölçüldü ve orada kümeler **ne zaman** ölçüldüklerine göre
ayrılmıştı. Grup temelli ayırma başka bir eksende çalışır: kümeler **kimin** verisi olduğuna göre
ayrılır. Bir kayıt birden çok satır üretiyorsa ayırmanın birimi satır değil o kayıttır.

#### Şişme Açıklığı Küçültüyor

Sızıntının bütündeki sayıyı şişirdiği bilinen bir sonuçtur. Bu kursun sorusu başkadır: açıklığa
ne oluyor. Aşağıdaki blok iki bölmenin derinlik 12 modellerini alt gruplara indirir.

```python
sa, ga, dus = [], [], []
for g in ADLAR:
    s1 = [y for y in SS if g in gruplar(y)]
    s2 = [y for y in GS if g in gruplar(y)]
    if min(len(s1), len(s2)) >= 60:     # 60 satir ~ 25 abone; DT6'nin satir karsiligi
        sa.append(dogruluk(ms, s1))
        ga.append(dogruluk(mg, s2))
        dus.append((sa[-1] - ga[-1], " ".join(g), sa[-1], ga[-1]))
for f, ad, d1, d2 in sorted(dus, reverse=True)[:2] + sorted(dus)[:1]:
    print(f"{ad:<14} satir {d1:.4f} | grup {d2:.4f} | dusus {f:+.4f}")
print(f"\naciklik -- satir bolmesi {max(sa) - min(sa):.4f} ({min(sa):.4f} .. "
      f"{max(sa):.4f}), grup temelli ayirma {max(ga) - min(ga):.4f} "
      f"({min(ga):.4f} .. {max(ga):.4f}), {len(sa)} alt grup")
```

```
tarife 40      satir 0.7623 | grup 0.5413 | dusus +0.2210
bolge merkez   satir 0.8364 | grup 0.6279 | dusus +0.2085
bolge bati     satir 0.9341 | grup 0.9259 | dusus +0.0081

aciklik -- satir bolmesi 0.1718 (0.7623 .. 0.9341), grup temelli ayirma 0.3846 (0.5413 .. 0.9259), 12 alt grup
```

Sızıntı alt grupları eşit şişirmiyor. En iyi alt grup iki bölmede de aynı yerde ve neredeyse aynı
sayıda: batı, 0,9341 ve 0,9259. İnen şey **kötü uçtur** — tarife 40 basamağı 0,7623'ten 0,5413'e,
merkez bölgesi 0,8364'ten 0,6279'a. Satır bölmesinde alt grup açıklığı **0,1718** görünüyor, grup
temelli ayırmada **0,3846**: sızıntı gruplar arası farkı yarıdan fazla küçültüyor.

Kötü tasarlanmış bir ayırma böylece iki hata birden üretir: bütündeki sayıyı yükseltir ve alt
gruplar arasındaki farkı bastırır. İkincisi daha sessizdir, çünkü tabloya bakan kişi "gruplar
birbirine yakın" diye okur ve alt grup ölçümünü gereksiz bulur.

#### Özet

- Kursun üçlüsü kuruldu: bütünde ölçülen sayı, **13 alt grupta** ölçülen aynı sayı ve aralarındaki
  **alt grup açıklığı**. Eksenler bölge, tarife basamağı, hane büyüklüğü ve okuma sayısıdır; tanım
  bir karardır ve kaç alt gruba bakıldığı her derste yazılır.
- Derinlik 6 karar ağacı sınama kümesinde tabanı 0,0198 geçiyor ama alt gruplarda 0,6111 ile
  0,9688 arasında değişiyor: açıklık **0,3576**, bütündeki farkın on sekiz katı. On üç alt grubun
  **beşinde model tabanın altında** kalıyor.
- Alt grup sayısı, kaç aboneden okunduğu yazılmadan okunamaz; tarife 10 basamağı 12 abone taşıdığı
  için açıklığa girmez.
- Okuma düzeyindeki 3.199 satır karıştırılınca 416 abone iki kümeye birden düşüyor ve derinlik
  12'de tabanın üstündeki fark 0,0108 yerine 0,1000 görünüyor; grup temelli ayırma bu
  **0,0892**'lik şişmeyi geri alır ve şişme kapasiteyle büyür.
- Sızıntı alt grup açıklığını da bozuyor: satır bölmesinde 0,1718 görünen açıklık grup temelli
  ayırmada **0,3846**. Kötü ayırma sayıyı yükseltmekle kalmaz, gruplar arası farkı da bastırır.

#### Sonraki Adım

Ölçüt boyunca doğruluk olarak alındı ve hiç sorgulanmadı. Oysa doğruluk iki hata türünü aynı
ağırlıkta sayar: şüphesiz bir aboneyi denetime göndermenin bedeliyle şüpheli bir aboneyi
kaçırmanın bedeli aynı değildir ve ikisinin oranı değiştiğinde aynı modelin **eşiği** değişir.
Ölçüt tanımları, eşik ve eğriler M27/K03'te kuruldu ve tekrarlanmayacak. Sonraki ders yalnız şunu
ölçer: aynı model iki ayrı bedel yapısında iki ayrı işletme noktası veriyor — ve bedelin alt
gruplarda aynı olmadığı durumda tek bir eşiğin hangi gruba ne yaptığı sayılır.

### Ölçüt Seçimi

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/olcut-secimi

Aynı modelin iki bedel yapısında iki ayrı işletme noktası ve iki ayrı karar vermesi: denetimin pahalı olduğu yapıda seçilen eşik 0,95 ve 252 abonenin 17'si işaretleniyor, kaçağın pahalı olduğu yapıda eşik 0,25 ve 77'si işaretleniyor; 60 abonenin kararı iki yapı arasında ters dönüyor. Taban çizgisi de bedelle birlikte değişiyor — birinde hiç kimseyi işaretlememek 0,2421, öbüründe herkesi işaretlemek 0,7579. Tek eşiğin alt gruplardaki kazancı +0,4138 ile -0,4468 arasında dağılıyor, açıklık 0,8606 ve on iki alt grubun dördünde model kendi tabanının altında kalıyor; alt gruba özgü eşik seçmek ise sınama bedelini yalnız dördünde düşürüyor.

Önceki ders ölçütü doğruluk olarak aldı ve hiç sorgulamadı. Doğruluk iki hata türünü aynı ağırlıkta
sayar: şüphesiz bir aboneyi denetime göndermek ile şüpheli bir aboneyi kaçırmak eşit ağırlıkta
yanlıştır. İşletmede eşit değildir. Bir denetim ekibinin yolu, zamanı ve boşa giden ziyaretin
abonede bıraktığı iz bir bedeldir; kaçırılan bir kaçak ya da giderilmemiş bir arıza başka bir
bedeldir ve ikisinin oranı bir iş kararıdır.

Bu ders o oranı **bedel yapısı** olarak yazar ve tek şeyi ölçer: aynı model, aynı puanlar, iki
ayrı bedel yapısı — kaç ayrı işletme noktası, kaç ayrı karar. Ölçüt tanımları, eşik ve eğriler
M27/K03'ün model değerlendirme konusunda kuruldu ve burada tekrarlanmaz. Eklenen tek şey, eşiğin
**iş hedefinden** okunmasıdır. Alt gruplar ve üçlü önceki dersten aynen sürer.

- **DT8.** Kurgu, bölme (**756/252/252**), tohum ve alt grup tanımları önceki dersten aynen sürer:
  dört eksen, **13 alt grup**, her sayının yanına n yazılır ve **n < 25 olan grup açıklığa
  girmez**.
- **DT9.** Model aynı derinlik 6 karar ağacıdır, tek farkla: yaprakta sınıf değil **şüpheli
  oranı** durur. Bu oran modelin puanıdır; eşiğin üstündeki abone denetime gönderilir.
- **DT10.** Ölçüt **abone başına bedeldir** ve **küçük iyidir**. Yanlış alarm (işaretlenen ama
  şüphesiz abone) $y$, kaçırma (işaretlenmeyen ama şüpheli abone) $k$ birim tutar; doğru kararlar
  sıfır tutar. Birim soyuttur ve para değildir.
- **DT11.** İki bedel yapısı sınanır. **Denetim pahalı**: $y = 2$, $k = 1$. **Kaçak pahalı**:
  $y = 1$, $k = 4$. İkisi de kurgudur ve bir iş kararını temsil eder.
- **DT12.** Eşik **10 aday** üzerinde süpürülür (0,05'ten 0,95'e onda birlik adımlarla) ve
  **doğrulama kümesinden** seçilir; sınama kümesi yalnız rapor için okunur.
- **DT13.** Taban çizgisi her bedel yapısı için ayrı hesaplanır ve iki öğrenmeyen yordamın **daha
  ucuz olanıdır**: hiç kimseyi işaretlememek, ya da herkesi işaretlemek.
- **DT14.** Alt gruba özgü eşik, o alt grubun **doğrulama** satırlarından seçilir ve o alt grubun
  sınama satırlarında raporlanır. Alt grup doğrulama kümeleri küçüktür ve seçim payı buradan gelir.
- **DT15.** Doğruluk bu derste hiç basılmaz. Önceki dersin 0,7778'i ile bu dersin bedelleri aynı
  eksende değildir ve karşılaştırılmaz.

#### İki Bedel Yapısı, İki Eşik

İlk blok kurguyu kurar, ağacı yaprakta oran bırakacak biçimde eğitir ve on eşiği iki bedel yapısı
altında süpürür.

```python
# 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, OKUMA, VERI = [], {}, []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r = 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()
    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),
         "bolge": k["bolge"][0]}
    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]


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


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


def agac(s, derinlik, alanlar, enaz=2):     # yaprakta sinif degil ORAN durur
    p, en = sum(x["supheli"] for x in s) / len(s), None
    if derinlik and len(s) >= 2 * enaz and 0.0 < p < 1.0:
        for a in alanlar:
            d = sorted({x[a] for x in s})
            for v in (d[1:] if len(d) < 10 else
                      [d[int(i * len(d) / 10)] for i in range(1, 10)]):
                sol = [x for x in s if x[a] < v]
                sag = [x for x in s if x[a] >= v]
                if min(len(sol), len(sag)) < enaz:
                    continue
                k = safsizlik(s) - (len(sol) * safsizlik(sol) + len(sag) * safsizlik(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 {"p": p}
    return {"alan": en[1], "esik": en[2], "sol": agac(en[3], derinlik - 1, alanlar),
            "sag": agac(en[4], derinlik - 1, alanlar)}


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


def gruplar(x):                    # dort eksen, on uc alt grup; 01'den aynen surer
    return [("bolge", x["bolge"]),
            ("tarife", "10" if x["ort_tuketim"] <= 10 else
             ("25" if x["ort_tuketim"] <= 25 else "40")),
            ("hane", "1-2" if x["hane"] <= 2 else ("3-4" if x["hane"] <= 4 else "5+")),
            ("okuma", "az" if x["donem"] <= 2 else "tam")]


def bedel(s, e, ya, ka):           # abone basina bedel; kucuk iyi
    t = 0
    for x in s:
        t += ya * (1 - x["supheli"]) if puan(M, x) >= e else ka * x["supheli"]
    return t / len(s)


def isaret(s, e):
    return sum(puan(M, x) >= e for x in s) / len(s)


ADLAR = sorted({g for x in VERI for g in gruplar(x)})
EGT, DOG, SIN = uce_bol(karistir(VERI, TOHUM + 90000))
M = agac(EGT, 6, ALAN)
ESIK = [0.05 + 0.10 * i for i in range(10)]
YAPI = (("denetim pahali", 2, 1), ("kacak pahali", 1, 4))

print(f"{'esik':>5} | {'A dog':>7} {'A sin':>7} | {'B dog':>7} {'B sin':>7} "
      f"| {'isaret':>7}")
for e in ESIK:
    print(f"{e:>5.2f} | {bedel(DOG, e, 2, 1):>7.4f} {bedel(SIN, e, 2, 1):>7.4f} "
          f"| {bedel(DOG, e, 1, 4):>7.4f} {bedel(SIN, e, 1, 4):>7.4f} "
          f"| {isaret(SIN, e):>7.4f}")
SEC = {}
for ad, ya, ka in YAPI:
    e = SEC[ad] = min(ESIK, key=lambda t: (bedel(DOG, t, ya, ka), t))
    hic, hep = bedel(SIN, 1.1, ya, ka), bedel(SIN, -0.1, ya, ka)
    print(f"\n{ad:<14} esik {e:.2f}  sinama bedeli {bedel(SIN, e, ya, ka):.4f}  taban "
          f"{min(hic, hep):.4f} ({'hicbiri' if hic < hep else 'hepsi'})  kazanc "
          f"{min(hic, hep) - bedel(SIN, e, ya, ka):+.4f}  isaretlenen "
          f"{sum(puan(M, x) >= e for x in SIN)}/{len(SIN)}")
```

```
 esik |   A dog   A sin |   B dog   B sin |  isaret
 0.05 |  1.0952  0.9762 |  0.6032  0.5437 |  0.7063
 0.15 |  0.7659  0.7659 |  0.4802  0.5913 |  0.5357
 0.25 |  0.4802  0.4246 |  0.4762  0.5595 |  0.3056
 0.35 |  0.3889  0.3214 |  0.5278  0.5913 |  0.2183
 0.45 |  0.3492  0.2976 |  0.5079  0.6349 |  0.1825
 0.55 |  0.2778  0.2579 |  0.5833  0.7262 |  0.1151
 0.65 |  0.2540  0.2460 |  0.6548  0.7341 |  0.1032
 0.75 |  0.2222  0.2302 |  0.6667  0.7540 |  0.0833
 0.85 |  0.2222  0.2302 |  0.6667  0.7540 |  0.0833
 0.95 |  0.2183  0.2222 |  0.6786  0.7778 |  0.0675

denetim pahali esik 0.95  sinama bedeli 0.2222  taban 0.2421 (hicbiri)  kazanc +0.0198  isaretlenen 17/252

kacak pahali   esik 0.25  sinama bedeli 0.5595  taban 0.7579 (hepsi)  kazanc +0.1984  isaretlenen 77/252
```

İki bedel sütunu ters yönde iniyor. Denetimin pahalı olduğu yapıda bedel eşik yükseldikçe düşüyor
ve en ucuz nokta **0,95**; kaçağın pahalı olduğu yapıda en ucuz nokta **0,25** ve ondan sonra
yükselmeye başlıyor. Model tek bir modeldir, puanlar tek bir puan kümesidir ve iki yapı aynı
tablodan iki ayrı satır seçiyor. 252 abonenin birinde **17'si**, öbüründe **77'si** denetime
gidiyor.

Taban çizgisi de bedelle birlikte yer değiştiriyor. Denetim pahalıyken en ucuz öğrenmeyen yordam
**hiç kimseyi işaretlememektir** ve 0,2421 tutuyor; kaçak pahalıyken **herkesi işaretlemektir** ve
0,7579 tutuyor. İkisi de aynı kümede, aynı etiketlerle hesaplanıyor. Modelin kazancı da buna göre
değişiyor: birinci yapıda tabanın yalnız **0,0198** altına inebiliyor, ikincisinde **0,1984**.
Aynı model, aynı sınama kümesi — ve biri "az işe yarar", öbürü "belirgin biçimde işe yarar" diye
raporlanır.

#### Karar Kimde Değişiyor

İki işletme noktası arasındaki fark bir tabloda iki satırdır, ama abone tarafında somut bir şeydir:
bazı aboneler bir yapıda denetime gider, öbüründe gitmez.

```python
eA, eB = SEC["denetim pahali"], SEC["kacak pahali"]
fark = [x for x in SIN if (puan(M, x) >= eA) != (puan(M, x) >= eB)]
oran = sorted(((sum(g in gruplar(x) for x in fark)
                / sum(g in gruplar(x) for x in SIN), g) for g in ADLAR), reverse=True)
print(f"karari degisen abone {len(fark)}/{len(SIN)}, {sum(x['supheli'] for x in fark)}"
      f" tanesi supheli; alt gruplarda oran:")
for o, g in oran[:2] + oran[-1:]:
    print(f"  {' '.join(g):<14} {o:.4f}")
```

```
karari degisen abone 60/252, 23 tanesi supheli; alt gruplarda oran:
  tarife 10      0.7500
  bolge dogu     0.5556
  bolge bati     0.0938
```

Altmış abonenin kararı ters dönüyor ve bunların 23'ü gerçekten şüpheli. Bedel yapısını seçmek bir
ölçüt tercihi değil, altmış hanenin kapısının çalınıp çalınmamasıdır. Dağılım eşit de değil: doğu
bölgesindeki abonelerin **0,5556**'sı iki yapı arasında yer değiştirirken batıda bu oran
**0,0938**. Bedel yapısı bir kez seçildiğinde yükünü bütün alt gruplar aynı ölçüde taşımıyor.

#### Bedel Alt Gruplarda Aynı Değil

Kaçağın pahalı olduğu yapıda seçilen tek eşik 0,25'tir ve on üç alt grubun hepsine aynı biçimde
uygulanır. Aşağıdaki blok o tek eşiğin her alt gruptaki bedelini, o alt grubun kendi tabanını ve
alt grup kendi eşiğini seçseydi ne olacağını yan yana basar.

```python
ya, ka = 1, 4
print(f"{'alt grup':<14} {'n':>4} {'isaret':>7} {'bedel':>7} {'taban':>7} {'kazanc':>8}"
      f" | {'kendi':>5} {'bedeli':>7} {'ek':>8}")
kz, ek = [], []
for g in ADLAR:
    d = [x for x in DOG if g in gruplar(x)]
    s = [x for x in SIN if g in gruplar(x)]
    b, tb = bedel(s, eB, ya, ka), min(bedel(s, 1.1, ya, ka), bedel(s, -0.1, ya, ka))
    ke = min(ESIK, key=lambda t: (bedel(d, t, ya, ka), t))
    kb = bedel(s, ke, ya, ka)
    if len(s) >= 25:
        kz.append(tb - b)
        ek.append(b - kb)
    print(f"{' '.join(g):<14} {len(s):>4} {isaret(s, eB):>7.4f} {b:>7.4f} {tb:>7.4f} "
          f"{tb - b:>+8.4f} | {ke:>5.2f} {kb:>7.4f} {b - kb:>+8.4f}"
          f"{'  n<25' if len(s) < 25 else ''}")
print(f"\nkazanc acikligi ({len(kz)} alt grup): en iyi {max(kz):+.4f}, en kotu "
      f"{min(kz):+.4f}, aciklik {max(kz) - min(kz):.4f}; tabanin altinda kalan "
      f"{sum(1 for v in kz if v < 0)}/{len(kz)}")
print(f"kendi esigi sinama bedelini dusuren alt grup: {sum(1 for v in ek if v > 0)}"
      f"/{len(ek)}, degistirmeyen {sum(1 for v in ek if v == 0)}, yukselten "
      f"{sum(1 for v in ek if v < 0)}")
```

```
alt grup          n  isaret   bedel   taban   kazanc | kendi  bedeli       ek
bolge bati       32  0.0938  0.0938  0.0000  -0.0938 |  0.35  0.0625  +0.0312
bolge dogu       36  0.7500  0.7778  0.4722  -0.3056 |  0.45  0.7222  +0.0556
bolge guney      58  0.1897  0.2759  0.6897  +0.4138 |  0.15  0.5517  -0.2759
bolge kuzey      68  0.2500  0.6618  0.7059  +0.0441 |  0.15  0.6765  -0.0147
bolge merkez     58  0.3276  0.8448  0.6552  -0.1897 |  0.25  0.8448  +0.0000
hane 1-2         73  0.3562  0.5205  0.7534  +0.2329 |  0.15  0.6301  -0.1096
hane 3-4        143  0.2657  0.5944  0.7692  +0.1748 |  0.25  0.5944  +0.0000
hane 5+          36  0.3611  0.5000  0.7222  +0.2222 |  0.55  0.7500  -0.2500
okuma az         85  0.2706  0.7059  0.7882  +0.0824 |  0.45  0.8471  -0.1412
okuma tam       167  0.3234  0.4850  0.7425  +0.2575 |  0.15  0.5509  -0.0659
tarife 10        12  0.7500  0.4167  0.6667  +0.2500 |  0.05  0.4167  +0.0000  n<25
tarife 25       193  0.1813  0.4870  0.6425  +0.1554 |  0.45  0.4560  +0.0311
tarife 40        47  0.7021  0.8936  0.4468  -0.4468 |  0.05  0.5957  +0.2979

kazanc acikligi (12 alt grup): en iyi +0.4138, en kotu -0.4468, aciklik 0.8606; tabanin altinda kalan 4/12
kendi esigi sinama bedelini dusuren alt grup: 4/12, degistirmeyen 2, yukselten 6
```

Bütünde 0,1984 olan kazanç alt gruplarda **+0,4138 ile −0,4468** arasına dağılıyor; **açıklık
0,8606**. Dört alt grupta model kendi tabanının **altında**: batı, doğu, merkez ve tarife 40
basamağı. Tarife 40 basamağının kendi tabanı 0,4468, modelin bedeli 0,8936 — o basamakta model,
"herkesi işaretle" demekten iki kat pahalı. Nedeni işaret sütununda: eşik 0,25 o basamaktaki
abonelerin 0,7021'ini işaretliyor ama basamağın şüpheli oranı 0,553 olduğu için işaretlenmeyenler
arasında kalan şüpheliler dört birimlik kaçırma bedelini ödüyor.

Son üç sütun bir düzeltme öneriyor ve düzeltmenin bedelini de gösteriyor. Her alt grup kendi
doğrulama satırlarından kendi eşiğini seçtiğinde tarife 40 basamağı 0,05'e iniyor ve bedeli
0,8936'dan 0,5957'ye düşüyor. Ama aynı işlem on iki alt grubun yalnız **dördünde** sınama bedelini
düşürüyor; ikisinde değiştirmiyor, **altısında yükseltiyor** — güneyde 0,2759, hane 5 ve üstünde
0,2500 birim. Sebep, alt grup doğrulama kümelerinin küçüklüğüdür: kırk yetmiş satırdan seçilen bir
eşik, o satırların gürültüsünü seçiyor. Alt grup başına eşik ayarlamak alt grup başına doğrulama
kümesi ister ve bu kümeler bölmeden değil tasarımdan gelir.

#### Özet

- Bedel yapısı iş hedefini sayıya çevirir: yanlış alarm ile kaçırmanın oranı bir iş kararıdır ve
  eşik o orandan okunur. Ölçüt **abone başına bedeldir** ve küçük iyidir.
- Aynı model, aynı puanlar, iki bedel yapısı: denetim pahalıyken seçilen eşik 0,95 ve 252 abonenin
  17'si işaretleniyor; kaçak pahalıyken eşik 0,25 ve 77'si işaretleniyor. **60 abonenin kararı ters
  dönüyor** ve 23'ü gerçekten şüpheli.
- Taban çizgisi de bedelle değişiyor: birinci yapıda hiç kimseyi işaretlememek (0,2421), ikincide
  herkesi işaretlemek (0,7579) taban olur. Modelin kazancı buna göre +0,0198 ya da +0,1984.
- Tek eşik alt gruplarda tek sonuç vermiyor: kazanç +0,4138 ile −0,4468 arasında dağılıyor,
  **açıklık 0,8606** ve **12 alt grubun 4'ünde model kendi tabanının altında** kalıyor.
- Alt gruba özgü eşik seçmek 12 alt grubun yalnız 4'ünde sınama bedelini düşürüyor, altısında
  yükseltiyor; alt grup doğrulama kümesi küçüldükçe seçim payı büyüyor.

#### Sonraki Adım

Bu derste taban çizgisi ikinci kez kendi başına bir soruya dönüştü. Bedel yapısı değişince taban
da değişti: birinde hiç kimseyi işaretlememek, öbüründe herkesi işaretlemek. Alt gruplarda ise her
grubun kendi tabanı çıktı ve bir grupta 0,0000, başkasında 0,7882 oldu. Yedi kurs boyunca taban
çizgisi bir **araçtı** — modelin sayısını okunur kılan sabit bir işaret. Burada sabit olmadığı
görüldü. Sonraki ders tabanı doğrudan konu edinir: bir problemde kaç taban vardır, hangisi
seçilir, seçim aynı modeli hangi iki ayrı biçimde okutur ve M27'nin yedi kursunda seçilmiş
tabanlar tek bir tabloda toplandığında ne görünür.

### Temel Model

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/temel-model

Taban çizgisinin bir araç değil bir tasarım nesnesi olduğunun ölçülmesi: aynı derinlik 6 karar ağacı sekiz ayrı taban adayına karşı -0,0119 ile +0,5357 arasında okunuyor ve seçim tek başına 0,5476 oynatıyor. Arama tablosu tabanı kendi kapasitesine sahiptir — beş hücrede 0,7579, on beş hücrede 0,7897 ile modeli geçiyor, otuz dokuz hücrede 0,7500'e düşüyor. Taban seçimi alt gruplarda da yön değiştiriyor: en sık sınıfa göre on iki alt grubun dördünde tabanın altında kalan model, bölge ve basamak arama tablosuna göre sekizinde altında kalıyor ve fark açıklığı 0,2173'ten 0,1351'e iniyor. M27'nin yedi kursunda seçilmiş taban çizgileri tek tabloda toplanıyor.

Önceki ders taban çizgisini ikinci kez kendi başına bir soruya dönüştürdü. Bedel yapısı değişince
taban da değişti: bir yapıda hiç kimseyi işaretlememek, öbüründe herkesi işaretlemek. Alt gruplarda
ise her grubun kendi tabanı çıktı ve bir grupta 0,0000, başkasında 0,7882 oldu. Yedi kurs boyunca
taban çizgisi bir **araçtı** — modelin sayısını okunur kılan, seçildikten sonra bir daha
tartışılmayan sabit bir işaret.

Bu ders onun sabit olmadığını ölçer. Bir problemde kaç taban vardır, aralarında nasıl seçim
yapılır, seçim aynı modeli hangi iki ayrı biçimde okutur. Taban çizgisi burada bir araç değil bir
**tasarım nesnesidir**: kendi kapasitesi, kendi aşırı uyumu ve kendi alt grup davranışı olan bir
yordamdır. Dersin sonunda M27'nin yedi kursunda fiilen seçilmiş tabanlar tek bir tabloda toplanır.

- **DT16.** Kurgu, bölme (**756/252/252**), tohum, ölçüt (**doğruluk**) ve alt grup tanımları
  önceki iki dersten aynen sürer: dört eksen, **13 alt grup**, **n < 25 olan grup açıklığa girmez**.
- **DT17.** Karşılaştırılan model **derinlik 6 karar ağacıdır** ve sınama kümesinde **0,7778**
  verir. Bu sayı ders boyunca hiç değişmez; değişen tek şey karşısına konan tabandır.
- **DT18.** Taban adayı, eğitim kümesinden öğrenilmiş olsa bile modelin kullandığı özniteliklerin
  tamamına bakmayan ve kendisi bir ayar araması yapmayan yordamdır. Sınır bir karardır.
- **DT19.** Sekiz aday sınanır: hepsini şüpheli saymak, sınıf oranına göre rastgele atamak, en sık
  sınıfı söylemek, tek bölmeli bir kural ve dört **arama tablosu** — bölge; bölge ve basamak;
  bunlara hane; dört eksenin tamamı. Arama tablosu bir hücredeki eğitim çoğunluğunu söyler,
  görülmemiş hücrede en sık sınıfı; **hücre sayısı yazılır**, çünkü ölçülen şey odur.
- **DT20.** Rastgele atama **yirmi koşumun ortalamasıdır**; tek koşum basılsaydı sayı koşumdan
  koşuma oynardı.
- **DT21.** Adaylar arasında seçim bu derste **yapılmaz**. Ölçülen şey seçimin sonucu değil,
  seçimin aynı modeli ne kadar oynatabildiğidir.
- **DT22.** Son bölümdeki kurs tablosunun her sayısı kaynak dersten okunmuştur; birimler kurslar
  arasında ortak değildir ve satırlar birbiriyle toplanmaz.

#### Bir Problemde Kaç Taban Var

İlk blok kurguyu kurar, modeli eğitir ve sekiz taban adayını aynı sınama kümesinde ölçer.

```python
# 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, OKUMA, VERI = [], {}, []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r = 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()
    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),
         "bolge": k["bolge"][0]}
    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]


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


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


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


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 gruplar(x):                    # dort eksen, on uc alt grup; 01'den aynen surer
    return [("bolge", x["bolge"]),
            ("tarife", "10" if x["ort_tuketim"] <= 10 else
             ("25" if x["ort_tuketim"] <= 25 else "40")),
            ("hane", "1-2" if x["hane"] <= 2 else ("3-4" if x["hane"] <= 4 else "5+")),
            ("okuma", "az" if x["donem"] <= 2 else "tam")]


ADLAR = sorted({g for x in VERI for g in gruplar(x)})
EGT, DOG, SIN = uce_bol(karistir(VERI, TOHUM + 90000))
M, TEK = agac(EGT, 6, ALAN), agac(EGT, 1, ALAN)
ORAN = sum(x["supheli"] for x in EGT) / len(EGT)
CS = int(ORAN > 0.5)


def gr(x):
    return dict(gruplar(x))


def arama(anahtar):                # arama tablosu tabani: hucrede egitim cogunlugu
    c = {}
    for x in EGT:
        c.setdefault(anahtar(x), [0, 0])[x["supheli"]] += 1
    c = {k: int(v[1] > v[0]) for k, v in c.items()}
    return lambda x: c.get(anahtar(x), CS)


def rast(s, n=20):                 # sinif oranina gore atama, yirmi kosumun ortalamasi
    t = 0.0
    for j in range(n):
        r = uretec(TOHUM + 61000 + j)
        t += sum((1 if r() < ORAN else 0) == x["supheli"] for x in s) / len(s)
    return t / n


def oran(f, s):
    return sum(f(x) == x["supheli"] for x in s) / len(s)


ANAHTAR = (("bolge", lambda x: x["bolge"]),
           ("bolge+basamak", lambda x: (x["bolge"], gr(x)["tarife"])),
           ("+hane", lambda x: (x["bolge"], gr(x)["tarife"], gr(x)["hane"])),
           ("dort eksen", lambda x: (x["bolge"], gr(x)["tarife"], gr(x)["hane"],
                                     gr(x)["okuma"])))
ADAY = [("hepsi supheli", 1, lambda x: 1), ("en sik sinif", 1, lambda x: CS),
        ("tek kural", 2, lambda x: tahmin(TEK, x))]
ADAY += [(ad, len({k(x) for x in EGT}), arama(k)) for ad, k in ANAHTAR]

mm = dogruluk(M, SIN)
print(f"model, derinlik 6 karar agaci: egitim {dogruluk(M, EGT):.4f} sinama {mm:.4f}\n\n"
      f"{'taban adayi':<16} {'hucre':>5} {'egitim':>7} {'sinama':>7} {'model farki':>12}")
print(f"{'rastgele atama':<16} {'--':>5} {rast(EGT):>7.4f} {rast(SIN):>7.4f} "
      f"{mm - rast(SIN):>+12.4f}")
fk = [mm - rast(SIN)]
for ad, n, f in ADAY:
    fk.append(mm - oran(f, SIN))
    print(f"{ad:<16} {n:>5} {oran(f, EGT):>7.4f} {oran(f, SIN):>7.4f} {fk[-1]:>+12.4f}")
print(f"\ntaban secimi ayni modeli {min(fk):+.4f} ile {max(fk):+.4f} arasinda okutuyor:"
      f" aralik {max(fk) - min(fk):.4f}")
```

```
model, derinlik 6 karar agaci: egitim 0.8466 sinama 0.7778

taban adayi      hucre  egitim  sinama  model farki
rastgele atama      --  0.6522  0.6450      +0.1327
hepsi supheli        1  0.2222  0.2421      +0.5357
en sik sinif         1  0.7778  0.7579      +0.0198
tek kural            2  0.7778  0.7579      +0.0198
bolge                5  0.7778  0.7579      +0.0198
bolge+basamak       15  0.7897  0.7897      -0.0119
+hane               39  0.7976  0.7500      +0.0278
dort eksen          66  0.8095  0.7738      +0.0040

taban secimi ayni modeli -0.0119 ile +0.5357 arasinda okutuyor: aralik 0.5476
```

Son sütun tek bir modelin sekiz ayrı okunuşudur. Model hiç değişmedi: sınama kümesinde 0,7778. Ama
"hepsini şüpheli say" tabanına göre modelin katkısı **+0,5357**, "bölge ve basamak arama tablosu"
tabanına göre **−0,0119**. Aradaki **0,5476**, verinin ya da modelin değil yalnızca **taban
seçiminin** ürettiği bir sayıdır. Aynı çalışma iki ayrı raporla anlatılabilir ve ikisi de doğru
hesaplanmıştır.

Ortadaki üç satır ikinci sonucu veriyor. En sık sınıf, tek bölmeli bir kural ve bölgeye bakan bir
arama tablosu **aynı sayıyı** üretiyor: 0,7579. Şüphelilik oranı hiçbir bölgede yarıyı geçmediği
için bölge tablosunun beş hücresi de aynı yanıtı söylüyor. Bir tabanı karmaşıklaştırmak onu
güçlendirmez; ancak hücrelerde çoğunluk **değişirse** güçlenir.

Asıl bulgu iki satır aşağıdadır. Bölge ile tarife basamağı birlikte alındığında on beş hücreden
bazılarında çoğunluk dönüyor ve tablo 0,7897 okuyor — **derinlik 6 karar ağacının üstünde**. On bir
öznitelikle eğitilmiş, yüzlerce bölme adayı denemiş bir ağaç, iki sütunlu bir arama tablosuna
kaybediyor. Hane eklendiğinde hücre sayısı 39'a çıkıyor: eğitim sayısı 0,7976'ya yükselirken sınama
sayısı 0,7500'e düşüyor. Dört eksenin tamamında 66 hücre, eğitim 0,8095, sınama 0,7738. **Taban
çizgisinin de bir kapasitesi vardır ve o kapasite aşıldığında taban da aşırı uyum gösterir.** Bu,
tabanı bir araçtan çıkarıp bir tasarım nesnesine çeviren şeydir: seçilirken model seçerken sorulan
sorular sorulur.

#### Taban Seçimi Alt Gruplarda Yön Değiştiriyor

İki tabanın bütündeki farkı yalnız 0,0318'dir. Alt gruplara inildiğinde ikisi aynı şeyi
söylemiyor.

```python
AB = arama(lambda x: (x["bolge"], gr(x)["tarife"]))
print(f"{'alt grup':<14} {'n':>4} {'model':>7} {'A taban':>8} {'A fark':>8} "
      f"{'B taban':>8} {'B fark':>8}")
fa, fb = [], []
for g in ADLAR:
    s = [x for x in SIN if g in gruplar(x)]
    a, b, d = oran(lambda x: CS, s), oran(AB, s), dogruluk(M, s)
    if len(s) >= 25:
        fa.append(d - a)
        fb.append(d - b)
    print(f"{' '.join(g):<14} {len(s):>4} {d:>7.4f} {a:>8.4f} {d - a:>+8.4f} "
          f"{b:>8.4f} {d - b:>+8.4f}{'  n<25' if len(s) < 25 else ''}")
print(f"\nA en sik sinif   : fark {min(fa):+.4f} .. {max(fa):+.4f}, aciklik "
      f"{max(fa) - min(fa):.4f}, tabanin altinda {sum(1 for v in fa if v < 0)}/{len(fa)}")
print(f"B bolge+basamak  : fark {min(fb):+.4f} .. {max(fb):+.4f}, aciklik "
      f"{max(fb) - min(fb):.4f}, tabanin altinda {sum(1 for v in fb if v < 0)}/{len(fb)}")
```

```
alt grup          n   model  A taban   A fark  B taban   B fark
bolge bati       32  0.9688   1.0000  -0.0312   1.0000  -0.0312
bolge dogu       36  0.6111   0.4722  +0.1389   0.6944  -0.0833
bolge guney      58  0.8793   0.8276  +0.0517   0.8276  +0.0517
bolge kuzey      68  0.7794   0.8235  -0.0441   0.8235  -0.0441
bolge merkez     58  0.6724   0.6552  +0.0172   0.6552  +0.0172
hane 1-2         73  0.7945   0.7534  +0.0411   0.8219  -0.0274
hane 3-4        143  0.7762   0.7692  +0.0070   0.7832  -0.0070
hane 5+          36  0.7500   0.7222  +0.0278   0.7500  +0.0000
okuma az         85  0.7412   0.7882  -0.0471   0.7647  -0.0235
okuma tam       167  0.7964   0.7425  +0.0539   0.8024  -0.0060
tarife 10        12  0.5833   0.6667  -0.0833   0.6667  -0.0833  n<25
tarife 25       193  0.8290   0.8394  -0.0104   0.8394  -0.0104
tarife 40        47  0.6170   0.4468  +0.1702   0.6170  +0.0000

A en sik sinif   : fark -0.0471 .. +0.1702, aciklik 0.2173, tabanin altinda 4/12
B bolge+basamak  : fark -0.0833 .. +0.0517, aciklik 0.1351, tabanin altinda 8/12
```

Doğu bölgesi iki tabanın ayrıldığı yerdir. En sık sınıfa göre model orada tabanı **0,1389**
geçiyor ve kursun en iyi katkılarından birini veriyor; bölge ve basamak tablosuna göre tabanın
**0,0833 altında** kalıyor. Tarife 40 basamağında da aynı şey oluyor: +0,1702 yerine 0,0000. İki
sayı da doğru. Fark, birinci tabanın doğu bölgesinin yüksek şüphe oranından habersiz olması,
ikincisinin ise o oranı zaten biliyor olmasıdır. Model bir alt grupta ne kattığını, ancak o alt
grubu **zaten bilen** bir tabanla karşılaştırıldığında söyler.

İki özet satırı sonucu veriyor. En sık sınıf tabanına göre model on iki alt grubun **dördünde**
tabanın altında; arama tablosu tabanına göre **sekizinde**. Fark açıklığı da 0,2173'ten 0,1351'e
iniyor. Güçlü taban modelin katkısını hem küçültüyor hem de alt gruplar arasında düzleştiriyor; bu
bir kusur değil, tabanın alt grubu zaten hesaba katmasının sonucudur. Hangi tabanın raporlanacağı
bu yüzden çalışmanın ne iddia ettiğini belirleyen karardır.

#### M27'nin Yedi Kursunda Seçilmiş Tabanlar

Yedi kurs boyunca her ders bir taban seçti ve gerekçesini yazdı. Aşağıdaki tablo o seçimleri
kaynak derslerden toplar. Birimler ortak değildir ve satırlar birbiriyle toplanmaz.

| Kurs | Seçilen öğrenmeyen yordam | Birim | Örnek sayı |
|---|---|---|---|
| K01 Makine Öğrenmesine Giriş | eğitim kümesinin en sık sınıfı | doğruluk | sınamada 0,7579 |
| K02 Veri Hazırlama ve Öznitelik Mühendisliği | hazırlık kararı uygulanmamış aynı kurulum | doğruluk | 0,7302 ile 0,8294 arası |
| K03 Denetimli Öğrenme | en sık sınıf; bağlanımda ortalamayı söylemek | doğruluk, m³ hata | sınamada 0,7579 ve 6,5324 m³ |
| K04 Denetimsiz Öğrenme | rastgele atama, sütun ortalaması, tek küme | küme içi uzaklık, geri kurma hatası | rastgele atama 5,9790 |
| K05 Derin Öğrenme | her veri kümesi için ayrı en sık sınıf | doğruluk | abone 0,7579; ızgara 0,5850; dizi 0,7100 |
| K06 Doğal Dil İşleme ve Bilgisayarla Görme | alana özgü taban | doğruluk, örtüşme, sözlük boyu | oran birimli on iki taban 0,0400 ile 0,8731 arası |
| K07 Pekiştirmeli Öğrenme ve Öneri Sistemleri | rastgele eylem; en çok seçilen kalem | getiri; ilk beş isabeti | 10,432 ve 0,6527 |

Tablodan iki şey okunur. Birincisi, taban çizgisi kurstan kursa **tür değiştiriyor**: bir sınıfı
söylemek, bir ortalamayı söylemek, rastgele davranmak, en çok seçileni önermek, ya da bir kararın
uygulanmadığı hâli koymak. İkincisi, K05 ve K06 satırları aynı kurs içinde bile tek bir taban
olmadığını gösteriyor: dört ayrı veri kümesi dört ayrı taban. "Taban çizgisini geçti" cümlesi
yazıldığında geçilen şey her seferinde başka bir yordamdı ve bu dersin tablosu o farkın
büyüklüğünü veriyor.

#### Özet

- Taban çizgisi bir araç değil bir tasarım nesnesidir. Aynı derinlik 6 karar ağacı, sekiz taban
  adayına karşı **−0,0119 ile +0,5357** arasında okunuyor; seçimin tek başına oynattığı **0,5476**.
- Bir tabanı karmaşıklaştırmak onu güçlendirmez: en sık sınıf, tek bölmeli kural ve bölge arama
  tablosu aynı 0,7579'u veriyor, çünkü hiçbir bölgede çoğunluk dönmüyor.
- Taban çizgisinin de kapasitesi vardır. Arama tablosu 15 hücrede 0,7897 ile **modeli geçiyor**,
  39 hücrede eğitimde 0,7976'ya çıkarken sınamada 0,7500'e düşüyor: taban da aşırı uyum gösterir.
- Alt gruplarda taban seçimi yön değiştiriyor. Doğu bölgesinde model bir tabana göre +0,1389,
  öbürüne göre −0,0833. En sık sınıfa göre 12 alt grubun 4'ünde tabanın altında olan model, arama
  tablosuna göre **8'inde** altında; fark açıklığı 0,2173'ten 0,1351'e iniyor.
- M27'nin yedi kursunda taban çizgisi tür değiştirdi ve tek bir kursta bile birden çok taban
  kullanıldı; "tabanı geçti" cümlesinde geçilen şey her seferinde başka bir yordamdır.

#### Sonraki Adım

Üç derste on dört ayrı sayı çifti karşılaştırıldı ve hepsinde fark doğrudan okundu: 0,0198,
−0,0119, +0,1702. Hiçbirinde sorulmayan şey, bu farkların **252 abonelik bir kümenin
gürültüsünden** ayırt edilip edilemeyeceğidir. Bir alt grupta 36 aboneden okunan 0,1389'luk bir
katkı, birkaç abonenin sınıfı ters dönseydi kaybolabilir. Hipotez sınaması, yeniden karıştırma ve
geri koyarak örnekleme M26/K05'te ölçüldü ve tekrarlanmayacak. Sonraki ders yalnız şunu ölçer: iki
modelin **farkının payı** ne kadardır, aynı örneklerde ölçülen **eşleştirilmiş karşılaştırma**
bağımsız karşılaştırmadan ne kadar dar bir pay verir ve ayrılmış kümenin büyüklüğü o payı nasıl
belirler.

### İstatistiksel Anlamlılık

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/istatistiksel-anlamlilik

İki modelin farkının payının ölçülmesi ve eşleştirilmiş karşılaştırmanın bağımsız karşılaştırmadan ne kadar dar bir pay verdiğinin sayılması: derinlik 6 karar ağacının dört rakibiyle arasındaki farkların hepsinin payı sıfırı içeriyor ve yalnız 0,5357'lik fark dışarıda bırakıyor. Aynı 252 abonede eşleştirilmiş pay 0,0476 ile 0,0794 arasında, bağımsız pay 0,1190 ile 0,1310 arasında; iki model ne kadar çok anlaşırsa pay o kadar daralıyor. Küme 63'ten 504'e çıkarken eşleştirilmiş pay 0,1111'den 0,0556'ya iniyor. Alt gruplarda on üç farkın yalnız dördünün payı sıfırı dışarıda bırakıyor ve kursun en büyük alt grup katkılarından biri olan +0,1389 bunlardan biri değil.

Üç derste on dört ayrı sayı çifti karşılaştırıldı ve hepsinde fark doğrudan okundu: bir yerde
+0,0198, başka bir yerde −0,0119, bir alt grupta +0,1702. Hiçbirinde sorulmayan şey, bu farkların
**252 abonelik bir kümenin gürültüsünden** ayırt edilip edilemeyeceğidir. Otuz altı aboneden okunan
0,1389'luk bir katkı, birkaç abonenin sınıfı ters dönseydi kaybolabilir.

Hipotez sınaması, yeniden karıştırma, geri koyarak örnekleme ve oynama payı M26/K05'te ölçüldü;
sınama kuramı burada tekrarlanmaz ve aynı araç yalnız model başarımına uygulanır. Bu ders üç şey
ölçer: iki modelin farkının payı, aynı örneklerde ölçmenin (**eşleştirilmiş karşılaştırma**) o payı
ne kadar daralttığı ve ayrılmış kümenin büyüklüğünün payı nasıl belirlediği.

- **DT23.** Kurgu, bölme (**756/252/252**), tohum, ölçüt (**doğruluk**) ve alt grup tanımları
  önceki derslerden aynen sürer: dört eksen, **13 alt grup**.
- **DT24.** Karşılaştırılan model **derinlik 6 karar ağacıdır** (sınamada 0,7778). Rakipler:
  en sık sınıf, derinlik 2 ağaç, derinlik 8 ağaç, bölge ve basamak arama tablosu ve hepsini
  şüpheli saymak. Hepsi önceki derslerde kurulmuştur.
- **DT25.** Pay **geri koyarak örneklemeyle** hesaplanır: **400 tekrar**, yüzde 5 ve yüzde 95
  noktaları. Yöntem M26/K05'te ölçüldü ve burada gerekçelendirilmez.
- **DT26.** **Eşleştirilmiş karşılaştırmada** yeniden örneklenen şey abone başına **fark**
  göstergesidir: aynı abone iki modelde de doğru ya da yanlıştır ve ortak hata payı düşer.
- **DT27.** **Bağımsız karşılaştırmada** iki modelin sayıları ayrı ayrı yeniden örneklenir; bu,
  iki modelin iki ayrı kümede ölçülmüş olması durumuna karşılık gelir.
- **DT28.** Payın sıfırı içermesi "iki model aynıdır" demek değildir; **bu kümede bu farkın ölçülemediği**
  demektir. Ölçüm eksiği ile eşitlik ayrı şeylerdir.
- **DT29.** Küme büyüklüğü süpürmesinde 504'lük satır doğrulama ve sınama kümelerinin
  birleştirilmesiyle kurulur ve **yalnız payın büyüklükle nasıl daraldığını** göstermek içindir;
  raporlanabilir bir başarım sayısı değildir, çünkü doğrulama kümesine daha önce bakılmıştır.
- **DT30.** Alt grup payları aynı yordamla hesaplanır. Küçük alt grupta pay geniştir ve bu bir
  kusur değil, örneklem büyüklüğünün doğrudan sonucudur.

#### İki Modelin Farkı ve Payı

İlk blok kurguyu kurar, beş rakibi aynı sınama kümesinde ağaçla karşılaştırır ve her fark için iki
pay basar.

```python
# 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, OKUMA, VERI = [], {}, []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r = 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()
    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),
         "bolge": k["bolge"][0]}
    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]


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


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


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


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 gruplar(x):                    # dort eksen, on uc alt grup; 01'den aynen surer
    return [("bolge", x["bolge"]),
            ("tarife", "10" if x["ort_tuketim"] <= 10 else
             ("25" if x["ort_tuketim"] <= 25 else "40")),
            ("hane", "1-2" if x["hane"] <= 2 else ("3-4" if x["hane"] <= 4 else "5+")),
            ("okuma", "az" if x["donem"] <= 2 else "tam")]


ADLAR = sorted({g for x in VERI for g in gruplar(x)})
EGT, DOG, SIN = uce_bol(karistir(VERI, TOHUM + 90000))
CS = int(sum(x["supheli"] for x in EGT) * 2 > len(EGT))
A, D2, D8 = agac(EGT, 6, ALAN), agac(EGT, 2, ALAN), agac(EGT, 8, ALAN)
TEKRAR = 400
c = {}
for x in EGT:                      # bolge+basamak arama tablosu tabani, 03'ten surer
    k = (x["bolge"], dict(gruplar(x))["tarife"])
    c.setdefault(k, [0, 0])[x["supheli"]] += 1
c = {k: int(v[1] > v[0]) for k, v in c.items()}
AB = (lambda x: c.get((x["bolge"], dict(gruplar(x))["tarife"]), CS))


def ikili(s, f, tohum):
    # geri koyarak ornekleme M26/K05'te olculdu; burada yalniz FARKA uygulanir
    dA = [int(tahmin(A, x) == x["supheli"]) for x in s]
    dB = [int(f(x) == x["supheli"]) for x in s]
    fark, n, esl, bag = [a - b for a, b in zip(dA, dB)], len(s), [], []
    for j in range(TEKRAR):
        r, r1, r2 = uretec(tohum + j), uretec(tohum + 5000 + j), uretec(tohum + 9000 + j)
        esl.append(sum(fark[int(r() * n)] for _ in range(n)) / n)
        bag.append(sum(dA[int(r1() * n)] for _ in range(n)) / n
                   - sum(dB[int(r2() * n)] for _ in range(n)) / n)
    esl.sort()
    bag.sort()
    a5, a95 = int(0.05 * TEKRAR), int(0.95 * TEKRAR) - 1
    return (sum(fark) / n, esl[a5], esl[a95], bag[a5], bag[a95],
            sum(1 for v in fark if v))


RAKIP = (("en sik sinif", lambda x: CS), ("derinlik 2", lambda x: tahmin(D2, x)),
         ("derinlik 8", lambda x: tahmin(D8, x)), ("arama tablosu", AB),
         ("hepsi supheli", lambda x: 1))
print(f"{'rakip':<15} {'uyusmaz':>8} {'fark':>8} | {'eslestirilmis':>21} {'gen':>7}"
      f" | {'bagimsiz':>21} {'gen':>7} | sifir")
for ad, f in RAKIP:
    d, lo, hi, blo, bhi, u = ikili(SIN, f, 71000)
    print(f"{ad:<15} {u:>8} {d:>+8.4f} | [{lo:>+8.4f}, {hi:>+8.4f}] {hi - lo:>7.4f}"
          f" | [{blo:>+8.4f}, {bhi:>+8.4f}] {bhi - blo:>7.4f} | "
          f"{'disinda' if lo > 0 or hi < 0 else 'icinde'}")
```

```
rakip            uyusmaz     fark |         eslestirilmis     gen |              bagimsiz     gen | sifir
en sik sinif          37  +0.0198 | [ -0.0198,  +0.0556]  0.0754 | [ -0.0516,  +0.0794]  0.1310 | icinde
derinlik 2            24  -0.0079 | [ -0.0437,  +0.0238]  0.0675 | [ -0.0714,  +0.0516]  0.1230 | icinde
derinlik 8            12  +0.0159 | [ -0.0079,  +0.0397]  0.0476 | [ -0.0437,  +0.0754]  0.1190 | icinde
arama tablosu         33  -0.0119 | [ -0.0556,  +0.0238]  0.0794 | [ -0.0754,  +0.0476]  0.1230 | icinde
hepsi supheli        215  +0.5357 | [ +0.4603,  +0.6190]  0.1587 | [ +0.4683,  +0.5992]  0.1310 | disinda
```

Son sütun dersin ilk sonucudur. Beş karşılaştırmanın **dördünde** payın içinde sıfır var. Modelin
en sık sınıfı 0,0198 geçmesi, arama tablosuna 0,0119 kaybetmesi, derinlik 2 ile arasındaki 0,0079,
derinlik 8 ile arasındaki 0,0159 — dördü de 252 abonelik bu kümede ölçülemiyor. Yalnız
"hepsini şüpheli say" farkı, 0,5357 ile payın dışında kalıyor. Önceki üç dersin tablolarındaki
sayılar yanlış hesaplanmış değil; **ölçüm eşiğinin altındalar** ve bu iki ayrı şeydir.

İkinci sonuç iki pay sütununun karşılaştırılmasıdır. Eşleştirilmiş pay her satırda daha dar:
0,0754'e karşı 0,1310, 0,0675'e karşı 0,1230, 0,0476'ya karşı 0,1190. Neden uyuşmazlık sütununda
duruyor. Derinlik 8 ağacı ile derinlik 6 ağacı 252 abonenin yalnız **12'sinde** ayrılıyor; geri
kalan 240 abonede ikisi de aynı yanıtı veriyor ve o abonelerin zorluğu farkın hesabından tamamen
çıkıyor. Bağımsız ölçümde çıkmıyor, çünkü orada iki modelin **ayrı kümelerde** ölçüldüğü
varsayılıyor ve her kümenin kendi zorluk değişkenliği paya giriyor. İki modeli aynı örneklerde
ölçmek, veri toplamadan payı **iki buçuk kata kadar** daraltıyor.

Son satır ters yönde okunur: "hepsini şüpheli say" ile ağaç 215 abonede ayrıldığı için
eşleştirilmiş pay orada bağımsız paydan **geniş**. Eşleştirme her zaman daraltmaz; iki model ne
kadar çok anlaşırsa o kadar daraltır.

#### Payı Belirleyen Küme Büyüklüğüdür

Payın genişliği modelden değil kümeden gelir. Aynı karşılaştırma, kümenin baş tarafından alınan
farklı büyüklüklerde yinelenir.

```python
HAVUZ = DOG + SIN
print(f"{'kume':>6} | {'fark':>8} {'eslestirilmis':>21} {'gen':>7} | {'bagimsiz gen':>13}")
for n in (63, 126, 189, 252, 504):
    d, lo, hi, blo, bhi, u = ikili(HAVUZ[:n] if n > 252 else SIN[:n], AB, 74000)
    print(f"{n:>6} | {d:>+8.4f} [{lo:>+8.4f}, {hi:>+8.4f}] {hi - lo:>7.4f} | "
          f"{bhi - blo:>13.4f}")
```

```
  kume |     fark         eslestirilmis     gen |  bagimsiz gen
    63 |  +0.0000 [ -0.0635,  +0.0476]  0.1111 |        0.2540
   126 |  +0.0079 [ -0.0397,  +0.0556]  0.0952 |        0.1667
   189 |  -0.0106 [ -0.0529,  +0.0317]  0.0847 |        0.1376
   252 |  -0.0119 [ -0.0476,  +0.0278]  0.0754 |        0.1270
   504 |  -0.0159 [ -0.0437,  +0.0119]  0.0556 |        0.0794
```

Fark sütunu kararsız: 63 aboneden 0,0000, 126'dan +0,0079, 504'ten −0,0159. İşaret bile
değişiyor. Pay sütunu ise düzenli daralıyor — 0,1111'den 0,0556'ya, yani küme sekiz katına
çıkarken pay yarıya iniyor. Bu, ölçülebilecek en küçük farkın küme büyüklüğüne bağlı olduğu
anlamına gelir: 252 abonede 0,04'ün altındaki hiçbir fark okunamaz ve M27 boyunca raporlanan
model farklarının çoğu bu eşiğin altındadır.

Son satır bir uyarı taşır. 504'lük küme doğrulama ile sınamanın birleşimidir ve doğrulama kümesine
model seçilirken zaten bakılmıştır; oradaki −0,0159 raporlanabilir bir başarım sayısı değildir.
Satır yalnız payın büyüklükle nasıl daraldığını göstermek için durur. Ayrılmış kümenin büyüklüğü
bu yüzden bir bölme oranı değil, **ölçülmek istenen en küçük farkın** bir sonucudur.

#### Alt Grupta Fark Payın İçinde Kayboluyor

Alt grup açıklığı üç derste ölçüldü. Şimdi her alt gruptaki farkın kendi payı hesaplanır.

```python
print(f"{'alt grup':<14} {'n':>4} {'uyusmaz':>8} {'fark':>8} "
      f"{'eslestirilmis pay':>22} {'sifir':>8}")
dis = 0
for g in ADLAR:
    s = [x for x in SIN if g in gruplar(x)]
    d, lo, hi, blo, bhi, u = ikili(s, lambda x: CS, 76000)
    dis += lo > 0 or hi < 0
    print(f"{' '.join(g):<14} {len(s):>4} {u:>8} {d:>+8.4f} [{lo:>+8.4f}, {hi:>+8.4f}]"
          f" {'disinda' if lo > 0 or hi < 0 else 'icinde':>8}")
print(f"\npayi sifiri disarida birakan alt grup: {dis}/{len(ADLAR)}")
```

```
alt grup          n  uyusmaz     fark      eslestirilmis pay    sifir
bolge bati       32        1  -0.0312 [ -0.0938,  +0.0000]   icinde
bolge dogu       36       19  +0.1389 [ -0.0556,  +0.3611]   icinde
bolge guney      58        3  +0.0517 [ +0.0172,  +0.1034]  disinda
bolge kuzey      68        7  -0.0441 [ -0.1176,  +0.0147]   icinde
bolge merkez     58        7  +0.0172 [ -0.0690,  +0.1034]   icinde
hane 1-2         73        9  +0.0411 [ -0.0274,  +0.1096]   icinde
hane 3-4        143       21  +0.0070 [ -0.0420,  +0.0629]   icinde
hane 5+          36        7  +0.0278 [ -0.0833,  +0.1389]   icinde
okuma az         85        4  -0.0471 [ -0.0824,  -0.0118]  disinda
okuma tam       167       33  +0.0539 [ +0.0060,  +0.1018]  disinda
tarife 10        12        1  -0.0833 [ -0.2500,  +0.0000]   icinde
tarife 25       193       22  -0.0104 [ -0.0466,  +0.0311]   icinde
tarife 40        47       14  +0.1702 [ +0.0426,  +0.2766]  disinda

payi sifiri disarida birakan alt grup: 4/13
```

Doğu bölgesi satırı bu dersin en sert sonucudur. Modelin oradaki katkısı **+0,1389** ve bu, kursun
şimdiye kadar ölçtüğü en büyük alt grup katkılarından biriydi. Payı **[−0,0556, +0,3611]** ve
sıfırı içeriyor. Otuz altı abonede on dokuz uyuşmazlık, farkı üçte bir puan genişliğinde bir
aralığa yayıyor. Aynı sayı iki derste "modelin doğuda kattığı" diye okundu; burada okunamayacağı
görülüyor.

Sıfırı dışarıda bırakan dört alt grup vardır ve biri ters yöndedir: az okuması olan 85 abonede
fark **−0,0471** ve payı **[−0,0824, −0,0118]**. Model o alt grupta en sık sınıfı söylemekten
ölçülebilir biçimde **kötüdür**. Kalan üçü ileri yöndedir: güney +0,0517, tam okumalılar +0,0539,
tarife 40 basamağı +0,1702.

Buradan iki kural çıkar. Alt grup açıklığı bir tasarım kararının sonucudur ve **açıklığın kendisi
ölçülebilir**, ama açıklığı oluşturan tek tek farklar çoğu alt grupta ölçülemez. İkincisi, on üç
alt gruba bakıp içlerinden en büyük farkı seçmek, M26/K05'te sayılan çoklu bakış payını yeniden
üretir: on üç bağımsız sınamanın birinde payın dışına çıkmak, on üç kez bakıldığı yazılmadan bir
bulgu değildir.

#### Özet

- Beş karşılaştırmanın dördünde payın içinde sıfır var: modelin en sık sınıfı 0,0198 geçmesi,
  arama tablosuna 0,0119 kaybetmesi ve iki derinlik farkı 252 abonede **ölçülemiyor**. Payın sıfırı
  içermesi eşitlik değil, ölçüm eksiği demektir.
- Eşleştirilmiş karşılaştırma bağımsızdan dar pay verir: 0,0754'e karşı 0,1310, 0,0476'ya karşı
  0,1190. Daralma iki modelin uyuşma oranından gelir ve 215 abonede ayrışan bir çiftte eşleştirme
  payı **genişletir**.
- Pay küme büyüklüğüyle daralıyor: 63 abonede 0,1111, 504'te 0,0556. Ayrılmış kümenin büyüklüğü
  bir bölme oranı değil, ölçülmek istenen en küçük farkın sonucudur.
- Alt gruplarda 13 farkın yalnız **4'ünün** payı sıfırı dışarıda bırakıyor. Kursun en büyük alt
  grup katkılarından biri olan doğu bölgesindeki +0,1389 bunlardan biri değil: payı [−0,0556, +0,3611].
- Sıfırı dışarıda bırakan dört farktan biri ters yönde: az okuması olan abonelerde model
  **−0,0471** ile tabanın ölçülebilir biçimde altında.

#### Sonraki Adım

Dört derste ölçünün kendisi tasarlandı: küme kime göre ayrıldı, eşik hangi bedelden okundu, taban
nasıl seçildi, fark hangi payla söylendi. Hepsinin ortak varsayımı, sınama kümesinin modelin
karşılaşacağı veriyle **aynı dağılımdan** geldiğidir. Bir ölçüm ağı zamanla değişir: yeni bölgeler
katılır, tarife basamakları kayar, sayaç değişimiyle sıfır okuma oranı düşer. Sonraki ders o
varsayımı ölçer — eğitim ile üretim verisi arasındaki farkı tek bir sayıya indirir, bu sayıyı
başarım düşüşüyle yan yana koyar ve **girdi kayması** ile **etiket kaymasını** ayırarak ikisinin
niçin farklı çözüm istediğini gösterir.

### Dağılım Kayması

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/dagilim-kaymasi

Eğitim ile üretim verisi arasındaki farkın tek bir sayıya indirilmesi ve bu sayının başarım düşüşüyle yan yana konması: ayırt edici bir model girdi kaymasında 0,1172'lik pay veriyor ve modelin tabanın üstündeki farkı 0,0198'den 0,0066'ya iniyor, ama etiket kaymasında aynı gösterge 0,0063'te kalırken şüpheli oranı 0,2421'den 0,4865'e çıkıyor. İki kayma iki ayrı çözüm istiyor: önsel düzeltmesi etiket kaymasında doğruluğu 0,6306'dan 0,6622'ye çıkarırken girdi kaymasında hiçbir kararı değiştirmiyor, girdi dağılımına göre yeniden eğitim ise girdi kaymasında 0,7318'i 0,7384'e çıkarıp etiket kaymasında 0,6261'e düşürüyor. Zaman sıralı üretim kümesinde alt grup açıklığı 0,3576'dan 0,2573'e iniyor ve on iki alt grubun hiçbirinde model tabanın altında kalmıyor.

Dört derste ölçünün kendisi tasarlandı: küme kime göre ayrıldı, eşik hangi bedelden okundu, taban
nasıl seçildi, fark hangi payla söylendi. Dördünün ortak varsayımı, sınama kümesinin modelin
karşılaşacağı veriyle **aynı dağılımdan** geldiğidir. Bir ölçüm ağı zamanla değişir: yeni bölgeler
katılır, tarife basamakları kayar, sayaç değişimiyle sıfır okuma oranı düşer.

Bu ders o varsayımı ölçer. **Dağılım kayması** iki ayrı şekilde gelir ve ikisi aynı ad altında
toplandığında yanlış çözüm seçilir. **Girdi kaymasında** özniteliklerin dağılımı değişir ama bir
abonenin öznitelikleri verildiğinde şüpheli olma olasılığı aynı kalır. **Etiket kaymasında**
şüphelilik oranı değişir. Veri kayması M27/K01'de anıldı ve zaman sıralı bölme orada ölçüldü;
burada eklenen şey kaymanın **tek bir sayıya indirilmesi** ve iki türün ayrılmasıdır.

- **DT31.** Kurgu, bölme (**756/252/252**), tohum, ölçüt (**doğruluk**), model (**derinlik 6 karar
  ağacı**, yaprakta şüpheli oranı) ve alt grup tanımları önceki derslerden aynen sürer: dört eksen,
  **13 alt grup**. Eğitim kümesinin şüpheli oranı **0,2222**'dir.
- **DT32.** **Kayma payı** bir **ayırt edici modelle** ölçülür: satırın eğitim kümesinden mi üretim
  kümesinden mi geldiğini kestiren derinlik 4 bir ağaç, iki kümeden eşit sayıda satırla eğitilir ve
  ayrılmış yarıda ölçülür. Sayı **doğruluk eksi 0,5**'tir; sıfıra yakın değer "ayırt edilemiyor"
  demektir. Beş koşumun ortalaması alınır ve etiket sütunu ayırt ediciye **verilmez**.
- **DT33.** Kayma payı yalnız **girdi** dağılımını görür. Etiket dağılımının kaymasını göremez ve
  bu dersin ölçtüğü şeylerden biri budur.
- **DT34.** Üç kurgu üretim kümesi doğrulama ve sınama kümelerinin birleşiminden (504 abone)
  türetilir. **Girdi kayması**: yüksek ortalama tüketimli abonelerin seçilme olasılığı yükseltilir,
  etiket kuralına dokunulmaz. **Etiket kayması**: şüpheli aboneler korunur, şüphesizlerin yalnız
  yüzde 30'u tutulur. **Zaman sıralı üretim**: abone numarasına göre sıralanmış kümenin son yüzde
  20'si; abone numarası ağa katılma sırasıdır.
- **DT35.** **Önsel düzeltmesi** modelin yaprak oranını, üretim ve eğitim şüphelilik oranlarının
  oran oranıyla çarpar; üretimde etiket bilmeyi gerektirir ve bu bir maliyettir. **Yeniden eğitim**
  aynı ağacı, girdi kayması kuralıyla örneklenmiş **439** satırlık bir eğitim kümesinde kurar;
  756 satırın 317'si düşer ve kayıp veri bir bedeldir.
- **DT36.** Model bir kez eğitilir ve dört kümede aynı model ölçülür; fark modelden değil veriden
  gelir. Üretim kümelerinin boyları eşit değildir (302, 222, 252) ve pay hesapları önceki derste
  ölçüldü, burada tekrarlanmaz.

#### Kaymanın Büyüklüğü Bir Sayıdır

İlk blok kurguyu kurar, üç üretim kümesini üretir, her biri için kayma payını ölçer ve aynı satırda
tabanı, modelin sayısını ve iki düzeltmenin sonucunu basar.

```python
# 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, OKUMA, VERI = [], {}, []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r = 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()
    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),
         "bolge": k["bolge"][0]}
    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]


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


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


def agac(s, derinlik, alanlar, enaz=2):
    p, en = sum(x["supheli"] for x in s) / len(s), None
    if derinlik and len(s) >= 2 * enaz and 0.0 < p < 1.0:
        for a in alanlar:
            d = sorted({x[a] for x in s})
            for v in (d[1:] if len(d) < 10 else
                      [d[int(i * len(d) / 10)] for i in range(1, 10)]):
                sol = [x for x in s if x[a] < v]
                sag = [x for x in s if x[a] >= v]
                if min(len(sol), len(sag)) < enaz:
                    continue
                k = safsizlik(s) - (len(sol) * safsizlik(sol) + len(sag) * safsizlik(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 {"p": p}
    return {"alan": en[1], "esik": en[2], "sol": agac(en[3], derinlik - 1, alanlar),
            "sag": agac(en[4], derinlik - 1, alanlar)}


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


def gruplar(x):                    # dort eksen, on uc alt grup; 01'den aynen surer
    return [("bolge", x["bolge"]),
            ("tarife", "10" if x["ort_tuketim"] <= 10 else
             ("25" if x["ort_tuketim"] <= 25 else "40")),
            ("hane", "1-2" if x["hane"] <= 2 else ("3-4" if x["hane"] <= 4 else "5+")),
            ("okuma", "az" if x["donem"] <= 2 else "tam")]


ADLAR = sorted({g for x in VERI for g in gruplar(x)})
EGT, DOG, SIN = uce_bol(karistir(VERI, TOHUM + 90000))
M = agac(EGT, 6, ALAN)
P0 = sum(x["supheli"] for x in EGT) / len(EGT)
CS = int(P0 > 0.5)


def dog(f, s):
    return sum(f(x) == x["supheli"] for x in s) / len(s)


def kayma(a, b, tohum, tekrar=5):
    # AYIRT EDICI MODEL: satirin hangi kumeden geldigini kestiren derinlik 4 agac
    t = 0.0
    for j in range(tekrar):
        n = min(len(a), len(b))
        ka = [dict(x, supheli=0) for x in karistir(a, tohum + j)[:n]]
        kb = [dict(x, supheli=1) for x in karistir(b, tohum + 500 + j)[:n]]
        d = agac(karistir(ka[:n // 2] + kb[:n // 2], tohum + 900 + j), 4, ALAN)
        s = ka[n // 2:] + kb[n // 2:]
        t += sum((puan(d, x) > 0.5) == x["supheli"] for x in s) / len(s)
    return t / tekrar - 0.5


def girdi_kay(s, tohum, guc=0.12):      # yuksek tuketim agir basar; etiket kurali AYNI
    r = uretec(tohum)
    return [x for x in s if r() < min(0.98, 0.03 + guc * max(0.0, x["ort_tuketim"] - 14))]


def etiket_kay(s, tohum, tut=0.30):     # supheliler korunur, supheslerin %30'u kalir
    r = uretec(tohum)
    return [x for x in s if x["supheli"] or r() < tut]


HAVUZ = DOG + SIN
ZU = uce_bol(sorted(VERI, key=lambda x: x["no"]))[2]
GK, EK = girdi_kay(HAVUZ, 83000), etiket_kay(HAVUZ, 84000)
MG = agac(girdi_kay(EGT, 86000), 6, ALAN)


def onsel(s):                           # onsel duzeltmesi: oranlarin orani ile
    p1 = sum(x["supheli"] for x in s) / len(s)
    o = (p1 / (1 - p1)) / (P0 / (1 - P0))
    return lambda x: int(puan(M, x) * o / (puan(M, x) * o + 1 - puan(M, x)) >= 0.5)


print(f"{'kume':<16} {'n':>4} {'supheli':>8} {'kayma':>8} {'taban':>7} {'model':>7} "
      f"{'fark':>8} {'onsel':>7} {'yenidn':>7}")
for ad, s in (("ayni dagilim", SIN), ("girdi kaymasi", GK), ("etiket kaymasi", EK),
              ("zaman sirali", ZU)):
    tb = dog(lambda x: CS, s)
    print(f"{ad:<16} {len(s):>4} {sum(x['supheli'] for x in s)/len(s):>8.4f} "
          f"{kayma(EGT, s, 85000):>+8.4f} {tb:>7.4f} "
          f"{dog(lambda x: int(puan(M, x) > 0.5), s):>7.4f} "
          f"{dog(lambda x: int(puan(M, x) > 0.5), s)-tb:>+8.4f} "
          f"{dog(onsel(s), s):>7.4f} {dog(lambda x: int(puan(MG, x) > 0.5), s):>7.4f}")
```

```
kume                n  supheli    kayma   taban   model     fark   onsel  yenidn
ayni dagilim      252   0.2421  -0.0127  0.7579  0.7778  +0.0198  0.7817  0.7698
girdi kaymasi     302   0.2748  +0.1172  0.7252  0.7318  +0.0066  0.7318  0.7384
etiket kaymasi    222   0.4865  +0.0063  0.5135  0.6306  +0.1171  0.6622  0.6261
zaman sirali      252   0.3532  -0.0056  0.6468  0.7500  +0.1032  0.7579  0.7381
```

Birinci satır ölçüyü doğruluyor. Eğitim ve sınama kümeleri aynı bölmeden geldiği için ayırt edici
model onları ayıramıyor ve kayma payı **−0,0127**; eksi işaret bir yön değil, sıfırdan ayırt
edilemeyen bir sayının koşum gürültüsüdür.

İkinci satırda kayma payı **+0,1172**: ayırt edici model bir satırın hangi kümeden geldiğini
rastgele tahminden 11,7 puan iyi kestiriyor, yani öznitelik düzeyinde gerçek bir fark var. Başarım
tarafında karşılığı şudur: model 0,7778'den 0,7318'e iniyor ve tabanın üstündeki farkı **0,0198'den
0,0066'ya** düşüyor. Kaymanın büyüklüğü ile katkının erimesi aynı satırda okunuyor.

Üçüncü ve dördüncü satırlar dersin ayrımını veriyor. Etiket kaymasında şüpheli oranı 0,2421'den
**0,4865**'e, zaman sıralı üretimde **0,3532**'ye çıkıyor — kümeler tanınmayacak kadar başka. Ama
kayma payı **+0,0063** ve **−0,0056**, yani sıfır. Girdi kaymasını ölçen gösterge, veri kümesinin
yarısının etiketi değişmiş olsa bile hiçbir şey görmüyor, çünkü baktığı tek şey özniteliklerin
dağılımıdır. **Kayma göstergesinin sessizliği, kayma olmadığı anlamına gelmez.**

#### İki Kayma İki Ayrı Çözüm İstiyor

Son iki sütun aynı tabloda iki düzeltmeyi taşıyor ve ikisi de yalnız kendi kaymasında çalışıyor.

Önsel düzeltmesi modelin yaprak oranını yeni şüphelilik oranına göre yeniden ölçekler. Etiket
kaymasında doğruluğu **0,6306'dan 0,6622'ye**, zaman sıralı üretimde **0,7500'den 0,7579'a**
çıkarıyor. Girdi kaymasında sayıyı hiç oynatmıyor: 0,7318 ve 0,7318. Sebep aritmetiktir — orada
şüpheli oranı yalnız 0,2748'e gitmiş, oranların oranı bire yakın ve hiçbir kararın işareti
dönmüyor. Bedeli de var: üretimdeki şüphelilik oranını bilmek orada etiket toplamayı gerektirir.

Yeniden eğitim ters yönde çalışıyor. Girdi kayması kuralıyla örneklenmiş 439 satırlık bir eğitim
kümesinde kurulan ağaç, girdi kaymasında **0,7318'den 0,7384'e** çıkıyor; öbür üç kümede sayıyı
**düşürüyor** (0,7698, **0,6261**, 0,7381). Eğitim kümesinin üçte biri atıldığı için model daha az
veriden öğreniyor ve bu kayıp yalnız hedeflenen kaymada telafi ediliyor.

Kural şudur: kaymanın **türü belirlenmeden** seçilen düzeltme zarar verir. Girdi kayması için
etiket toplamak, etiket kayması için veri atmak — ikisi de bu tabloda sayıyı aşağı çekiyor.

#### Alt Gruplarda Kayma Eşit Değil

Zaman sıralı üretim kümesi dördü içinde en gerçekçi olanıdır: ağ büyüdükçe sonradan katılan
aboneler kümeye giriyor. İkinci blok o kümede alt grupların payını ve şüphelilik oranını eğitim
kümesindekilerle karşılaştırır.

```python
print(f"{'alt grup':<14} | {'egitim pay':>10} {'uretim pay':>10} | {'egitim sup':>10} "
      f"{'uretim sup':>10} | {'n':>4} {'taban':>7} {'model':>7} {'fark':>8}")
ol, fr = [], []
for g in ADLAR:
    e = [x for x in EGT if g in gruplar(x)]
    u = [x for x in ZU if g in gruplar(x)]
    tb, md = dog(lambda x: CS, u), dog(lambda x: int(puan(M, x) > 0.5), u)
    if len(u) >= 25:
        ol.append(md)
        fr.append(md - tb)
    print(f"{' '.join(g):<14} | {len(e)/len(EGT):>10.4f} {len(u)/len(ZU):>10.4f} | "
          f"{sum(x['supheli'] for x in e)/len(e):>10.4f} "
          f"{sum(x['supheli'] for x in u)/len(u):>10.4f} | {len(u):>4} {tb:>7.4f} "
          f"{md:>7.4f} {md-tb:>+8.4f}{'  n<25' if len(u) < 25 else ''}")
print(f"\nuretim kumesinde aciklik ({len(ol)} alt grup): en iyi {max(ol):.4f}, en kotu "
      f"{min(ol):.4f}, aciklik {max(ol)-min(ol):.4f}; tabanin altinda "
      f"{sum(1 for v in fr if v < 0)}/{len(fr)}")
```

```
alt grup       | egitim pay uretim pay | egitim sup uretim sup |    n   taban   model     fark
bolge bati     |     0.1667     0.1429 |     0.0714     0.1389 |   36  0.8611  0.8889  +0.0278
bolge dogu     |     0.1799     0.1548 |     0.4706     0.6667 |   39  0.3333  0.7692  +0.4359
bolge guney    |     0.1865     0.2183 |     0.1064     0.2727 |   55  0.7273  0.8000  +0.0727
bolge kuzey    |     0.2897     0.2937 |     0.1963     0.2973 |   74  0.7027  0.7027  +0.0000
bolge merkez   |     0.1772     0.1905 |     0.2761     0.4375 |   48  0.5625  0.6458  +0.0833
hane 1-2       |     0.3148     0.3135 |     0.2227     0.4177 |   79  0.5823  0.6962  +0.1139
hane 3-4       |     0.5265     0.5476 |     0.2060     0.3188 |  138  0.6812  0.7754  +0.0942
hane 5+        |     0.1587     0.1389 |     0.2750     0.3429 |   35  0.6571  0.7714  +0.1143
okuma az       |     0.3373     0.3294 |     0.1725     0.2892 |   83  0.7108  0.7831  +0.0723
okuma tam      |     0.6627     0.6706 |     0.2475     0.3846 |  169  0.6154  0.7337  +0.1183
tarife 10      |     0.0384     0.0476 |     0.2069     0.4167 |   12  0.5833  0.6667  +0.0833  n<25
tarife 25      |     0.7804     0.7262 |     0.1712     0.2732 |  183  0.7268  0.7923  +0.0656
tarife 40      |     0.1812     0.2262 |     0.4453     0.5965 |   57  0.4035  0.6316  +0.2281

uretim kumesinde aciklik (12 alt grup): en iyi 0.8889, en kotu 0.6316, aciklik 0.2573; tabanin altinda 0/12
```

İlk iki sütun neredeyse durağan: en büyük değişim tarife 25 basamağında 0,7804'ten 0,7262'ye. Alt
grupların bileşimi değişmemiş, yani girdi kayması bu kümede küçüktür ve kayma payının −0,0056'sı
onunla uyuşuyor. Sonraki iki sütunda ise **her alt grubun** şüphelilik oranı yükseliyor, ama eşit
değil: doğuda 0,4706'dan 0,6667'ye, hane 1–2 grubunda 0,2227'den 0,4177'ye, tarife 25 basamağında
yalnız 0,1712'den 0,2732'ye. Etiket kayması bütünde tek bir sayı gibi görünüyor, alt gruplarda on
üç ayrı sayı.

Son satır kursun üçlüsünü tamamlıyor ve beklenmedik yöndedir. Üretim kümesinde alt grup açıklığı
**0,2573**; birinci derste aynı model için ölçülen açıklık 0,3576'ydı. Kaymış küme grupları
birbirine **yaklaştırıyor**. Daha da sert olanı, on iki alt grubun **hiçbirinde** model tabanın
altında kalmıyor; aynı model aynı ölçütle, kaymamış kümede beş alt grupta tabanın altındaydı.
Sebep tabanın kendisidir: şüphelilik oranı yükseldikçe "hiçbiri şüpheli değil" demek her alt
grupta zayıflıyor ve model onu geçiyor. Kaymış bir kümede ölçülen sayı modelin iyileştiğini değil
tabanın kötüleştiğini gösteriyor ve tabanı yanına yazmayan bir rapor bunu ayıramaz.

#### Özet

- Kayma bir sayıya iner: ayırt edici bir model satırın eğitimden mi üretimden mi geldiğini
  kestirir ve doğruluğun 0,5'ten farkı **kayma payıdır**. Girdi kaymasında +0,1172, aynı dağılımda
  −0,0127.
- Kayma payı yalnız girdiyi görür. Etiket kaymasında şüpheli oranı 0,2421'den 0,4865'e çıkarken
  gösterge +0,0063'te, zaman sıralı üretimde −0,0056'da kalıyor: **göstergenin sessizliği kayma
  olmadığı anlamına gelmez**.
- Kaymanın büyüklüğü başarım düşüşüyle yan yana okunur: girdi kaymasında modelin tabanın üstündeki
  farkı 0,0198'den **0,0066**'ya iniyor.
- İki kayma iki ayrı çözüm istiyor. Önsel düzeltmesi etiket kaymasında 0,6306'yı 0,6622'ye
  çıkarıyor, girdi kaymasında hiçbir kararı değiştirmiyor. Girdi dağılımına göre yeniden eğitim
  girdi kaymasında 0,7318'i 0,7384'e çıkarıyor, öbür üç kümede sayıyı düşürüyor.
- Zaman sıralı üretimde alt grup payları durağan ama şüphelilik oranları eşitsiz yükseliyor
  (doğuda +0,1961, tarife 25'te +0,1020). Açıklık 0,3576'dan **0,2573**'e iniyor ve model artık
  hiçbir alt grupta tabanın altında değil — çünkü düşen şey model değil tabandır.

#### Sonraki Adım

Beş derste bir sayının **ne olduğu** ve **kimin için** olduğu ölçüldü: ayırmanın birimi kime göre
seçildi, eşik hangi bedelden okundu, taban kaç türlü kurulabildi, fark hangi payla söylendi,
üretim verisi ne kadar kaydı. Her adımda aynı ağacın ürettiği sayı bir alt grupta başka bir şey
söyledi ve açıklık 0,2573 ile 0,8606 arasında yeniden ölçüldü. Bütün bunlarda model **kapalı bir
kutu** olarak kaldı. Modelin o sayıyı **neye dayanarak** ürettiği hiç sorulmadı — hangi öznitelik
kararı taşıyor, tek bir abone için verilen karar hangi değere dayanıyor ve bu gerekçe yazıya
döküldüğünde modelin gerçekten yaptığı şeyi mi anlatıyor. Sonraki konu bu üç soruyu ölçer.

## Yorumlanabilirlik

Modelin sayıyı neye dayanarak ürettiğinin okunabilir olup olmadığının ölçülmesi: bir kararla ilgili sorulabilecek sorulardan kaçının çıktıyla, kaçının bir açıklamayla cevaplandığı, modelden okunan önem sırasıyla bozarak ölçülen sıranın kaç sırada ayrıştığı ve ilişkili iki özniteliğin önemi nasıl bölüştüğü, yerel vekil modelin asıl modelin kararını kaç örnekte doğru anlattığı ve aynı örneğe iki yöntemin iki ayrı açıklama vermesi, kısmi bağımlılığın bütünde düz görünürken iki alt grupta ters yönde eğimli olması, kural listesi uzadıkça doğruluğun nereye geldiği ve hangi alt grupta en iyi aileye yaklaşılamadığı.

### Yorumlanabilirlik İhtiyacı

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/yorumlanabilirlik-ihtiyaci

Bir karar hakkında sorulabilecek on iki sorunun kaçının modelin çıktısıyla, kaçının bir açıklamayla, kaçının hiçbiriyle kapanmadığının sayılması: çıktı tek başına 4 soruyu kapatıyor, açıklama ortalamada 8,58'e çıkarıyor, üç soru hiçbir açıklamayla kapanmıyor. Kararın döndüğü tek adımlık değişim sınama kümesinin 159 abonesinde bulunuyor, batı bölgesinde otuz iki abonenin ikisinde bulunuyor; on üç alt gruba bakıldı ve eşiği geçen on ikisinde kapanan soru sayısı en iyi 8,89 ile en kötü 7,88 arasında değişiyor, açıklık 1,02 sorudur.

Önceki konu beş derste sayının **ne olduğunu** ve **kimin için** olduğunu ölçtü: bölmenin
şişirdiği pay, bedel yapısının oynattığı işletme noktası, tabanın seçimi, iki model farkının payı
ve dağılım kayması. Beşinde de ölçülen şey modelin **çıktısıydı**. Modelin o çıktıyı **neye
dayanarak** ürettiği hiç sorulmadı.

Bu soru bir tercih meselesi gibi anlatılır ve genellikle bir gereklilik listesiyle desteklenir.
Burada gereklilik listesi yazılmaz; ölçülen şey bir **işlevdir**: bir abone hakkında verilmiş
kararın gerekçesinin **belgelenebilir** olması. Belgelenebilirlik somut bir sayıya iner. Bir karar
hakkında sorulabilecek soruların bir kümesi vardır; o kümenin kaçı modelin çıktısına bakarak,
kaçı bir açıklamaya bakarak cevaplanır, kaçı hiçbirine bakarak cevaplanmaz. Bu dersin ölçüsü
budur ve alt gruplarda ayrı ayrı okunur.

- **YO1.** Küme, etiket, tohum ve bölme M27/K01–K07 boyunca kullanılan **kurgudur**: bölgesel
  ölçüm ağından türetilen abone tablosu, kaçak/arıza şüphesi etiketi, tohum 20260218, bölme
  756/252/252, sınama kümesinde taban çizgisi 0,7579.
- **YO2.** Açıklanacak model M27/K03'ün seçtiği doğrusal modeldir: on iki ölçekli sütun, öğrenme
  adımı 0,3, tur 300, sınamada 0,8016. Bu konuda model **seçilmez, verili alınır**; ölçülen şey
  modelin başarımı değil, kararının okunabilirliğidir.
- **YO3.** Alt gruplar bu konu boyunca sabittir ve M27/K08'in Değerlendirme Tasarımı konusunda
  kurulan dört ekseni izler: beş bölge, üç tarife basamağı (10, 25 ve 40 metreküp), üç hane
  büyüklüğü aralığı ve iki okuma düzeyi (üç dönemin hepsinde okuması olan abone ile daha az
  olan). **Bakılan alt grup sayısı 13'tür.**
- **YO4.** Bir alt grubun sayısı ancak sınama kümesinde en az 25 kaydı varsa okunur. Eşiğin altında
  kalan grup tabloya girer ama sayısı bir bulgu sayılmaz.
- **YO5.** Karşıt örnek **tek sütunda bir adımlık** değişimdir. Adım, sayısal sütunlarda eğitim
  kümesindeki standart sapma, iki değerli sütunda değerin dönmesi, bölgede başka bir bölgeye
  geçiştir. Bu üç adım aynı büyüklükte değildir ve karşılaştırmayı zorlaştıran şey budur.
- **YO6.** Kişi başına tüketim ortalama tüketimden ve hane büyüklüğünden türetilir; kaynağı
  oynatıldığında yeniden hesaplanır, kendisi tek başına oynatılmaz.
- **YO7.** Bir soru, cevabı modelin çıktısından ya da bir açıklamadan **mekanik olarak** okunabilir
  ise kapalı sayılır. Uzman yorumu, saha doğrulaması ya da politika kararı gerektiren soru açıktır.

#### Bir Karar Hakkında Sorulabilecek Sorular

Kurgudaki abone şüpheli olarak işaretlendiğinde onu telefonda dinleyecek kişinin, sahaya gidecek
ekibin ve kararı sonradan denetleyecek kişinin soruları aynı değildir. On iki soru bu üç kişinin
sorularının birleşimidir.

Modelin çıktısının kapattıkları dörttür: abone şüpheli işaretini aldı mı, puanı kaç ve eşiğe ne
kadar yakın, karar hangi eşikte veriliyor, aynı satır yeniden verildiğinde aynı işaret çıkıyor mu.

Bir açıklamanın kapatabildikleri beştir: puanı en çok hangi sütun itiyor, o sütun hangi yönde
itiyor, hangi tek sütunun bir adımlık değişimi işareti döndürür, aynı işareti alan öbür aboneler
de aynı sütuna mı dayanıyor, bu abonenin alt grubunda işaret oranı bütündekinden farklı mı.

Hiçbirinin kapatmadıkları üçtür: işaret doğru mu, şüphe kaçaktan mı arızadan mı geliyor, bu
işaretten sonra ne yapılmalı. Birincisi saha doğrulaması ister, ikincisi kurgunun etiketinde
zaten ayrılmamıştır, üçüncüsü bir politika kararıdır.

```python
# yorum.py — MODELDIR. M27/K01–K07'nin KURGU abone tablosu ayni tohumla uretilir;
# on iki sutunluk oznitelik kumesi ve bolme kurs boyunca sabittir.
import math
import statistics

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


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

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


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


ABONE, VERI = [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r, v = uretec(TOHUM + 7000 + k["no"]), []
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        v.append(0.0 if r() < 0.038 else math.floor(
            k["bolge"][2] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100)
        r()
    if not v:
        continue
    ort, oyn, r = sum(v) / len(v), max(v) - min(v), uretec(TOHUM + 51000 + k["no"])
    z = (0.052 * (ort - 20) + 0.85 * (min(v) == 0.0) + 0.026 * oyn
         + 0.24 * (k["hane"] >= 5) - 0.20 * (k["memnuniyet"] >= 4) + k["bolge"][3]
         + 0.9 * (k["no"] - 10001) / 1399 + (r() + r() + r() - 1.5) * 1.30)
    x = {"hane": k["hane"], "memnuniyet": k["memnuniyet"], "donem": len(v),
         "ort_tuketim": round(ort, 2), "oynaklik": round(oyn, 2),
         "sifir_okuma": int(min(v) == 0.0), "supheli": int(z > 1.35),
         "bolge": k["bolge"][0]}
    x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3)
    for b in BOLGE:
        x["b_" + b[0]] = int(k["bolge"][0] == b[0])
    VERI.append(x)


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:]
ALAN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
        "kisi_basi", "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]
TABAN = sum(x["supheli"] == 0 for x in SIN) / len(SIN)


def sikistir(z):
    if z >= 0:
        return 1.0 / (1.0 + math.exp(-z)) if z < 700 else 1.0
    e = math.exp(z) if z > -700 else 0.0
    return e / (1.0 + e)


def olcek(egt, alan):
    return ({a: statistics.fmean(x[a] for x in egt) for a in alan},
            {a: max(1e-9, statistics.pstdev([x[a] for x in egt])) for a in alan})


def egit(egt, alan, o, s, adim=0.3, tur=300):    # MODELDIR: lojistik baglanim
    X = [[1.0] + [(x[a] - o[a]) / s[a] for a in alan] for x in egt]
    Y = [x["supheli"] for x in egt]
    w = [0.0] * len(X[0])
    for _ in range(tur):
        g = [0.0] * len(w)
        for i in range(len(X)):
            h = sikistir(sum(w[j] * X[i][j] for j in range(len(w)))) - Y[i]
            for j in range(len(w)):
                g[j] += h * X[i][j]
        for j in range(len(w)):
            w[j] -= adim * g[j] / len(X)
    return w


def puan(w, alan, o, s, x):
    return sikistir(w[0] + sum(w[j + 1] * (x[a] - o[a]) / s[a]
                               for j, a in enumerate(alan)))


def karar(w, alan, o, s, x):
    return int(puan(w, alan, o, s, x) > 0.5)


O, S = olcek(EGT, ALAN)
W = egit(EGT, ALAN, O, S)
DOGRULUK = sum(karar(W, ALAN, O, S, x) == x["supheli"] for x in SIN) / len(SIN)
print(f"egitim {len(EGT)}, dogrulama {len(DOG)}, sinama {len(SIN)}")
print(f"taban cizgisi {TABAN:.4f}, dogrusal modelin sinama dogrulugu {DOGRULUK:.4f}")
```

```
egitim 756, dogrulama 252, sinama 252
taban cizgisi 0.7579, dogrusal modelin sinama dogrulugu 0.8016
```

#### Kararın Döndüğü Tek Adım

Beş açıklama sorusundan üçü her abone için kapanır, çünkü doğrusal modelin puanı sütun başına bir
terimin toplamıdır ve o terimler her zaman okunabilir. Dördüncüsü — **hangi tek sütunun bir
adımlık değişimi işareti döndürür** — kapanmayabilir. Karar sınırından yeterince uzakta duran bir
abone için tek adımlık hiçbir değişim işareti döndürmez ve o soru cevapsız kalır. Bu, açıklama
yönteminin bir eksikliği değil, o abonenin kararının **kesinliğidir**; ama sonuç aynı kapıya
çıkar: gerekçe belgesinde o satır boş kalır.

```python
def basamak(x):
    return ("tarife 10" if x["ort_tuketim"] <= 10 else
            "tarife 25" if x["ort_tuketim"] <= 25 else "tarife 40")


def hane_grup(x):
    return "hane 1-2" if x["hane"] <= 2 else ("hane 3-4" if x["hane"] <= 4
                                              else "hane 5+")


def okuma_grup(x):
    return "okuma az" if x["donem"] <= 2 else "okuma tam"


def esitse(f, deger):
    return lambda x: f(x) == deger


ALTGRUP = ([("bolge " + b[0], esitse(lambda x: x["bolge"], b[0])) for b in BOLGE]
           + [(t, esitse(basamak, t)) for t in ("tarife 10", "tarife 25", "tarife 40")]
           + [(h, esitse(hane_grup, h)) for h in ("hane 1-2", "hane 3-4", "hane 5+")]
           + [(o, esitse(okuma_grup, o)) for o in ("okuma az", "okuma tam")])
ENAZ, BOY = 25, {}
for ad, f in ALTGRUP:
    BOY[ad] = sum(1 for x in SIN if f(x))
KISA = [ad for ad in BOY if BOY[ad] < ENAZ]
print(f"alt grup sayisi {len(ALTGRUP)}, esik {ENAZ} kayit, "
      f"esigin altinda kalan {KISA}")

TEK = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
       "bolge"]


def degistir(x, a, v):
    d = dict(x)
    d[a] = v
    if a in ("ort_tuketim", "hane"):
        d["kisi_basi"] = round(d["ort_tuketim"] / d["hane"], 3)
    if a == "bolge":
        for b in BOLGE:
            d["b_" + b[0]] = int(v == b[0])
    return d


def karsit(x):                       # tek sutunda bir adimlik degisim
    k = karar(W, ALAN, O, S, x)
    for a in TEK:
        if a == "sifir_okuma":
            adaylar = [1 - x[a]]
        elif a == "bolge":
            adaylar = [b[0] for b in BOLGE if b[0] != x["bolge"]]
        else:
            adaylar = [x[a] + S[a], x[a] - S[a]]
        for v in adaylar:
            if karar(W, ALAN, O, S, degistir(x, a, v)) != k:
                return a
    return None


KARSIT = [karsit(x) for x in SIN]
ORNEK = SIN[4]
print(f"\nornek abone: bolge {ORNEK['bolge']}, hane {ORNEK['hane']}, "
      f"okuma {ORNEK['donem']}, ortalama tuketim {ORNEK['ort_tuketim']}")
print(f"  puan {puan(W, ALAN, O, S, ORNEK):.4f}, karar "
      f"{karar(W, ALAN, O, S, ORNEK)}, karsit ornek sutunu {KARSIT[4]}")
print(f"butun sinama kumesinde karsit ornegi olan abone "
      f"{sum(1 for k in KARSIT if k)}/{len(SIN)} "
      f"({sum(1 for k in KARSIT if k) / len(SIN):.4f})")
```

```
alt grup sayisi 13, esik 25 kayit, esigin altinda kalan ['tarife 10']

ornek abone: bolge merkez, hane 4, okuma 2, ortalama tuketim 34.16
  puan 0.4768, karar 0, karsit ornek sutunu ort_tuketim
butun sinama kumesinde karsit ornegi olan abone 159/252 (0.6310)
```

Örnek abonenin puanı 0,4768 ile eşiğin hemen altında ve ortalama tüketimi bir standart sapma
arttığında işaret dönüyor. Bu abone için gerekçe belgesindeki satır yazılabilir. Sınama kümesinin
252 abonesinin 159'unda böyle bir satır yazılabiliyor; kalan 93 abone için tek adımlık hiçbir
değişim işareti döndürmüyor.

#### Alt Gruplarda Kapanan Soru Sayısı

Bütünde ölçülen 0,6310 tek başına okunmaz. Aynı sayı on üç alt grupta ayrı ayrı ölçülür ve
kapanan soru sayısına çevrilir: her abone için dört soruyu çıktı, üç soruyu her zaman üretilebilen
açıklama kapatır, dördüncü açıklama sorusu karşıt örnek varsa kapanır, beşincisi abonenin bütün
alt grupları eşik boyunun üstündeyse kapanır.

```python
SABIT = 4 + 3          # cikti dort soru, her zaman kapanan uc aciklama sorusu


def kapanan(i, x):
    okunur = all(BOY[ad] >= ENAZ for ad, f in ALTGRUP if f(x))
    return SABIT + (1 if KARSIT[i] else 0) + (1 if okunur else 0)


TUM = sum(kapanan(i, x) for i, x in enumerate(SIN)) / len(SIN)
print(f"{'alt grup':<14}{'kayit':>6}{'karsit orani':>14}{'kapanan soru':>14}")
SATIR = []
for ad, f in ALTGRUP:
    g = [(i, x) for i, x in enumerate(SIN) if f(x)]
    kar = sum(1 for i, x in g if KARSIT[i]) / len(g)
    kap = sum(kapanan(i, x) for i, x in g) / len(g)
    SATIR.append((ad, kap))
    print(f"{ad:<14}{len(g):>6}{kar:>14.4f}{kap:>14.2f}")
enk = min(SATIR, key=lambda t: t[1])
eni = max(SATIR, key=lambda t: t[1])
print(f"\nbutunde kapanan soru {TUM:.2f}/12; yalniz cikti 4/12; "
      f"hicbir aciklamayla kapanmayan 3/12")
print(f"en iyi alt grup {eni[0]} {eni[1]:.2f}, en kotu alt grup {enk[0]} "
      f"{enk[1]:.2f}, aciklik {eni[1] - enk[1]:.2f} soru")
```

```
alt grup       kayit  karsit orani  kapanan soru
bolge kuzey       68        0.8235          8.82
bolge guney       58        0.3793          8.31
bolge dogu        36        0.8333          8.81
bolge bati        32        0.0625          7.88
bolge merkez      58        0.8448          8.83
tarife 10         12        0.2500          7.25
tarife 25        193        0.5907          8.59
tarife 40         47        0.8936          8.89
hane 1-2          73        0.5753          8.49
hane 3-4         143        0.6503          8.62
hane 5+           36        0.6667          8.64
okuma az          85        0.5647          8.49
okuma tam        167        0.6647          8.63

butunde kapanan soru 8.58/12; yalniz cikti 4/12; hicbir aciklamayla kapanmayan 3/12
en iyi alt grup tarife 40 8.89, en kotu alt grup tarife 10 7.25, aciklik 1.64 soru
```

Bütünde açıklama kapanan soru sayısını 4'ten 8,58'e çıkarıyor. Alt gruplarda aynı sayı, eşiği
geçen on iki grupta 7,88 ile 8,89 arasında dağılıyor ve açıklık 1,02 sorudur; eşiğin altında
kalan tarife 10 da sayılırsa alt uç 7,25'e iner. Karşıt örnek oranı ise çok daha keskin
ayrışıyor: merkez bölgesinde 0,8448, batı bölgesinde 0,0625. Batı bölgesinde otuz iki abonenin
ikisi için kararın döndüğü tek adım gösterilebiliyor. Bunun nedeni kurguda okunabilir: batının
taban tüketimi 14 metreküple beş bölgenin en düşüğüdür, dolayısıyla oradaki aboneler karar
sınırından uzakta
durur ve bir standart sapmalık hiçbir hareket onları öbür tarafa geçirmez.

Kararın değişip değişmediği burada okunur. Bütünde bakan biri "kararların gerekçesi
belgelenebiliyor" cümlesini yazar. Alt gruba bakan biri aynı cümleyi batı bölgesi için yazamaz;
oradaki abonelerin gerekçe belgesinde karşıt örnek satırı boştur. En düşük tarife basamağının
sayısı ise okunmaz bile, çünkü sınama kümesinde 12 kaydı vardır ve eşik 25'tir. Bakılan alt grup
sayısı 13, okunan 12'dir.

Üç sorunun hiçbir açıklamayla kapanmadığı da aynı tabloda durur ve bu ders bakımından en önemli
satırdır. Açıklama, kararın **nasıl** üretildiğini anlatır; kararın **doğru** olup olmadığını,
şüphenin **kaynağını** ve bundan **sonra ne yapılacağını** anlatmaz. Bu üç soruyu kapatmak için
açıklama değil saha verisi, daha ince bir etiket ve yazılı bir politika gerekir.

#### Özet

- Bir karar hakkında sorulabilecek on iki sorunun 4'ü modelin çıktısıyla, 5'i bir açıklamayla
  kapanabilir, 3'ü hiçbiriyle kapanmaz; kapanmayan üçü doğruluk, şüphenin kaynağı ve bundan sonra
  ne yapılacağıdır.
- Bütünde ortalama kapanan soru sayısı 8,58/12'dir; açıklama olmadan bu sayı 4/12'de kalır.
- Kararın döndüğü tek adımlık değişim sınama kümesinin 159 abonesinde bulunuyor, oran 0,6310.
- On üç alt gruba bakıldı, 25 kayıtlık eşiği geçen 12'si okundu; okunan gruplarda kapanan soru
  sayısı 7,88 ile 8,89 arasında değişiyor ve açıklık 1,02 sorudur.
- Karşıt örnek oranı merkez bölgesinde 0,8448, batı bölgesinde 0,0625'tir; batının taban tüketimi
  en düşük olduğu için oradaki aboneler karar sınırından uzakta durur.

#### Sonraki Adım

Bu derste beş açıklama sorusundan üçü "her zaman kapanır" diye geçildi ve gerekçesi doğrusal
modelin puanının sütun başına bir terime ayrılabilmesiydi. O terimlerin sıralaması, modelin hangi
sütuna dayandığının **küresel** cevabı olarak okunur ve M27/K02 ile K03 o sıralamayı zaten
ölçmüştü. Ama bir sıralama tek bir yolla üretilmez. Sütunu modelden okumak yerine sütunu
**bozarak** ölçmek — değerlerini birbirine karıştırıp başarımın ne kadar düştüğüne bakmak — ikinci
bir sıralama verir ve iki sıralamanın aynı çıkması için hiçbir neden yoktur. Sonraki ders iki
sıralamayı yan yana koyar, kaç sırada ayrıştıklarını sayar ve aynı niceliğin iki biçimi olan
ortalama tüketimle kişi başına tüketimin önemi nasıl bölüştüğünü ölçer.

### Öznitelik Önemi

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/oznitelik-onemi

Aynı model üzerinde iki küresel önem sıralamasının yan yana ölçülmesi: katsayılardan okunan sıra ile sütunu bozarak ölçülen sıra on iki sütunun onunda ayrışıyor ve en büyük kayma beş sıradır. Oynaklık katsayı sırasında üçüncü, bozma sırasında sekizincidir. İlişkili iki sütun önemi bölüşüyor: kişi başına tüketimin önemi tam modelde 0,0018, ortalama tüketim çıkarılıp model yeniden eğitildiğinde 0,0387'ye çıkıyor. On üç alt grupta ölçülen en önemli sütunun kayıp artışı 0,0162 ile 0,1882 arasında değişiyor ve bir alt grupta ilk sıra değişiyor.

Önceki derste beş açıklama sorusundan üçünün her abone için kapandığı söylendi ve gerekçesi
doğrusal modelin puanının sütun başına bir terime ayrılabilmesiydi. O terimlerin büyüklüğüne göre
sıralanması, modelin hangi sütuna dayandığının **küresel açıklaması** olarak okunur: tek bir
aboneye değil, modelin bütününe ait bir cevaptır.

Bu sıralamanın kendisi yeni değildir. M27/K02'nin Öznitelik Seçimi konusu önemi bir seçim ölçütü
olarak kullandı, M27/K03'ün Doğrusal Modeller konusu katsayının değerinin yanındaki sütun
kümesine bağlı olduğunu ölçtü. İkisi de burada tekrarlanmaz. Bu dersin sorusu farklıdır ve
öncekilerin cevabını girdi olarak alır: **önem tek bir yolla ölçülmez.** Sütunu modelden okumak
bir sıralama verir; sütunu **bozup** başarımın ne kadar düştüğüne bakmak ikinci bir sıralama
verir. İki sıralamanın aynı çıkması için hiçbir neden yoktur ve ne kadar ayrıştıkları ölçülebilir.

- **YO8.** Kurulum önceki dersinkidir: aynı kurgu abone tablosu, tohum 20260218, bölme
  756/252/252, taban çizgisi 0,7579, on iki sütunlu doğrusal model sınamada 0,8016. Alt gruplar
  ve 25 kayıtlık okuma eşiği aynen sürer; **bakılan alt grup sayısı 13'tür**.
- **YO9.** Modelden okunan önem, ölçekli sütunların katsayılarının mutlak değerine göre
  sıralamasıdır. Bu sıralamanın nasıl üretildiği önceki kurslarda ölçüldü; burada girdi alınır.
- **YO10.** Bozarak ölçülen önem, tek bir sütunun değerlerinin sınama kümesi içinde birbirine
  karıştırılması ve başarımdaki düşüşün ölçülmesidir. Karıştırma satır sırasını değiştirir,
  sütunun değer kümesini değiştirmez; model yeniden eğitilmez.
- **YO11.** Düşüş doğrulukta değil **ortalama kayıpta** ölçülür. 252 kayıtlık bir kümede doğruluk
  0,004'lük adımlarla değişir ve tek bir abone sıralamayı oynatabilir; kayıp sürekli bir sayıdır
  ve küçük alt gruplarda da okunabilir.
- **YO12.** Karıştırma 10 tekrarla yapılır ve ortalaması alınır; tohumlar 20260218'den türetilir.
- **YO13.** Önem sıralaması modelin **neye dayandığını** gösterir, bir nedensel etkiyi göstermez.
  Nedensel yorumun sınırı M26'nın Uygulamalı İstatistik konusunda ayrıca ölçülmüştü.

#### İki Sıralama

Kurulum önceki dersle aynıdır ve alt gruplar aynı yerde tanımlanır.

```python
# yorum.py — MODELDIR. M27/K01–K07'nin KURGU abone tablosu ayni tohumla uretilir;
# on iki sutunluk oznitelik kumesi ve bolme kurs boyunca sabittir.
import math
import statistics

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


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

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


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


ABONE, VERI = [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r, v = uretec(TOHUM + 7000 + k["no"]), []
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        v.append(0.0 if r() < 0.038 else math.floor(
            k["bolge"][2] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100)
        r()
    if not v:
        continue
    ort, oyn, r = sum(v) / len(v), max(v) - min(v), uretec(TOHUM + 51000 + k["no"])
    z = (0.052 * (ort - 20) + 0.85 * (min(v) == 0.0) + 0.026 * oyn
         + 0.24 * (k["hane"] >= 5) - 0.20 * (k["memnuniyet"] >= 4) + k["bolge"][3]
         + 0.9 * (k["no"] - 10001) / 1399 + (r() + r() + r() - 1.5) * 1.30)
    x = {"hane": k["hane"], "memnuniyet": k["memnuniyet"], "donem": len(v),
         "ort_tuketim": round(ort, 2), "oynaklik": round(oyn, 2),
         "sifir_okuma": int(min(v) == 0.0), "supheli": int(z > 1.35),
         "bolge": k["bolge"][0]}
    x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3)
    for b in BOLGE:
        x["b_" + b[0]] = int(k["bolge"][0] == b[0])
    VERI.append(x)


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:]
ALAN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
        "kisi_basi", "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]
TABAN = sum(x["supheli"] == 0 for x in SIN) / len(SIN)


def sikistir(z):
    if z >= 0:
        return 1.0 / (1.0 + math.exp(-z)) if z < 700 else 1.0
    e = math.exp(z) if z > -700 else 0.0
    return e / (1.0 + e)


def olcek(egt, alan):
    return ({a: statistics.fmean(x[a] for x in egt) for a in alan},
            {a: max(1e-9, statistics.pstdev([x[a] for x in egt])) for a in alan})


def egit(egt, alan, o, s, adim=0.3, tur=300):    # MODELDIR: lojistik baglanim
    X = [[1.0] + [(x[a] - o[a]) / s[a] for a in alan] for x in egt]
    Y = [x["supheli"] for x in egt]
    w = [0.0] * len(X[0])
    for _ in range(tur):
        g = [0.0] * len(w)
        for i in range(len(X)):
            h = sikistir(sum(w[j] * X[i][j] for j in range(len(w)))) - Y[i]
            for j in range(len(w)):
                g[j] += h * X[i][j]
        for j in range(len(w)):
            w[j] -= adim * g[j] / len(X)
    return w


def puan(w, alan, o, s, x):
    return sikistir(w[0] + sum(w[j + 1] * (x[a] - o[a]) / s[a]
                               for j, a in enumerate(alan)))


def karar(w, alan, o, s, x):
    return int(puan(w, alan, o, s, x) > 0.5)


O, S = olcek(EGT, ALAN)
W = egit(EGT, ALAN, O, S)
DOGRULUK = sum(karar(W, ALAN, O, S, x) == x["supheli"] for x in SIN) / len(SIN)
print(f"egitim {len(EGT)}, dogrulama {len(DOG)}, sinama {len(SIN)}")
print(f"taban cizgisi {TABAN:.4f}, dogrusal modelin sinama dogrulugu {DOGRULUK:.4f}")


def basamak(x):
    return ("tarife 10" if x["ort_tuketim"] <= 10 else
            "tarife 25" if x["ort_tuketim"] <= 25 else "tarife 40")


def hane_grup(x):
    return "hane 1-2" if x["hane"] <= 2 else ("hane 3-4" if x["hane"] <= 4
                                              else "hane 5+")


def okuma_grup(x):
    return "okuma az" if x["donem"] <= 2 else "okuma tam"


def esitse(f, deger):
    return lambda x: f(x) == deger


ALTGRUP = ([("bolge " + b[0], esitse(lambda x: x["bolge"], b[0])) for b in BOLGE]
           + [(t, esitse(basamak, t)) for t in ("tarife 10", "tarife 25", "tarife 40")]
           + [(h, esitse(hane_grup, h)) for h in ("hane 1-2", "hane 3-4", "hane 5+")]
           + [(o, esitse(okuma_grup, o)) for o in ("okuma az", "okuma tam")])
ENAZ = 25
BOY = {ad: sum(1 for x in SIN if f(x)) for ad, f in ALTGRUP}
print(f"alt grup sayisi {len(ALTGRUP)}, esik {ENAZ} kayit, esigin altinda "
      f"{[a for a in BOY if BOY[a] < ENAZ]}")
```

```
egitim 756, dogrulama 252, sinama 252
taban cizgisi 0.7579, dogrusal modelin sinama dogrulugu 0.8016
alt grup sayisi 13, esik 25 kayit, esigin altinda ['tarife 10']
```

Bozarak ölçülen önem tek bir işlemdir: bir sütunun değerleri sınama kümesi içinde birbirine
karıştırılır, böylece sütun kendi dağılımını korur ama satırla bağını yitirir; model o bozulmuş
kümede yeniden ölçülür ve kaybın ne kadar arttığına bakılır.

```python
def kayip(w, alan, o, s, st):     # dogruluk 252 kayitta 0,004'luk adimlarla degisiyor
    t = 0.0
    for x in st:
        p = min(max(puan(w, alan, o, s, x), 1e-9), 1 - 1e-9)
        t -= math.log(p) if x["supheli"] else math.log(1 - p)
    return t / len(st)


def bozarak(w, alan, o, s, st, bozulan, tekrar=10, tohum=TOHUM + 400000):
    k0, t = kayip(w, alan, o, s, st), 0.0
    for r in range(tekrar):
        sira = karistir(list(range(len(st))), tohum + 977 * r)
        yeni = []
        for i, x in enumerate(st):
            d = dict(x)
            for a in bozulan:
                d[a] = st[sira[i]][a]
            yeni.append(d)
        t += kayip(w, alan, o, s, yeni)
    return t / tekrar - k0


BOZ = {a: bozarak(W, ALAN, O, S, SIN, [a]) for a in ALAN}
MODELDEN = sorted(ALAN, key=lambda a: -abs(W[ALAN.index(a) + 1]))
BOZARAK = sorted(ALAN, key=lambda a: -BOZ[a])
print(f"{'sutun':<13}{'katsayi':>9}{'model sirasi':>13}{'kayip artisi':>14}"
      f"{'bozma sirasi':>14}{'kayma':>7}")
ayrisan = 0
for a in MODELDEN:
    ra, rb = MODELDEN.index(a) + 1, BOZARAK.index(a) + 1
    ayrisan += ra != rb
    print(f"{a:<13}{W[ALAN.index(a) + 1]:>+9.3f}{ra:>13}{BOZ[a]:>14.4f}"
          f"{rb:>14}{rb - ra:>+7}")
print(f"\nayrisan sira sayisi {ayrisan}/{len(ALAN)}, en buyuk kayma "
      f"{max(abs(MODELDEN.index(a) - BOZARAK.index(a)) for a in ALAN)}")
print(f"model sirasinin ilk ucu {MODELDEN[:3]}")
print(f"bozma sirasinin ilk ucu {BOZARAK[:3]}")
```

```
sutun          katsayi model sirasi  kayip artisi  bozma sirasi  kayma
ort_tuketim     +0.772            1        0.1332             1     +0
sifir_okuma     +0.684            2        0.0564             2     +0
oynaklik        +0.380            3        0.0012             8     +5
b_dogu          +0.306            4        0.0146             3     -1
memnuniyet      -0.273            5        0.0016             7     +2
hane            +0.156            6        0.0053             5     -1
donem           +0.148            7       -0.0004            10     +3
b_bati          -0.147            8        0.0054             4     -4
b_guney         -0.109            9       -0.0011            11     +2
kisi_basi       +0.071           10        0.0018             6     -4
b_merkez        -0.048           11       -0.0014            12     +1
b_kuzey         -0.005           12        0.0002             9     -3

ayrisan sira sayisi 10/12, en buyuk kayma 5
model sirasinin ilk ucu ['ort_tuketim', 'sifir_okuma', 'oynaklik']
bozma sirasinin ilk ucu ['ort_tuketim', 'sifir_okuma', 'b_dogu']
```

On iki sütunun onu iki sıralamada ayrı yerlerde duruyor. İlk iki sıra ortaktır, üçüncü sıradan
itibaren ayrışma başlıyor. En büyük kayma oynaklıkta: katsayı sırasında üçüncü, bozma sırasında
sekizinci. Katsayı 0,380 ile hatırı sayılır bir büyüklük taşıyor ama sütunu karıştırmak kaybı
yalnız 0,0012 arttırıyor. İki sayı çelişmiyor, iki ayrı şey söylüyor. Katsayı, **öbür sütunlar
sabit tutulduğunda** oynaklığın bir standart sapmalık artışının puana ne kattığını söyler. Bozma
ise oynaklığın taşıdığı bilginin **başka sütunlarda da bulunup bulunmadığını** ölçer: oynaklık
ortalama tüketimle birlikte hareket ettiği için karıştırıldığında model açığı kapatıyor.

Üç sütunun kayıp artışı eksi işaretli. Bir sütunu bozmak kaybı düşürmüşse o sütun modele
zarar veriyor demektir; büyüklükleri 0,0014 ve altında olduğu için burada okunacak şey işaretin
kendisi değil, üç sütunun **sıfır civarında** durmasıdır.

#### İlişkili İki Sütun Önemi Nasıl Bölüşüyor

Ortalama tüketim ile kişi başına tüketim aynı niceliğin iki biçimidir; ikincisi birincinin hane
büyüklüğüne bölünmesiyle üretilir. Bozma sırasında biri birinci, öbürü altıncıdır.

```python
IKI = ["ort_tuketim", "kisi_basi"]
birlikte = bozarak(W, ALAN, O, S, SIN, IKI)
print(f"tek tek {BOZ[IKI[0]]:.4f} ve {BOZ[IKI[1]]:.4f}, toplam "
      f"{BOZ[IKI[0]] + BOZ[IKI[1]]:.4f}, birlikte {birlikte:.4f}")
for cik in IKI:
    kalan = [a for a in ALAN if a != cik]
    o2, s2 = olcek(EGT, kalan)
    w2 = egit(EGT, kalan, o2, s2)
    dg = sum(karar(w2, kalan, o2, s2, x) == x["supheli"] for x in SIN) / len(SIN)
    obur = IKI[1] if cik == IKI[0] else IKI[0]
    print(f"{cik} cikarildi: sinama {dg:.4f}, {obur} onemi "
          f"{bozarak(w2, kalan, o2, s2, SIN, [obur]):.4f}")
```

```
tek tek 0.1332 ve 0.0018, toplam 0.1350, birlikte 0.1437
ort_tuketim cikarildi: sinama 0.7778, kisi_basi onemi 0.0387
kisi_basi cikarildi: sinama 0.8016, ort_tuketim onemi 0.1441
```

Kişi başına tüketimin önemi tam modelde 0,0018'dir ve bu sayıya bakan biri sütunun boşuna
durduğu sonucuna varır. Ortalama tüketim modelden çıkarılıp model yeniden eğitildiğinde aynı
sütunun önemi 0,0387'ye, yani yirmi bir katına çıkıyor. Sütun değişmedi; **model değişti**. Önem
bir sütunun özelliği değil, bir sütunun **belirli bir modeldeki** özelliğidir.

İkisini birlikte bozmak 0,1437 veriyor; tek tek bozmaların toplamı 0,1350. Fark 0,0087, ikisinin
**artıklı biçimde** taşıdığı paydır: her biri tek başına karıştırıldığında öbürü açığı kapattığı
için o pay hiçbir tekil ölçüde görünmez. Bir önem sıralaması, ilişkili sütunlar arasında bir payı
her zaman kaybeder.

#### Alt Gruplarda En Önemli Sütun

Bütün sıralama bir kümenin sıralamasıdır ve o küme alt gruplardan oluşur.

```python
print(f"{'alt grup':<14}{'kayit':>6}{'en onemli sutun':>16}{'kayip artisi':>14}"
      f"{'ikinci sutun':>14}")
OKUNAN = []
for ad, f in ALTGRUP:
    g = [x for x in SIN if f(x)]
    d = {a: bozarak(W, ALAN, O, S, g, [a]) for a in ALAN}
    sira = sorted(ALAN, key=lambda a: -d[a])
    if BOY[ad] >= ENAZ:
        OKUNAN.append((ad, sira[0], d[sira[0]]))
    print(f"{ad:<14}{len(g):>6}{sira[0]:>16}{d[sira[0]]:>14.4f}{sira[1]:>14}")
eni, enk = max(OKUNAN, key=lambda t: t[2]), min(OKUNAN, key=lambda t: t[2])
print(f"\nokunan alt grup {len(OKUNAN)}/{len(ALTGRUP)}; ilk sirada "
      f"{BOZARAK[0]} disinda bir sutun bulunan alt grup "
      f"{sum(1 for t in OKUNAN if t[1] != BOZARAK[0])}")
print(f"en yuksek {eni[0]} {eni[2]:.4f}, en dusuk {enk[0]} {enk[2]:.4f}, "
      f"aciklik {eni[2] - enk[2]:.4f}")
```

```
alt grup       kayit en onemli sutun  kayip artisi  ikinci sutun
bolge kuzey       68     ort_tuketim        0.0719   sifir_okuma
bolge guney       58     sifir_okuma        0.1882   ort_tuketim
bolge dogu        36     ort_tuketim        0.1753    memnuniyet
bolge bati        32     ort_tuketim        0.0162   sifir_okuma
bolge merkez      58     ort_tuketim        0.1879   sifir_okuma
tarife 10         12     sifir_okuma        0.1288        b_bati
tarife 25        193     ort_tuketim        0.0408   sifir_okuma
tarife 40         47     ort_tuketim        0.1033      oynaklik
hane 1-2          73     ort_tuketim        0.1339   sifir_okuma
hane 3-4         143     ort_tuketim        0.1215   sifir_okuma
hane 5+           36     ort_tuketim        0.1513   sifir_okuma
okuma az          85     ort_tuketim        0.1213   sifir_okuma
okuma tam        167     ort_tuketim        0.1181   sifir_okuma

okunan alt grup 12/13; ilk sirada ort_tuketim disinda bir sutun bulunan alt grup 1
en yuksek bolge guney 0.1882, en dusuk bolge bati 0.0162, aciklik 0.1720
```

On üç alt gruba bakıldı, eşiği geçen 12'si okundu. Okunan on iki alt grubun on birinde ilk sıra
ortalama tüketim; güney bölgesinde ilk sıra sıfır okuma göstergesine geçiyor ve kayıp artışı
0,1882 ile bütündeki 0,1332'nin üstünde. Bütünde yazılan "model en çok ortalama tüketime
dayanıyor" cümlesi güney bölgesinin abonelerine sorulduğunda yanlıştır.

Açıklık daha da keskin: en önemli sütunun kayıp artışı güney bölgesinde 0,1882, batı
bölgesinde 0,0162 — aralarında on bir katlık bir fark var. Batı bölgesinde hiçbir sütunu bozmak
kaybı kayda değer ölçüde arttırmıyor, çünkü oradaki aboneler karar sınırından uzakta duruyor ve
puanları sütun oynamalarına karşı duyarsız. Önceki dersin karşıt örnek sayısı da aynı bölgede
çökmüştü; iki ayrı ölçü aynı olguyu iki ayrı yerden gösteriyor.

#### Özet

- Aynı model için katsayılardan okunan sıra ile bozarak ölçülen sıra on iki sütunun onunda
  ayrışıyor; en büyük kayma beş sıradır ve oynaklıktadır.
- Katsayı öbür sütunlar sabitken bir sütunun kattığını, bozma ise o sütunun bilgisinin başka
  sütunlarda bulunup bulunmadığını ölçer; oynaklığın katsayısı 0,380 iken kayıp artışı 0,0012'dir.
- Önem sütunun değil, sütunun belirli bir modeldeki durumunun özelliğidir: kişi başına tüketimin
  önemi 0,0018'den, ortalama tüketim çıkarılıp model yeniden eğitildiğinde 0,0387'ye çıkıyor.
- İlişkili iki sütunu birlikte bozmak 0,1437, tek tek bozmaların toplamı 0,1350 veriyor; aradaki
  0,0087 hiçbir tekil ölçüde görünmeyen artıklı paydır.
- On üç alt gruba bakıldı, 12'si okundu: on birinde ilk sıra ortalama tüketim, güney bölgesinde
  sıfır okuma göstergesi; en önemli sütunun kayıp artışı 0,0162 ile 0,1882 arasında ve açıklık
  0,1720'dir.

#### Sonraki Adım

İki sıralama da modelin bütününe aittir. Kurgudaki abone kendisine şüpheli işareti geldiğinde
modelin genel olarak neye dayandığını değil, **kendi** kararının neye dayandığını sorar ve
küresel sıralama o soruya cevap vermez: güney bölgesinde ilk sıranın değişmesi tam olarak bunu
gösterdi. Sonraki ders tek bir tahmini açıklayan yöntemlere geçer. Asıl modelin bir örneğin
çevresindeki davranışını taklit eden küçük bir vekil model kurulur, çıktı öznitelikler arasında
paylaştırılarak katkı payları hesaplanır ve iki yöntem aynı aboneye sorulur. Ölçülecek şey
açıklamanın **sadakatidir**: vekil model asıl modelin kararını kaç örnekte doğru anlatıyor ve
aynı abone için iki yöntem kaç kez iki ayrı açıklama veriyor.

### Yerel Açıklama Yöntemleri

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/yerel-aciklama-yontemleri

Tek bir tahmini açıklayan iki yöntemin aynı abonelere sorulması ve açıklamanın sadakatinin ölçülmesi: yerel vekil model komşuluktaki kararların ortalama 0,9417'sini doğru veriyor, ama 252 abonenin 41'inde komşuluk tek etiket taşıdığı için açıklama boş çıkıyor. Vekil modelle katkı payı dağıtımı 211 dolu açıklamanın 145'inde ayrı sütun gösteriyor. Sadakat batı bölgesinde 0,9664 ile en yüksek, orada boş açıklama oranı 0,4688; en düşük sadakat 0,9027 ile en üst tarife basamağındadır ve açıklık 0,0637'dir.

Önceki dersin iki sıralaması da modelin bütününe aitti. Kurgudaki abone şüpheli işaretini
aldığında modelin genel olarak neye dayandığını değil, **kendi** kararının neye dayandığını sorar.
Güney bölgesinde küresel sıralamanın ilk sırasının değişmesi, bütünün cevabının tek bir abone için
doğru olmayabileceğini göstermişti.

Yerel açıklama bu soruya iki ayrı yapıyla cevap verir. Birincisi, asıl modelin bir örneğin
**çevresindeki** davranışını taklit eden küçük bir model kurar; ikincisi, çıktıyı öznitelikler
arasında **paylaştırır**. İkisi de bir sütun adı üretir; bu ders o iki adın ne kadar sık aynı
olduğunu ve açıklamanın asıl modeli gerçekten anlatıp anlatmadığını sayar.

- **YO14.** Kurulum önceki iki dersinkidir: aynı kurgu abone tablosu, tohum 20260218, bölme
  756/252/252, taban çizgisi 0,7579, doğrusal model sınamada 0,8016. **Bakılan alt grup sayısı
  13**, okuma eşiği 25 kayıt.
- **YO15.** Yerel vekil model, açıklanan abonenin çevresinde üretilmiş 40 komşuya oturtulan **tek
  bölmeli** küçük bir modeldir. Komşular sayısal sütunların bir standart sapmalık aralığında
  oynatılmasıyla, iki değerli sütunun ve bölgenin 0,2 olasılıkla değişmesiyle üretilir; etiketleri
  gerçek etiket değil **asıl modelin kararıdır**.
- **YO16.** Açıklamanın sadakati, vekil modelin komşuluktaki kararların kaçını doğru verdiğidir.
  Komşuluğun tamamı tek etiket taşıyorsa vekil model sabittir: sadakati 1 olur, açıklaması **boştur**.
- **YO17.** Katkı payı dağıtımı, taban kayıttan başlayıp abonenin sütunlarını rastgele bir sırayla
  tek tek yerine koyar, her adımda puandaki değişimi kaydeder ve 24 sıra üzerinden ortalar. Taban
  kayıt eğitim kümesinin ortalamasıdır, bölgesi beş göstergenin eğitim ortalamasıdır.
- **YO18.** Tek özniteliği bozma, katkı payının tek sıralı biçimidir: yalnız bir sütun taban
  değerine çekilir. İki yöntem karşılaştırılırken her birinin verdiği **ilk sütun** karşılaştırılır.

#### İki Yöntem, Aynı Abone

Kurulum önceki derslerinkiyle aynıdır.

```python
# yorum.py — MODELDIR. M27/K01–K07'nin KURGU abone tablosu ayni tohumla uretilir;
# on iki sutunluk oznitelik kumesi ve bolme kurs boyunca sabittir.
import math
import statistics

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


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

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


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


ABONE, VERI = [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r, v = uretec(TOHUM + 7000 + k["no"]), []
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        v.append(0.0 if r() < 0.038 else math.floor(
            k["bolge"][2] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100)
        r()
    if not v:
        continue
    ort, oyn, r = sum(v) / len(v), max(v) - min(v), uretec(TOHUM + 51000 + k["no"])
    z = (0.052 * (ort - 20) + 0.85 * (min(v) == 0.0) + 0.026 * oyn
         + 0.24 * (k["hane"] >= 5) - 0.20 * (k["memnuniyet"] >= 4) + k["bolge"][3]
         + 0.9 * (k["no"] - 10001) / 1399 + (r() + r() + r() - 1.5) * 1.30)
    x = {"hane": k["hane"], "memnuniyet": k["memnuniyet"], "donem": len(v),
         "ort_tuketim": round(ort, 2), "oynaklik": round(oyn, 2),
         "sifir_okuma": int(min(v) == 0.0), "supheli": int(z > 1.35),
         "bolge": k["bolge"][0]}
    x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3)
    for b in BOLGE:
        x["b_" + b[0]] = int(k["bolge"][0] == b[0])
    VERI.append(x)


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:]
ALAN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
        "kisi_basi", "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]
TABAN = sum(x["supheli"] == 0 for x in SIN) / len(SIN)


def sikistir(z):
    if z >= 0:
        return 1.0 / (1.0 + math.exp(-z)) if z < 700 else 1.0
    e = math.exp(z) if z > -700 else 0.0
    return e / (1.0 + e)


def olcek(egt, alan):
    return ({a: statistics.fmean(x[a] for x in egt) for a in alan},
            {a: max(1e-9, statistics.pstdev([x[a] for x in egt])) for a in alan})


def egit(egt, alan, o, s, adim=0.3, tur=300):    # MODELDIR: lojistik baglanim
    X = [[1.0] + [(x[a] - o[a]) / s[a] for a in alan] for x in egt]
    Y = [x["supheli"] for x in egt]
    w = [0.0] * len(X[0])
    for _ in range(tur):
        g = [0.0] * len(w)
        for i in range(len(X)):
            h = sikistir(sum(w[j] * X[i][j] for j in range(len(w)))) - Y[i]
            for j in range(len(w)):
                g[j] += h * X[i][j]
        for j in range(len(w)):
            w[j] -= adim * g[j] / len(X)
    return w


def puan(w, alan, o, s, x):
    return sikistir(w[0] + sum(w[j + 1] * (x[a] - o[a]) / s[a]
                               for j, a in enumerate(alan)))


def karar(w, alan, o, s, x):
    return int(puan(w, alan, o, s, x) > 0.5)


O, S = olcek(EGT, ALAN)
W = egit(EGT, ALAN, O, S)
DOGRULUK = sum(karar(W, ALAN, O, S, x) == x["supheli"] for x in SIN) / len(SIN)
print(f"egitim {len(EGT)}, dogrulama {len(DOG)}, sinama {len(SIN)}, taban "
      f"cizgisi {TABAN:.4f}, dogrusal modelin sinama dogrulugu {DOGRULUK:.4f}")


def basamak(x):
    return ("tarife 10" if x["ort_tuketim"] <= 10 else
            "tarife 25" if x["ort_tuketim"] <= 25 else "tarife 40")


def hane_grup(x):
    return "hane 1-2" if x["hane"] <= 2 else ("hane 3-4" if x["hane"] <= 4
                                              else "hane 5+")


def okuma_grup(x):
    return "okuma az" if x["donem"] <= 2 else "okuma tam"


def esitse(f, deger):
    return lambda x: f(x) == deger


ALTGRUP = ([("bolge " + b[0], esitse(lambda x: x["bolge"], b[0])) for b in BOLGE]
           + [(t, esitse(basamak, t)) for t in ("tarife 10", "tarife 25", "tarife 40")]
           + [(h, esitse(hane_grup, h)) for h in ("hane 1-2", "hane 3-4", "hane 5+")]
           + [(o, esitse(okuma_grup, o)) for o in ("okuma az", "okuma tam")])
ENAZ = 25
BOY = {ad: sum(1 for x in SIN if f(x)) for ad, f in ALTGRUP}
print(f"alt grup sayisi {len(ALTGRUP)}, esik {ENAZ} kayit, esigin altinda "
      f"{[a for a in BOY if BOY[a] < ENAZ]}")
```

```
egitim 756, dogrulama 252, sinama 252, taban cizgisi 0.7579, dogrusal modelin sinama dogrulugu 0.8016
alt grup sayisi 13, esik 25 kayit, esigin altinda ['tarife 10']
```

İki yöntem art arda kurulur ve her abone için birer sütun adı üretir.

```python
YEREL = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
         "bolge"]
TABAN_K = {a: statistics.fmean(x[a] for x in EGT) for a in
           ("ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem",
            "sifir_okuma")}
TABAN_K["bolge"] = None          # taban kayitta bolge tek bir bolge degil, ortalama
B_ORT = {"b_" + b[0]: statistics.fmean(x["b_" + b[0]] for x in EGT) for b in BOLGE}


def duzelt(d):                   # turetilmis sutunlari yeniden hesaplar
    d["kisi_basi"] = round(d["ort_tuketim"] / max(1, d["hane"]), 3)
    if d["bolge"] is None:
        d.update(B_ORT)
    else:
        for b in BOLGE:
            d["b_" + b[0]] = int(d["bolge"] == b[0])
    return d


TABAN_KAYIT = duzelt(dict(SIN[0], **TABAN_K))


def komsuluk(x, sayi=40, tohum=TOHUM + 600000):
    r, c = uretec(tohum + int(x["ort_tuketim"] * 100) + x["hane"]), []
    for _ in range(sayi):
        d = dict(x)
        for a in ("ort_tuketim", "oynaklik", "memnuniyet", "donem"):
            d[a] = x[a] + (2 * r() - 1) * S[a]
        d["hane"] = max(1, round(x["hane"] + (2 * r() - 1) * S["hane"]))
        if r() < 0.2:
            d["sifir_okuma"] = 1 - x["sifir_okuma"]
        if r() < 0.2:
            d["bolge"] = BOLGE[int(r() * 5)][0]
        c.append(duzelt(d))
    return c


def vekil(x):                    # MODELDIR: tek bolmeli karar agaci, yerel vekil
    c = komsuluk(x)
    y = [karar(W, ALAN, O, S, k) for k in c]
    if len(set(y)) == 1:
        return None, 1.0         # komsulugun tamami tek etiket: aciklama bos
    en = (0.0, None)
    for a in YEREL:
        d = sorted({k[a] for k in c})
        aday = d[1:] if a in ("sifir_okuma", "bolge") else \
            [d[int(i * len(d) / 8)] for i in range(1, 8)]
        for v in aday:
            sol = {i for i in range(len(c))
                   if (c[i][a] != v if a == "bolge" else c[i][a] < v)}
            if not sol or len(sol) == len(c):
                continue
            ps = sum(y[i] for i in sol) * 2 > len(sol)
            pg = sum(y[i] for i in range(len(c)) if i not in sol) * 2 > len(c) - len(sol)
            u = sum((ps if i in sol else pg) == y[i] for i in range(len(c))) / len(c)
            if u > en[0]:
                en = (u, a)
    return en[1], en[0]


def katki(x, tur=24, tohum=TOHUM + 700000):
    r = uretec(tohum + int(x["ort_tuketim"] * 100) + x["hane"])
    pay = {a: 0.0 for a in YEREL}
    for _ in range(tur):
        sira = list(YEREL)
        for i in range(len(sira) - 1, 0, -1):
            j = int(r() * (i + 1))
            sira[i], sira[j] = sira[j], sira[i]
        d, onceki = dict(TABAN_KAYIT), puan(W, ALAN, O, S, TABAN_KAYIT)
        for a in sira:
            d[a] = x[a]
            yeni = puan(W, ALAN, O, S, duzelt(d))
            pay[a] += yeni - onceki
            onceki = yeni
    return {a: pay[a] / tur for a in YEREL}


def tek_bozma(x):                # tek ozniteligi bozma: bir sutun tabana cekilir
    p0 = puan(W, ALAN, O, S, x)
    return {a: p0 - puan(W, ALAN, O, S, duzelt(dict(x, **{a: TABAN_K[a]})))
            for a in YEREL}


SADAKAT, VSUT, KSUT, TSUT = [], [], [], []
for x in SIN:
    a, u = vekil(x)
    p, t = katki(x), tek_bozma(x)
    SADAKAT.append(u)
    VSUT.append(a)
    KSUT.append(max(YEREL, key=lambda k: abs(p[k])))
    TSUT.append(max(YEREL, key=lambda k: abs(t[k])))
DOLU = [i for i in range(len(SIN)) if VSUT[i]]
AYRI = [i for i in DOLU if VSUT[i] != KSUT[i]]
print(f"ortalama sadakat {sum(SADAKAT) / len(SADAKAT):.4f}; komsulugunda tek "
      f"etiket bulunan, yani bos aciklama alan abone {len(SIN) - len(DOLU)}")
print(f"dolu aciklama {len(DOLU)}, bunlarda ortalama sadakat "
      f"{sum(SADAKAT[i] for i in DOLU) / len(DOLU):.4f}")
print(f"vekil model ile katki payinin ayni sutunu vermedigi abone "
      f"{len(AYRI)}/{len(DOLU)} ({len(AYRI) / len(DOLU):.4f})")
print(f"katki payi ile tek bozmanin ayristigi abone "
      f"{sum(1 for i in range(len(SIN)) if KSUT[i] != TSUT[i])}/{len(SIN)}")
i = min(AYRI, key=lambda i: abs(puan(W, ALAN, O, S, SIN[i]) - 0.5))
x, p = SIN[i], katki(SIN[i])
print(f"\nornek abone: bolge {x['bolge']}, ortalama tuketim {x['ort_tuketim']}, "
      f"sifir okuma {x['sifir_okuma']}, puan {puan(W, ALAN, O, S, x):.4f}")
print(f"  vekil modelin bolme sutunu {VSUT[i]}, sadakat {SADAKAT[i]:.4f}")
print("  katki paylari " + ", ".join(f"{a} {p[a]:+.4f}" for a in
                                     sorted(YEREL, key=lambda a: -abs(p[a]))[:3]))
```

```
ortalama sadakat 0.9417; komsulugunda tek etiket bulunan, yani bos aciklama alan abone 41
dolu aciklama 211, bunlarda ortalama sadakat 0.9303
vekil model ile katki payinin ayni sutunu vermedigi abone 145/211 (0.6872)
katki payi ile tek bozmanin ayristigi abone 27/252

ornek abone: bolge dogu, ortalama tuketim 24.67, sifir okuma 0, puan 0.4885
  vekil modelin bolme sutunu ort_tuketim, sadakat 0.7750
  katki paylari bolge +0.1631, ort_tuketim +0.1335, oynaklik +0.0428
```

Örnek abone iki açıklama alıyor ve ikisi başka şey söylüyor. Vekil model, o abonenin çevresinde
kararı ayıran şeyin ortalama tüketim olduğunu söylüyor ve komşuluktaki kararların 0,7750'sini
doğru veriyor. Katkı payı dağıtımı, aboneyi taban kayıttan bu puana taşıyan en büyük payın bölge
olduğunu söylüyor: doğu bölgesinde olmak puana 0,1631 katmış. İkisi de doğrudur ve iki ayrı soruya
cevap verir: birincisi "buradan çıkış hangi sütundan olur", ikincisi "buraya hangi sütun getirdi".
211 dolu açıklamanın 145'inde aynı sütunu vermiyorlar. Katkı payının tek sıralı biçimi olan tek
özniteliği bozma ise 27 abonede ondan ayrışıyor: bir sütunun kattığı şey ondan önce hangi
sütunların yerine konduğuna bağlıdır.

#### Sadakat Tek Başına Okunmaz

Ortalama sadakat 0,9417 ile yüksek görünüyor. Bu sayının içinde komşuluğu tek etiket taşıyan 41
abone var: vekil model sabittir, sadakati tanım gereği 1'dir ve söylediği hiçbir şey yoktur. Boş
açıklamalar dışarıda bırakıldığında sadakat 0,9303'e iniyor.

```python
print(f"{'alt grup':<14}{'kayit':>6}{'sadakat':>9}{'bos aciklama':>14}{'ayrisma':>9}")
OKUNAN = []
for ad, f in ALTGRUP:
    g = [i for i, x in enumerate(SIN) if f(x)]
    sd = sum(SADAKAT[i] for i in g) / len(g)
    bos = sum(1 for i in g if VSUT[i] is None) / len(g)
    d = [i for i in g if VSUT[i]]
    ay = sum(1 for i in d if VSUT[i] != KSUT[i]) / len(d)
    if BOY[ad] >= ENAZ:
        OKUNAN.append((ad, sd, ay))
    print(f"{ad:<14}{len(g):>6}{sd:>9.4f}{bos:>14.4f}{ay:>9.4f}")
eni, enk = max(OKUNAN, key=lambda t: t[1]), min(OKUNAN, key=lambda t: t[1])
ea = max(OKUNAN, key=lambda t: t[2])
print(f"\nokunan alt grup {len(OKUNAN)}/{len(ALTGRUP)}")
print(f"sadakat en yuksek {eni[0]} {eni[1]:.4f}, en dusuk {enk[0]} {enk[1]:.4f}, "
      f"aciklik {eni[1] - enk[1]:.4f}")
print(f"ayrisma en yuksek {ea[0]} {ea[2]:.4f}, en dusuk "
      f"{min(OKUNAN, key=lambda t: t[2])[0]} {min(t[2] for t in OKUNAN):.4f}")
```

```
alt grup       kayit  sadakat  bos aciklama  ayrisma
bolge kuzey       68   0.9401        0.0441   0.7231
bolge guney       58   0.9586        0.2414   0.7273
bolge dogu        36   0.9028        0.1389   0.7097
bolge bati        32   0.9664        0.4688   0.4118
bolge merkez      58   0.9371        0.0690   0.6852
tarife 10         12   0.9688        0.5833   1.0000
tarife 25        193   0.9495        0.1503   0.7012
tarife 40         47   0.9027        0.1064   0.5952
hane 1-2          73   0.9538        0.2603   0.6852
hane 3-4         143   0.9320        0.1329   0.7097
hane 5+           36   0.9556        0.0833   0.6061
okuma az          85   0.9456        0.2353   0.8154
okuma tam        167   0.9397        0.1257   0.6301

okunan alt grup 12/13
sadakat en yuksek bolge bati 0.9664, en dusuk tarife 40 0.9027, aciklik 0.0637
ayrisma en yuksek okuma az 0.8154, en dusuk bolge bati 0.4118
```

On üç alt gruba bakıldı, 12'si okundu. Sadakatin en yüksek olduğu alt grup batı bölgesidir,
0,9664; aynı satırda boş açıklama oranı 0,4688, yani otuz iki abonenin on beşi hiçbir şey
söylemeyen bir açıklama alıyor. Sadakati yalnız başına raporlayan biri batıyı en iyi açıklanan
grup diye yazar; iki sütun yan yana konduğunda o cümle tersine döner. **Sadakat, açıklamanın bir
şey söylediğini varsayar; söylemediğinde de yüksek çıkar.**

En düşük sadakat 0,9027 ile en üst tarife basamağındadır ve açıklık 0,0637'dir. Yüksek tüketimli
aboneler karar sınırının yakınında yoğunlaştığı için komşulukları iki etiket taşır ve tek bir bölme
yetmez; aynı grup açıklamaların en dolu olduğu gruptur. İki yöntemin ayrışması ise alt gruplarda
0,4118 ile 0,8154 arasında değişiyor.

#### Özet

- Yerel vekil model komşuluktaki kararların ortalama 0,9417'sini doğru veriyor; boş açıklamalar
  dışarıda bırakıldığında 0,9303'e iniyor.
- 252 abonenin 41'inde komşuluk tek etiket taşıyor: vekil model sabittir, sadakati 1'dir ve
  açıklaması boştur. Sadakat bu yüzden tek başına okunmaz.
- Vekil model ile katkı payı dağıtımı 211 dolu açıklamanın 145'inde ayrı sütun gösteriyor; ikisi
  "buradan çıkış hangi sütundan olur" ve "buraya hangi sütun getirdi" sorularına cevap verir.
- On üç alt gruba bakıldı, 12'si okundu: sadakat 0,9027 ile 0,9664 arasında, açıklık 0,0637;
  en yüksek sadakatli grupta boş açıklama oranı 0,4688'dir.

#### Sonraki Adım

Bu derste açıklamalar tek tek abonelere aitti. Bir sütunun modele **bütün olarak** ne yaptığını
görmenin başka bir yolu vardır: sütunun değeri bir uçtan öbür uca gezdirilirken öbür sütunlar
kümenin kendi değerlerinde bırakılır ve ortalama puanın nasıl değiştiğine bakılır. Bu kısmi
bağımlılıktır ve genellikle eğri olarak çizilir. Burada çizilmez, sayı basılır; sayı basıldığında
ortalamanın ne gizlediği görünür olur. Sonraki ders bütünde düz görünen bir kısmi bağımlılığın iki
alt grupta ters yönde eğimli olabildiğini kaç sütunda gerçekleştiğiyle sayar.

### Kısmi Bağımlılık ve Etkileşim

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/kismi-bagimlilik-ve-etkilesim

Bir sütunun modele bütün olarak ne yaptığının sayı olarak basılması ve ortalamanın ne gizlediğinin sayılması: karar ağacında beş sütunun üçü bütünde düz görünüyor, bunların ikisinde alt gruplar ters yönde eğimli. Hane büyüklüğünün kısmi bağımlılığı bütünde -0,0069 ile düzdür, üçüncü tarife basamağında +0,1301, doğu bölgesinde -0,1891 ve açıklık 0,3192'dir. Memnuniyette açıklık 0,2189'dur. Okuma sayısı hem bütünde hem on iki alt grupta tam olarak 0,0000 eğimlidir: düz görünen her sayı bir etkileşim gizlemiyor.

Önceki iki ders açıklamayı ya modelin bütününe ya da tek bir aboneye bağladı. Aradaki soru
sorulmadı: bir sütunun değeri bir uçtan öbür uca gezdirilirken modelin çıktısı **ortalamada**
nasıl davranıyor. Bu, kısmi bağımlılıktır ve tek bir sütunun modeldeki etkisini bir eğri olarak
özetler. Burada eğri çizilmez, ızgara noktalarındaki sayılar basılır — çünkü bu dersin sorusu tam
olarak o ortalamanın içinde kaybolan şeyle ilgilidir.

Kısmi bağımlılık bir ortalamadır ve her ortalama gibi ters yönlü iki hareketi birbirine
götürebilir. Bir sütun bir alt grupta puanı yukarı, başka bir alt grupta aşağı itiyorsa bütündeki
eğri **düz** çıkar ve sütunun modelde hiçbir rolü yokmuş gibi görünür. Bu dersin ölçüsü budur:
bütünde düz görünen kaç sütunda alt gruplar ters yönde eğimli.

- **YO19.** Kurulum önceki derslerinkidir: aynı kurgu abone tablosu, tohum 20260218, bölme
  756/252/252, sınama kümesinde taban çizgisi 0,7579. Alt gruplar ve 25 kayıtlık okuma eşiği
  sürer; **bakılan alt grup sayısı 13'tür**.
- **YO20.** Bu ders açıklanan modeli değiştirir. Doğrusal model sütunları birbiriyle çarpmaz,
  dolayısıyla bir sütunun kısmi bağımlılığı her alt grupta aynı işareti taşır ve bu dersin sorusu
  orada sorulamaz. Açıklanan model M27/K03'ün karar ağacı ailesidir; burada budanmamış derinlik 6
  ağacı kullanılır ve sınamada 0,7897 verir. Ailenin M27/K03'te budamayla ulaştığı sayı 0,7857'dir.
- **YO21.** Kısmi bağımlılık şöyle hesaplanır: bir sütun ızgaradaki değere çekilir, öbür sütunlar
  kümenin kendi değerlerinde bırakılır, puanların ortalaması alınır. Izgara eğitim kümesindeki
  farklı değerlerin en fazla beş noktasıdır; farklı değeri beşten az olan sütunda nokta sayısı o
  kadardır.
- **YO22.** Türetilmiş kişi başına tüketim her ızgara noktasında kaynağıyla birlikte yeniden
  hesaplanır.
- **YO23.** Eğim, ızgaranın son noktasındaki kısmi bağımlılıktan ilk noktasındakinin
  çıkarılmasıdır. Bütünde mutlak eğimi 0,05'in altında olan sütun **düz** sayılır; bir alt grupta
  mutlak eğimi 0,02'yi geçen sütun **eğimli** sayılır. İki eşik de puan ölçeğindedir ve puan 0 ile
  1 arasında değişir.
- **YO24.** Grafik çizilmez; kısmi bağımlılık ızgara noktalarındaki sayılarla basılır.

#### Kısmi Bağımlılık Sayı Olarak

Kurulum önceki derslerinkiyle aynıdır.

```python
# yorum.py — MODELDIR. M27/K01–K07'nin KURGU abone tablosu ayni tohumla uretilir;
# on iki sutunluk oznitelik kumesi ve bolme kurs boyunca sabittir.
import math
import statistics

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


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

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


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


ABONE, VERI = [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r, v = uretec(TOHUM + 7000 + k["no"]), []
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        v.append(0.0 if r() < 0.038 else math.floor(
            k["bolge"][2] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100)
        r()
    if not v:
        continue
    ort, oyn, r = sum(v) / len(v), max(v) - min(v), uretec(TOHUM + 51000 + k["no"])
    z = (0.052 * (ort - 20) + 0.85 * (min(v) == 0.0) + 0.026 * oyn
         + 0.24 * (k["hane"] >= 5) - 0.20 * (k["memnuniyet"] >= 4) + k["bolge"][3]
         + 0.9 * (k["no"] - 10001) / 1399 + (r() + r() + r() - 1.5) * 1.30)
    x = {"hane": k["hane"], "memnuniyet": k["memnuniyet"], "donem": len(v),
         "ort_tuketim": round(ort, 2), "oynaklik": round(oyn, 2),
         "sifir_okuma": int(min(v) == 0.0), "supheli": int(z > 1.35),
         "bolge": k["bolge"][0]}
    x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3)
    for b in BOLGE:
        x["b_" + b[0]] = int(k["bolge"][0] == b[0])
    VERI.append(x)


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:]
ALAN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
        "kisi_basi", "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]
TABAN = sum(x["supheli"] == 0 for x in SIN) / len(SIN)


def basamak(x):
    return ("tarife 10" if x["ort_tuketim"] <= 10 else
            "tarife 25" if x["ort_tuketim"] <= 25 else "tarife 40")


def hane_grup(x):
    return "hane 1-2" if x["hane"] <= 2 else ("hane 3-4" if x["hane"] <= 4
                                              else "hane 5+")


def okuma_grup(x):
    return "okuma az" if x["donem"] <= 2 else "okuma tam"


def esitse(f, deger):
    return lambda x: f(x) == deger


ALTGRUP = ([("bolge " + b[0], esitse(lambda x: x["bolge"], b[0])) for b in BOLGE]
           + [(t, esitse(basamak, t)) for t in ("tarife 10", "tarife 25", "tarife 40")]
           + [(h, esitse(hane_grup, h)) for h in ("hane 1-2", "hane 3-4", "hane 5+")]
           + [(o, esitse(okuma_grup, o)) for o in ("okuma az", "okuma tam")])
ENAZ = 25
BOY = {ad: sum(1 for x in SIN if f(x)) for ad, f in ALTGRUP}
print(f"egitim {len(EGT)}, dogrulama {len(DOG)}, sinama {len(SIN)}; alt grup "
      f"sayisi {len(ALTGRUP)}, esigin altinda {[a for a in BOY if BOY[a] < ENAZ]}")
```

```
egitim 756, dogrulama 252, sinama 252; alt grup sayisi 13, esigin altinda ['tarife 10']
```

Ağaç M27/K03'teki biçimiyle kurulur ve kısmi bağımlılık beş sütun için ızgara noktalarında
basılır.

```python
def oran(s):
    return sum(x["supheli"] for x in s) / len(s) if s else 0.0


def safliksizlik(s):
    p = oran(s)
    return 2 * p * (1 - p)


def en_iyi_bolme(s, enaz=2):
    en = None
    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 = safliksizlik(s) - (len(sol) * safliksizlik(sol)
                                   + len(sag) * safliksizlik(sag)) / len(s)
            if en is None or k > en[0]:
                en = (k, a, v, sol, sag)
    return en


def agac(s, derinlik, enaz=2):        # MODELDIR: karar agaci, M27/K03'un ailesi
    p = oran(s)
    en = (en_iyi_bolme(s, enaz) if derinlik and len(s) >= 2 * enaz
          and 0.0 < p < 1.0 else None)
    if en is None or en[0] <= 1e-9:
        return {"oran": p}
    return {"alan": en[1], "esik": en[2], "sol": agac(en[3], derinlik - 1, enaz),
            "sag": agac(en[4], derinlik - 1, enaz)}


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


AGAC = agac(EGT, 6)
AD = sum((agac_puan(AGAC, x) > 0.5) == x["supheli"] for x in SIN) / len(SIN)
print(f"taban cizgisi {TABAN:.4f}, karar agacinin sinama dogrulugu {AD:.4f}")

IZGARA_SUTUN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem"]


def izgara(a, nokta=5):
    d = sorted({x[a] for x in EGT})
    k = min(nokta, len(d))
    return [d[int(i * (len(d) - 1) / (k - 1))] for i in range(k)]


def kismi(st, a, gr):                 # kismi bagimlilik: sayi olarak, cizilmez
    p = []
    for v in gr:
        t = 0.0
        for x in st:
            d = dict(x)
            d[a] = v
            d["kisi_basi"] = round(d["ort_tuketim"] / max(1, d["hane"]), 3)
            t += agac_puan(AGAC, d)
        p.append(t / len(st))
    return p


DUZ, EGIM = 0.05, {}
IZG = {a: izgara(a) for a in IZGARA_SUTUN}
for a in IZGARA_SUTUN:
    p = kismi(SIN, a, IZG[a])
    EGIM[a] = p[-1] - p[0]
    print(f"{a:<13}" + "  ".join(f"{v:g}:{q:.4f}" for v, q in zip(IZG[a], p))
          + f"   egim {EGIM[a]:+.4f}")
YASSI = [a for a in IZGARA_SUTUN if abs(EGIM[a]) < DUZ]
print(f"\nbutunde duz gorunen sutun ({DUZ} esigiyle) {YASSI}")
```

```
taban cizgisi 0.7579, karar agacinin sinama dogrulugu 0.7897
ort_tuketim  0:0.0848  15.23:0.1380  19.51:0.2234  23.81:0.2250  42.9:0.3838   egim +0.2990
oynaklik     0:0.1374  5.52:0.1374  9.89:0.1945  15.64:0.3158  40.57:0.7731   egim +0.6357
hane         1:0.2546  2:0.2510  3:0.2274  4:0.2165  6:0.2477   egim -0.0069
memnuniyet   1:0.2926  2:0.2588  3:0.2315  4:0.2354  5:0.2460   egim -0.0466
donem        1:0.2491  2:0.2491  3:0.2491   egim +0.0000

butunde duz gorunen sutun (0.05 esigiyle) ['hane', 'memnuniyet', 'donem']
```

Ortalama tüketim ve oynaklık okunması kolay iki satır: ızgara boyunca puan tek yönde artıyor,
eğimler +0,2990 ve +0,6357. Kalan üç sütun düz. Hane büyüklüğünün eğimi -0,0069, yani puanın
binde yedisi; memnuniyetinki -0,0466; okuma sayısınınki tam olarak sıfır.

Bu üç satıra bakan biri şu cümleyi yazar: model kararını hane büyüklüğüne, memnuniyete ve okuma
sayısına dayandırmıyor. Cümle üç sütun için de aynı gerekçeyle yazılıyor ama üçünde de aynı şeyi
anlatmıyor ve hangisinde neyi anlattığı bütünden okunamaz.

Hesabın kendisi de bir varsayım taşır ve varsayım burada açıkça yazılmalıdır. Bir sütun ızgara
noktasına çekilirken öbür sütunlar oldukları yerde bırakılıyor; yani sütunların birbirinden
bağımsız oynatılabildiği varsayılıyor. Hane büyüklüğü 6'ya çekilen bir abonenin ortalama tüketimi
değişmiyor, oysa kurguda ikisi birlikte hareket eder. Önceki dersin bozarak ölçülen önemi de aynı
varsayıma dayanıyordu ve orada ilişkili iki sütunun önemi bölüşmüştü. Kısmi bağımlılık, kümede hiç
görülmemiş bileşimler üzerinde de puan hesaplar; ızgara uçlarındaki sayılar bu yüzden ortadaki
sayılardan daha az güvenilirdir.

#### Ortalamanın Gizlediği Etkileşim

Aynı hesap on iki okunabilir alt grupta ayrı ayrı yapılır.

```python
ESIK = 0.02
E = {a: {} for a in YASSI}
for ad, f in ALTGRUP:
    if BOY[ad] < ENAZ:
        continue
    g = [x for x in SIN if f(x)]
    for a in YASSI:
        p = kismi(g, a, IZG[a])
        E[a][ad] = p[-1] - p[0]
KISA = [(ad.replace("bolge ", "").replace("tarife ", "t").replace("hane ", "h")
         .replace("okuma ", "ok "), ad) for ad in E[YASSI[0]]]
print("alt grup " + "".join(f"{a:>13}" for a in YASSI))
print("butun    " + "".join(f"{EGIM[a]:>+13.4f}" for a in YASSI))
for kisa, ad in KISA:
    print(f"{kisa:<9}" + "".join(f"{E[a][ad]:>+13.4f}" for a in YASSI))
KIRIK = [a for a in YASSI if max(E[a].values()) > ESIK and min(E[a].values()) < -ESIK]
print(f"\nokunan alt grup {len(E[YASSI[0]])}/{len(ALTGRUP)}, egim esigi {ESIK}")
print(f"butunde duz gorunen sutun {len(YASSI)}, bunlardan alt gruplarda ters "
      f"yonde egimli olan {len(KIRIK)}")
for a in KIRIK:
    y = max(E[a], key=lambda k: E[a][k])
    d = min(E[a], key=lambda k: E[a][k])
    print(f"  {a}: en yuksek {y} {E[a][y]:+.4f}, en dusuk {d} {E[a][d]:+.4f}, "
          f"aciklik {E[a][y] - E[a][d]:.4f}")
```

```
alt grup          hane   memnuniyet        donem
butun          -0.0069      -0.0466      +0.0000
kuzey          +0.0916      -0.1146      +0.0000
guney          -0.0477      -0.0108      +0.0000
dogu           -0.1891      +0.0278      +0.0000
bati           -0.0442      -0.0313      +0.0000
merkez         +0.0522      -0.0573      +0.0000
t25            -0.0264      -0.0143      +0.0000
t40            +0.1301      -0.1911      +0.0000
h1-2           -0.0354      -0.0665      +0.0000
h3-4           +0.0049      -0.0533      +0.0000
h5+            +0.0040      +0.0205      +0.0000
ok az          +0.0155      -0.0359      +0.0000
ok tam         -0.0183      -0.0520      +0.0000

okunan alt grup 12/13, egim esigi 0.02
butunde duz gorunen sutun 3, bunlardan alt gruplarda ters yonde egimli olan 2
  hane: en yuksek tarife 40 +0.1301, en dusuk bolge dogu -0.1891, aciklik 0.3192
  memnuniyet: en yuksek bolge dogu +0.0278, en dusuk tarife 40 -0.1911, aciklik 0.2189
```

Hane büyüklüğü bütünde -0,0069 ile düzdür. En üst tarife basamağında +0,1301, doğu bölgesinde
-0,1891; açıklık 0,3192, yani bütündeki eğimin kırk altı katı. Yüksek tüketimli abonelerde hane
büyüdükçe şüphe artıyor, doğu bölgesinde hane büyüdükçe azalıyor. İki hareket bütünde birbirini
götürüyor ve geriye binde yedilik bir sayı kalıyor. **Bütünde okunan düzlük bir yokluk değil, bir
toplamdır.**

Memnuniyette aynı şey daha küçük ölçekte oluyor: bütünde -0,0466, en üst tarife basamağında
-0,1911, doğu bölgesinde +0,0278, açıklık 0,2189. İki sütunun da en uç değerleri **aynı iki alt
grupta** ve ters sırada duruyor; bu, ağacın bu iki sütunu birbirinden bağımsız değil, tüketim
düzeyi ve bölgeyle birlikte kullandığı anlamına gelir. Etkileşim tam olarak budur.

Okuma sayısı üçüncü tür bir düzlüktür ve bu dersin kontrolüdür. Hem bütünde hem on iki alt grubun
hepsinde eğim tam olarak 0,0000: ağaç bu sütuna hiç bölme koymamış. Düz görünen her sayının altında
bir etkileşim yoktur; bazen sütun gerçekten kullanılmamıştır. İki durumu ayırmanın yolu bütüne
bakmak değil, alt gruplara bakmaktır — ve bakılmadığında ikisi aynı satır olarak okunur.

Kararın değişip değişmediği burada da okunur. Bütüne bakan biri üç sütunu birden modelden
çıkarmayı önerir. Alt gruplara bakan biri bunu yalnız okuma sayısı için önerir; öbür ikisi
kullanılıyor, yalnız **kimin için ne yönde** kullanıldığı bütünde görünmüyor.

#### Özet

- Kısmi bağımlılık bir sütunu ızgara boyunca gezdirip puanların ortalamasını alır; burada eğri
  çizilmedi, ızgara noktalarındaki sayılar basıldı.
- Hesap sütunların bağımsız oynatılabildiğini varsayar ve kümede hiç görülmemiş bileşimler üretir;
  ızgara uçlarındaki sayılar ortadakilerden daha az güvenilirdir.
- Beş sütunun ikisi bütünde açıkça eğimli (+0,2990 ve +0,6357), üçü düz görünüyor.
- Bütünde düz görünen üç sütunun ikisinde alt gruplar ters yönde eğimli: hane büyüklüğünde açıklık
  0,3192, memnuniyette 0,2189.
- Hane büyüklüğünün eğimi bütünde -0,0069 iken üçüncü tarife basamağında +0,1301, doğu bölgesinde
  -0,1891'dir; bütündeki düzlük bir yokluk değil, ters yönlü iki hareketin toplamıdır.
- Okuma sayısı hem bütünde hem on iki alt grupta tam olarak 0,0000 eğimlidir: düz görünen her sayı
  bir etkileşim gizlemez, bazen sütun gerçekten kullanılmamıştır.

#### Sonraki Adım

Dört derste açıklama hep **modelin dışından** üretildi: kurulmuş bir modelin kararı sonradan
okundu, bozuldu, taklit edildi ve ortalandı. Her seferinde açıklamanın kendisi bir yaklaşımdı ve
sadakati ayrıca ölçülmek zorunda kaldı. Başka bir yol vardır: modeli baştan okunabilir kurmak.
Kararı birkaç kuralın sırayla uygulanmasıyla veren bir model, açıklamayı ayrıca üretmez — modelin
kendisi açıklamadır ve sadakati tanım gereği tamdır. Sonraki ders bu yolun bedelini ölçer: kaç
kuralda M27/K03'ün en iyi ailesinin sayısına yaklaşılıyor ve hangi alt grupta hiç yaklaşılamıyor.

### Doğası Gereği Yorumlanabilir Modeller

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/dogasi-geregi-yorumlanabilir-modeller

Açıklamayı sonradan üretmek yerine modeli baştan okunabilir kurmanın bedelinin ölçülmesi: iki kurallık, dört koşullu bir sıralı liste sınamada 0,7897 veriyor, otuz üç sütunlu en iyi ailenin 0,8056'sına 0,0159 yani dört abone kalıyor. Listeyi üç ve dört kurala uzatmak yaklaştırmıyor, 0,7857'ye geri düşürüyor. On üç alt gruba bakıldı, okunan on ikisinin altısında en iyi aileye 0,02 içinde yaklaşılamıyor; en uzağı merkez bölgesidir, 0,7414 yerine 0,6552 ve fark 0,0862. Üç alt grupta kural listesi en iyi aileyi geçiyor.

Dört derste açıklama hep modelin dışından üretildi: kurulmuş bir modelin kararı sonradan okundu,
bozuldu, taklit edildi ve ortalandı. Her seferinde açıklama bir yaklaşımdı ve sadakati ayrıca
ölçülmek zorunda kaldı.

Başka bir yol vardır: modeli baştan okunabilir kurmak. Kararı birkaç kuralın sırayla
uygulanmasıyla veren bir model açıklamayı ayrıca üretmez — modelin kendisi açıklamadır ve
sadakati tanım gereği tamdır. Bu dersin sorusu o yolun bedelidir. M27/K03'ün Doğrusal Modeller
konusu bedeli bir kez ölçmüştü: on iki katsayılı model ile otuz üç sütunlu en iyi aile arasında
0,0040, yani tek abone. O sayı burada tekrarlanmaz, **girdi alınır** — çünkü kural listesi on iki
katsayıdan çok daha okunabilirdir ve bedelin okunabilirlikle nasıl büyüdüğü asıl sorudur.

- **YO25.** Kurulum önceki derslerinkidir: aynı kurgu abone tablosu, tohum 20260218, bölme
  756/252/252, sınama kümesinde taban çizgisi 0,7579. Alt gruplar ve 25 kayıtlık okuma eşiği
  sürer; **bakılan alt grup sayısı 13'tür**.
- **YO26.** Karşılaştırma çizgileri M27/K03'ten gelir ve aynı tohumla yeniden hesaplanır: on iki
  sütunlu doğrusal model 0,8016, en iyi aile (otuz üç sütunlu, karesel cezalı) 0,8056. Karar ağacı
  ailesinin sayısı aynı kurstan 0,7857'dir.
- **YO27.** Kural listesi sıralı bir modeldir: ilk uyan kural kararı verir, hiçbiri uymazsa son
  etiket verilir. Her kural en fazla iki koşul taşır ve iki koşul aynı sütundan olamaz.
- **YO28.** Liste açgözlü kurulur: her adımda, kalan kayıtların varsayılan etiketine göre en çok
  doğru kazandıran kural eklenir ve kapsadığı kayıtlar çıkarılır. En az kapsam 12 kayıttır ve
  koşul eşikleri eğitim kümesinin ondalıklarından alınır.
- **YO29.** "En iyi aileye yaklaşmak", sınama doğruluğu farkının 0,02'yi geçmemesidir; 0,02 bu
  sınama kümesinde beş abonedir.

#### Üç Karşılaştırma Çizgisi

Kurulum önceki derslerinkidir; üstüne M27/K03'ün en iyi ailesi aynı tohumla yeniden kurulur.

```python
# yorum.py — MODELDIR. M27/K01–K07'nin KURGU abone tablosu ayni tohumla uretilir;
# on iki sutunluk oznitelik kumesi ve bolme kurs boyunca sabittir.
import itertools
import math
import statistics

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


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

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


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


ABONE, VERI = [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r, v = uretec(TOHUM + 7000 + k["no"]), []
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        v.append(0.0 if r() < 0.038 else math.floor(
            k["bolge"][2] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100)
        r()
    if not v:
        continue
    ort, oyn, r = sum(v) / len(v), max(v) - min(v), uretec(TOHUM + 51000 + k["no"])
    z = (0.052 * (ort - 20) + 0.85 * (min(v) == 0.0) + 0.026 * oyn
         + 0.24 * (k["hane"] >= 5) - 0.20 * (k["memnuniyet"] >= 4) + k["bolge"][3]
         + 0.9 * (k["no"] - 10001) / 1399 + (r() + r() + r() - 1.5) * 1.30)
    x = {"hane": k["hane"], "memnuniyet": k["memnuniyet"], "donem": len(v),
         "ort_tuketim": round(ort, 2), "oynaklik": round(oyn, 2),
         "sifir_okuma": int(min(v) == 0.0), "supheli": int(z > 1.35),
         "bolge": k["bolge"][0]}
    x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3)
    for b in BOLGE:
        x["b_" + b[0]] = int(k["bolge"][0] == b[0])
    VERI.append(x)


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:]
ALAN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
        "kisi_basi", "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]
TABAN = sum(x["supheli"] == 0 for x in SIN) / len(SIN)


def sikistir(z):
    if z >= 0:
        return 1.0 / (1.0 + math.exp(-z)) if z < 700 else 1.0
    e = math.exp(z) if z > -700 else 0.0
    return e / (1.0 + e)


def olcek(egt, alan):
    return ({a: statistics.fmean(x[a] for x in egt) for a in alan},
            {a: max(1e-9, statistics.pstdev([x[a] for x in egt])) for a in alan})


def egit(egt, alan, o, s, adim=0.3, tur=300, ceza=0.0):   # MODELDIR: lojistik baglanim
    X = [[1.0] + [(x[a] - o[a]) / s[a] for a in alan] for x in egt]
    Y = [x["supheli"] for x in egt]
    w = [0.0] * len(X[0])
    for _ in range(tur):
        g = [0.0] * len(w)
        for i in range(len(X)):
            h = sikistir(sum(w[j] * X[i][j] for j in range(len(w)))) - Y[i]
            for j in range(len(w)):
                g[j] += h * X[i][j]
        for j in range(len(w)):
            w[j] -= adim * (g[j] / len(X) + (ceza * w[j] if j else 0.0))
    return w


def puan(w, alan, o, s, x):
    return sikistir(w[0] + sum(w[j + 1] * (x[a] - o[a]) / s[a]
                               for j, a in enumerate(alan)))


def karar(w, alan, o, s, x):
    return int(puan(w, alan, o, s, x) > 0.5)


O, S = olcek(EGT, ALAN)
W = egit(EGT, ALAN, O, S)
print(f"egitim {len(EGT)}, dogrulama {len(DOG)}, sinama {len(SIN)}")


def basamak(x):
    return ("tarife 10" if x["ort_tuketim"] <= 10 else
            "tarife 25" if x["ort_tuketim"] <= 25 else "tarife 40")


def hane_grup(x):
    return "hane 1-2" if x["hane"] <= 2 else ("hane 3-4" if x["hane"] <= 4
                                              else "hane 5+")


def okuma_grup(x):
    return "okuma az" if x["donem"] <= 2 else "okuma tam"


def esitse(f, deger):
    return lambda x: f(x) == deger


ALTGRUP = ([("bolge " + b[0], esitse(lambda x: x["bolge"], b[0])) for b in BOLGE]
           + [(t, esitse(basamak, t)) for t in ("tarife 10", "tarife 25", "tarife 40")]
           + [(h, esitse(hane_grup, h)) for h in ("hane 1-2", "hane 3-4", "hane 5+")]
           + [(o, esitse(okuma_grup, o)) for o in ("okuma az", "okuma tam")])
ENAZ = 25
BOY = {ad: sum(1 for x in SIN if f(x)) for ad, f in ALTGRUP}
print(f"alt grup sayisi {len(ALTGRUP)}, esik {ENAZ} kayit, esigin altinda "
      f"{[a for a in BOY if BOY[a] < ENAZ]}")
CARPIM = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "kisi_basi"]


def genislet(x):
    d = dict(x)
    for a, b in itertools.combinations(CARPIM, 2):
        d[a + "*" + b] = x[a] * x[b]
    for a in CARPIM:
        d[a + "^2"] = x[a] * x[a]
    return d


GENIS = (ALAN + [a + "*" + b for a, b in itertools.combinations(CARPIM, 2)]
         + [a + "^2" for a in CARPIM])
GE, GS = [genislet(x) for x in EGT], [genislet(x) for x in SIN]
OG, SG = olcek(GE, GENIS)
WG = egit(GE, GENIS, OG, SG, ceza=0.05)          # M27/K03'un en iyi ailesi
EN_IYI = sum(karar(WG, GENIS, OG, SG, x) == x["supheli"] for x in GS) / len(GS)
DM = sum(karar(W, ALAN, O, S, x) == x["supheli"] for x in SIN) / len(SIN)
print(f"taban cizgisi {TABAN:.4f}, on iki sutunlu dogrusal model {DM:.4f}, "
      f"en iyi aile ({len(GENIS)} sutun) {EN_IYI:.4f}")
```

```
egitim 756, dogrulama 252, sinama 252
alt grup sayisi 13, esik 25 kayit, esigin altinda ['tarife 10']
taban cizgisi 0.7579, on iki sutunlu dogrusal model 0.8016, en iyi aile (33 sutun) 0.8056
```

#### Kural Listesi Uzadıkça

Liste açgözlü kurulur ve uzunluk birden altıya süpürülür.

```python
KURAL_SUTUN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem",
               "sifir_okuma", "bolge"]


def uyar(k, x):
    a, yon, e = k
    return x[a] == e if yon == "=" else (x[a] < e if yon == "<" else x[a] >= e)


def kosullar(kume):
    for a in KURAL_SUTUN:
        d = sorted({x[a] for x in kume})
        if a == "bolge":
            for v in d:
                yield (a, "=", v)
        else:
            for v in (d if len(d) < 10 else
                      [d[int(i * len(d) / 10)] for i in range(1, 10)]):
                yield (a, "<", v)
                yield (a, ">=", v)


def kazanc(g, v0, enaz):                 # varsayilana gore kazanilan dogru sayisi
    if len(g) < enaz:
        return None
    poz = sum(x["supheli"] for x in g)
    etiket = int(poz * 2 > len(g))
    return ((poz if etiket else len(g) - poz)
            - (poz if v0 else len(g) - poz), etiket)


def kural_listesi(egt, uzunluk, enaz=12, tohum=8):   # MODELDIR: sirali kural listesi
    kalan, liste = list(egt), []
    for _ in range(uzunluk):
        v0 = int(sum(x["supheli"] for x in kalan) * 2 > len(kalan))
        aday = []
        for k1 in kosullar(kalan):
            g1 = [x for x in kalan if uyar(k1, x)]
            z = kazanc(g1, v0, enaz)
            if z:
                p = sum(x["supheli"] for x in g1) / len(g1)
                aday.append((p if v0 == 0 else 1 - p, z[0], k1, g1, z[1]))
        if not aday:
            break
        aday.sort(key=lambda t: -t[0])
        en = max(((t[1], [t[2]], t[4]) for t in aday[:tohum]), key=lambda t: t[0])
        for _, _, k1, g1, _ in aday[:tohum]:
            for k2 in kosullar(g1):
                if k2[0] == k1[0]:
                    continue
                z = kazanc([x for x in g1 if uyar(k2, x)], v0, enaz)
                if z and z[0] > en[0]:
                    en = (z[0], [k1, k2], z[1])
        if en[0] <= 0:
            break
        liste.append((en[1], en[2]))
        kalan = [x for x in kalan if not all(uyar(k, x) for k in en[1])]
        if not kalan:
            break
    p = sum(x["supheli"] for x in kalan)
    return liste, (int(p * 2 > len(kalan)) if kalan else 0)


def kural_tahmin(liste, son, x):
    for kosul, etiket in liste:
        if all(uyar(k, x) for k in kosul):
            return etiket
    return son


def yaz(kosul):
    return " ve ".join(f"{a} {y} {e}" for a, y, e in kosul)


YAKIN = 0.02                      # sinama kumesinde bes abone
print(f"{'kural':>6}{'kosul':>7}{'sinama':>9}{'en iyi aileye fark':>20}")
SWEEP = []
for n in range(1, 7):
    liste, son = kural_listesi(EGT, n)
    d = sum(kural_tahmin(liste, son, x) == x["supheli"] for x in SIN) / len(SIN)
    k = sum(len(c) for c, e in liste)
    SWEEP.append((d, -len(liste), liste, son, k))
    print(f"{len(liste):>6}{k:>7}{d:>9.4f}{EN_IYI - d:>+20.4f}")
SECIM = max(SWEEP, key=lambda t: (t[0], t[1]))
print(f"\nen iyi aileye en cok yaklasan liste {-SECIM[1]} kural, {SECIM[4]} kosul, "
      f"sinama {SECIM[0]:.4f}, fark {EN_IYI - SECIM[0]:+.4f} "
      f"({round((EN_IYI - SECIM[0]) * len(SIN))} abone)")
for kosul, etiket in SECIM[2]:
    print(f"  eger {yaz(kosul)} ise {etiket}")
print(f"  yoksa {SECIM[3]}")
```

```
 kural  kosul   sinama  en iyi aileye fark
     1      2   0.7857             +0.0198
     2      4   0.7897             +0.0159
     3      6   0.7857             +0.0198
     4      8   0.7857             +0.0198
     4      8   0.7857             +0.0198
     4      8   0.7857             +0.0198

en iyi aileye en cok yaklasan liste 2 kural, 4 kosul, sinama 0.7897, fark +0.0159 (4 abone)
  eger bolge = dogu ve oynaklik >= 11.86 ise 1
  eger sifir_okuma >= 1 ve oynaklik >= 20.06 ise 1
  yoksa 0
```

Tek kural iki koşulla 0,7857 veriyor; bu, M27/K03'te budanmış karar ağacı ailesinin sayısıdır.
İkinci kural sayıyı 0,7897'ye çıkarıyor ve en iyi aileye 0,0159, yani dört abone kalıyor. Üçüncü
ve dördüncü kurallar yaklaştırmıyor, 0,7857'ye geri düşürüyor; beşinci adımda açgözlü yordam
kazanç bulamayıp duruyor. **Uzunluk ile doğruluk arasında tek yönlü bir ilişki yok.**

Bedelin büyüklüğü asıl okunacak yerdedir. M27/K03 on iki katsayı için farkı 0,0040, yani tek abone
ölçmüştü; dört koşula inildiğinde aynı fark dört aboneye çıkıyor. Okunabilirlik sürekli bir
eksendir ve bedeli o eksende büyür; hangi noktanın seçileceği bir ölçüm değil bir karardır, ama
karar ancak iki ucun sayısı yazıldığında verilebilir.

Listenin kendisi üç satırda okunuyor ve her satır bir cümledir. Bu modelin açıklamasının sadakati
tanım gereği 1'dir, çünkü açıklama modelin kendisidir; üçüncü dersin 41 boş açıklaması burada
oluşmaz.

#### Hangi Alt Grupta Yaklaşılamıyor

Bütünde ölçülen 0,0159 tek başına okunmaz. Aynı iki model on üç alt grupta yan yana konur.

```python
LISTE, SON = SECIM[2], SECIM[3]
print(f"{'alt grup':<14}{'kayit':>6}{'kural listesi':>15}{'en iyi aile':>13}"
      f"{'fark':>9}")
UZAK, OKUNAN = [], 0
for ad, f in ALTGRUP:
    g = [x for x in SIN if f(x)]
    kl = sum(kural_tahmin(LISTE, SON, x) == x["supheli"] for x in g) / len(g)
    ei = sum(karar(WG, GENIS, OG, SG, genislet(x)) == x["supheli"]
             for x in g) / len(g)
    if BOY[ad] >= ENAZ:
        OKUNAN += 1
        if ei - kl > YAKIN:
            UZAK.append((ad, kl, ei))
    print(f"{ad:<14}{len(g):>6}{kl:>15.4f}{ei:>13.4f}{ei - kl:>+9.4f}")
UZAK.sort(key=lambda t: t[1] - t[2])
print(f"\nokunan alt grup {OKUNAN}/{len(ALTGRUP)}; en iyi aileye {YAKIN} icinde "
      f"yaklasamayan alt grup {len(UZAK)}, en uzagi {UZAK[0][0]} "
      f"({UZAK[0][1]:.4f} yerine {UZAK[0][2]:.4f}, fark {UZAK[0][2] - UZAK[0][1]:+.4f})")
```

```
alt grup       kayit  kural listesi  en iyi aile     fark
bolge kuzey       68         0.8088       0.7794  -0.0294
bolge guney       58         0.8621       0.8448  -0.0172
bolge dogu        36         0.6667       0.7222  +0.0556
bolge bati        32         1.0000       1.0000  +0.0000
bolge merkez      58         0.6552       0.7414  +0.0862
tarife 10         12         0.6667       0.6667  +0.0000
tarife 25        193         0.8290       0.8342  +0.0052
tarife 40         47         0.6596       0.7234  +0.0638
hane 1-2          73         0.7945       0.8356  +0.0411
hane 3-4         143         0.8042       0.7972  -0.0070
hane 5+           36         0.7222       0.7778  +0.0556
okuma az          85         0.7529       0.7765  +0.0235
okuma tam        167         0.8084       0.8204  +0.0120

okunan alt grup 12/13; en iyi aileye 0.02 icinde yaklasamayan alt grup 6, en uzagi bolge merkez (0.6552 yerine 0.7414, fark +0.0862)
```

Bütünde dört abone olan fark alt gruplarda dağılıyor. On üç alt gruba bakıldı, eşiği geçen 12'si
okundu ve bunların altısında en iyi aileye 0,02 içinde yaklaşılamıyor. En uzağı merkez bölgesidir:
0,6552'ye karşı 0,7414, fark 0,0862 — bütündeki farkın beş katından fazlası. En üst tarife
basamağında fark 0,0638, doğu bölgesinde ve büyük hanelerde 0,0556.

Nedeni listenin kendisinden okunuyor. İki kuralın biri doğu bölgesine, öbürü sıfır okumasına
bağlı; merkez bölgesinin şüpheli aboneleri ikisine de girmiyor ve hepsi son satırın varsayılan
etiketini alıyor. **Kısalık bütün için ödenir, faturası bazı alt gruplara çıkar.**

Ters yön de aynı tabloda duruyor. Üç alt grupta kural listesi en iyi aileyi geçiyor: kuzeyde
0,0294, güneyde 0,0172, orta hane büyüklüğünde 0,0070. Bütündeki tek sayı, hangi modelin kimin
için daha iyi olduğunu söylemiyor.

#### Özet

- İki kurallık, dört koşullu sıralı liste sınamada 0,7897 veriyor; en iyi ailenin 0,8056'sına
  0,0159, yani dört abone kalıyor.
- Listeyi uzatmak yaklaştırmıyor: üç ve dört kural 0,7857'ye düşürüyor ve liste dördüncü kuraldan
  sonra doyuyor. Tek kural 0,7857 ile karar ağacı ailesinin sayısını veriyor.
- Okunabilirliğin bedeli o eksende büyüyor: M27/K03'te on iki katsayı için bir abone, burada dört
  koşul için dört abone.
- Kural listesinin sadakati tanım gereği 1'dir; üçüncü dersin 41 boş açıklaması burada oluşmaz.
- On üç alt gruba bakıldı, 12'si okundu: altısında en iyi aileye 0,02 içinde yaklaşılamıyor, en
  uzağı merkez bölgesinde 0,0862; üç alt grupta ise kural listesi en iyi aileyi geçiyor.

#### Sonraki Adım

On derste bir sayının ne olduğu, kimin için olduğu ve neye dayandığı ölçüldü: bölmenin şişirdiği
pay, bedel yapısının oynattığı işletme noktası, tabanın seçimi, farkın payı, dağılım kayması,
açıklamanın kapattığı soru sayısı, iki önem sıralamasının ayrışması, açıklamanın sadakati,
ortalamanın gizlediği etkileşim ve kural listesinin bedeli. Hepsinde ölçülen şey **doğruluk ya da
okunabilirlikti**.

Hiçbiri bir **zarar** ölçüsü değildi. Merkez bölgesindeki 0,0862'lik fark, oradaki abonelerin
şüpheli işaretini daha sık yanlış aldığı anlamına gelir; kimin ne kadar yanlış işaret aldığı ve o
işaretin ona ne yaptığı on derste hiç sorulmadı. Sonraki konu bu soruyla açılır: yanlışlık kümenin
neresinden geliyor, adil olmanın kaç ayrı tanımı var ve bu tanımlar aynı anda sağlanabiliyor mu
ve modelin öğrendiği şey tek tek kayıtlar hakkında ne sızdırıyor.

## Etik ve Sorumluluk

Ölçüsü iyi çıkan bir sistemin kime zarar verdiğinin sayılması: veri, etiket ve dağıtım yanlılığının ayrı ayrı ölçülmesi ve üçünün aynı sayıya farklı yollardan vurması, oran eşitliği, yakalama eşitliği ve isabet eşitliğinin aynı anda sağlanamaması ile birini düzeltmenin öbürünü ne kadar bozduğu, tek bir kaydın eklenip çıkarılmasının çıktıyı ne kadar oynattığı ve gürültü düzeyi süpürüldükçe doğruluktan gidenle duyarlılıktan düşenin yan yana okunması, kimliksizleştirmenin tek başına yetmemesi, bir modeli devralan kişinin sorularından kaçının belgeyle cevaplandığı, sabitlenmemiş tek kalemin oynattığı sayı ve müfredat boyunca biriken toplam kalem sayısı.

### Yanlılık Kaynakları

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/yanlilik-kaynaklari

Aynı zararın üç ayrı yerde doğduğunun ayrı ayrı sayılması: on üç alt grupta ölçülen doğrusal model bütünde 0,8194 doğruluk ve 0,3704 duyarlılık verirken az okuması olan abonelerde duyarlılık 0,2222'de kalıyor. Tabloya hiç girmeyen 69 abone yüzünden az okumalıların payı 0,3695 yerine 0,3349 okunuyor; yalnız tam okumalılardan kurulan eğitim kümesi o alt grupta kesinliği 0,5455'ten 0,3774'e indiriyor, kayda geçmeyen 19 şüpheli duyarlılığı 0,0370'e düşürüyor, kırk ziyaretlik kapasite ise aynı alt gruba 0,0359 oranında uygulanıp duyarlılığı 0,1111'de bırakıyor. Üçünde de bütündeki doğruluk en çok 0,0337 oynuyor.

Önceki konu on derste modelin ürettiği sayıyı açtı: sayının ne olduğu, kimin için olduğu ve
modelin onu neye dayanarak ürettiği ölçüldü. Açıklama bir kararı okunabilir kıldı, ama okunabilir
bir karar iyi bir karar değildir. Açıklama kararın hangi özniteliğe dayandığını söyler, kararın
**kime ne yaptığını** söylemez; bir alt gruba sistematik zarar veren bir model de aynı berraklıkla
açıklanır.

Bu konu o boşluğu doldurur ve ilk soru en somut olanıdır: zarar **nereden** geliyor. Tabloya kimin
girdiği bir yanlılıktır, etiketin kimi kaçırdığı ikincisi, modelin kime uygulandığı üçüncüsüdür.
Üçü ayrı yerde doğar, ayrı çözüm ister ve bu derste görüleceği gibi **aynı sayıya** vurur.
Gözlemin seçilmesinden doğan yanlılık M26/K05'in Uygulamalı İstatistik konusunda ölçülmüştü;
tekrarlanmaz, girdi olarak alınır.

- **ME1.** Küme, etiket, tohum ve bölme M27/K01–K07'den devralınır ve **kurgudur**: 1.260 abone,
  756 satırlık eğitim kümesi. Şüphe etiketi gerçek bir denetim kaydı değildir.
- **ME2.** Doğrulama ve sınama kümeleri bu konu boyunca **birleştirilip** tek bir 504 abonelik
  ayrılmış küme olarak okunur; alt grup sayıları 252 abonede fazla ince kalıyor. Sınama kümesinin
  tabanı 0,7579, birleşik kümenin tabanı 0,7857.
- **ME3.** Model M27/K03'ün on iki sütunlu doğrusal modelidir, ayarları sabittir ve sınama
  kümesinde 0,8016 verir; karşılaştırma çizgisi budur.
- **ME4.** Alt gruplar bu konuda tanımlanır ve sabit kalır: bölge (beş), tarife basamağı (üç),
  hane büyüklüğü (üç), okuma sayısı (iki). **On üç alt gruba bakılır** ve bu sayı her derste
  yazılır; ayrılmış kümede elli kayıttan küçük alt grup açıklık hesabına girmez.
- **ME5.** Tarife basamakları 10 ve 25 m³ eşikleriyle kurulur; 40 m³ üstünde iki abone kaldığı
  için üst basamak birleştirilir. Okuma sayısı ekseni **az** (bir ya da iki dönem) ve **tam** (üç
  dönem) olarak ikiye ayrılır.
- **ME6.** Ölçüler doğruluk, duyarlılık ve kesinliktir; tanımları M27/K03'te kuruldu ve burada
  tekrarlanmaz. Hiç işaretleme yapılmayan bir alt grupta kesinlik tanımsızdır.
- **ME7.** İki ölçüm için devralınan kurgunun üstüne yalnız bu derste geçerli iki katman eklenir:
  az okuması olan abonelerde şüphelilerin bir bölümünün kayda geçmediği bir **kayıt süreci** ve
  saha ekibinin yalnız en yüksek puanlıları ziyaret ettiği bir **kapasite**.
- **ME8.** Yanlılık burada bir niyet değil bir **ölçüdür**; üç mekanizma da sıradan kararların
  yan ürünüdür.

#### Üç Yanlılık Üç Ayrı Yerde Doğar

Kurulum kümeyi üretir, doğrusal modeli eğitir ve aynı modeli on üç alt grupta ayrı ayrı ölçer.

```python
# etik.py — MODELDIR. Ayni KURGU abone tablosu, ayni tohum ve ayni bolme;
# hedef kacak ya da ariza suphesi etiketidir ve o etiket de KURGUDUR.
import math
import statistics

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


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

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


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


ABONE, VERI, YOK = [], [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r, v = uretec(TOHUM + 7000 + k["no"]), []
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        v.append(0.0 if r() < 0.038 else math.floor(
            k["bolge"][2] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100)
        r()
    if not v:
        YOK.append(k["bolge"][0])
        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 = {"hane": k["hane"], "memnuniyet": k["memnuniyet"], "donem": len(v),
         "ort_tuketim": round(ort, 2), "oynaklik": round(oyn, 2), "il": k["bolge"][0],
         "sifir_okuma": int(min(v) == 0.0), "supheli": int(z > 1.35)}
    x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3)
    for b in BOLGE:
        x["b_" + b[0]] = int(k["bolge"][0] == b[0])
    VERI.append(x)


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, AYR = K[:756], K[756:]
ALAN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
        "kisi_basi", "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]
ORT = {a: statistics.fmean(x[a] for x in EGT) for a in ALAN}
SAP = {a: max(1e-9, statistics.pstdev([x[a] for x in EGT])) for a in ALAN}


def olcekli(x):
    return [1.0] + [(x[a] - ORT[a]) / SAP[a] for a in ALAN]


def sikistir(z):
    if z >= 0:
        return 1.0 / (1.0 + math.exp(-z)) if z < 700 else 1.0
    e = math.exp(z) if z > -700 else 0.0
    return e / (1.0 + e)


def egit(kume, etiket):                  # MODELDIR: dogrusal model, egim inisi
    X = [olcekli(x) for x in kume]
    Y = [x[etiket] for x in kume]
    w = [0.0] * len(X[0])
    for _ in range(200):
        g = [0.0] * len(w)
        for i in range(len(X)):
            h = sikistir(sum(w[j] * X[i][j] for j in range(len(w)))) - Y[i]
            for j in range(len(w)):
                g[j] += h * X[i][j]
        for j in range(len(w)):
            w[j] -= 0.3 * g[j] / len(X)
    return w


def olasilik(w, x):
    return sikistir(sum(a * b for a, b in zip(w, olcekli(x))))


def gruplar(x):
    t = 10 if x["ort_tuketim"] <= 10 else 25 if x["ort_tuketim"] <= 25 else 40
    return ["bolge " + x["il"], "tarife %d" % t,
            "hane " + ("1-2" if x["hane"] <= 2 else "3-4" if x["hane"] <= 4 else "5+"),
            "okuma " + ("az" if x["donem"] <= 2 else "tam")]


ALT = sorted({g for x in AYR for g in gruplar(x)})
W = egit(EGT, "supheli")


def olc(w, s):                           # dogruluk, duyarlilik, kesinlik
    sup = sum(x["supheli"] for x in s)
    ip = [x for x in s if olasilik(w, x) > 0.5]
    dp = sum(x["supheli"] for x in ip)
    return (sum((olasilik(w, x) > 0.5) == x["supheli"] for x in s) / len(s),
            dp / sup if sup else float("nan"), dp / len(ip) if ip else float("nan"))


print(f"abone {len(ABONE)}, hic okuma uretmeyen {len(YOK)}, etiketli {len(VERI)}, "
      f"supheli {sum(x['supheli'] for x in VERI)}")
print(f"egitim {len(EGT)}, ayrilmis {len(AYR)}, bakilan alt grup {len(ALT)}")
print(f"taban {sum(x['supheli'] == 0 for x in AYR) / len(AYR):.4f}, butunde"
      + "".join(f"{v:>11.4f}" for v in olc(W, AYR)) + "\n")
print(f"{'alt grup':<14}{'egitim':>7}{'ayrilmis':>9}{'supheli':>8}"
      f"{'dogruluk':>11}{'duyarlilik':>11}{'kesinlik':>11}")
for g in ALT:
    s = [x for x in AYR if g in gruplar(x)]
    print(f"{g:<14}{sum(1 for x in EGT if g in gruplar(x)):>7}{len(s):>9}"
          f"{sum(x['supheli'] for x in s):>8}"
          + "".join(f"{v:>11.4f}" for v in olc(W, s)))
```

```
abone 1329, hic okuma uretmeyen 69, etiketli 1260, supheli 276
egitim 756, ayrilmis 504, bakilan alt grup 13
taban 0.7857, butunde     0.8194     0.3704     0.6349

alt grup       egitim ayrilmis supheli   dogruluk duyarlilik   kesinlik
bolge bati        126       63       1     0.9841     0.0000        nan
bolge dogu        136       83      38     0.7108     0.6842     0.6842
bolge guney       141      117      17     0.8632     0.1176     0.6667
bolge kuzey       219      144      23     0.8264     0.1739     0.4000
bolge merkez      134       97      29     0.7423     0.2759     0.6667
hane 1-2          238      144      31     0.8264     0.3871     0.6667
hane 3-4          398      289      61     0.8201     0.3607     0.6286
hane 5+           120       71      16     0.8028     0.3750     0.6000
okuma az          255      167      27     0.8443     0.2222     0.5455
okuma tam         501      337      81     0.8071     0.4198     0.6538
tarife 10          29       22       6     0.7273     0.0000        nan
tarife 25         590      376      54     0.8511     0.2037     0.4583
tarife 40         137      106      48     0.7264     0.6042     0.7436
```

Bütünde okunan üç sayı iyi görünüyor: doğruluk 0,8194 ile tabanın 0,0337 üstünde, duyarlılık
0,3704, kesinlik 0,6349. Alt gruplarda aynı model on üç ayrı davranış gösteriyor: doğruluk batıda
0,9841, doğuda 0,7108; duyarlılık doğuda 0,6842, güneyde 0,1176. En keskin iki satır ölçülemeyen
satırlardır — batıda ve en alt tarife basamağında hiç işaretleme yapılmadığı için kesinlik
tanımsız ve o basamağın eğitim kümesinde toplam 29 satırı var.

Bu ders okuma sayısı eksenini izler. Az okumalılarda doğruluk 0,8443 ile bütünün üstünde, ama
duyarlılık 0,2222 ile tam okumalıların 0,4198'inin altında; açıklık 0,1976. Yüksek doğruluk
yanıltıcıdır: şüpheli oranı düşük olduğu için hiç kimseyi işaretlememek zaten yüksek doğruluk
verir. **İzlenecek sayı 0,2222'dir.**

#### Veri: Tabloya Kim Girdi

Veri yanlılığı, eğitim kümesinin modelin uygulanacağı nüfusa benzememesidir. Kaynağı burada ölçüm
ağıdır: bir abone ne kadar az okuma ürettiyse tabloya o kadar zayıf girer, hiç üretmeyen girmez.

```python
AZ = [x for x in AYR if x["donem"] < 3]
TAM = [x for x in AYR if x["donem"] == 3]
az_tablo = sum(1 for x in VERI if x["donem"] < 3)
agda = (az_tablo + len(YOK)) / (len(VERI) + len(YOK))
print(f"tabloda az okumali abone orani {az_tablo / len(VERI):.4f}, agdaki gercek "
      f"oran {agda:.4f}, fark {agda - az_tablo / len(VERI):.4f}")
TEK = [x for x in EGT if x["donem"] == 3]
WT = egit(TEK, "supheli")


def satir(ad, w):
    a, b = olc(w, AZ), olc(w, AYR)
    print(f"{ad:<26}{a[0]:>12.4f}{a[1]:>14.4f}{a[2]:>12.4f}{b[0]:>15.4f}{b[1]:>17.4f}")


print(f"\n{'egitim kumesi':<26}{'az dogruluk':>12}{'az duyarlilik':>14}"
      f"{'az kesinlik':>12}{'butun dogruluk':>15}{'butun duyarlilik':>17}")
satir(f"{len(EGT)} satir, hepsi", W)
satir(f"{len(TEK)} satir, tam okumali", WT)
```

```
tabloda az okumali abone orani 0.3349, agdaki gercek oran 0.3695, fark 0.0345

egitim kumesi              az dogruluk az duyarlilik az kesinlik butun dogruluk butun duyarlilik
756 satir, hepsi                0.8443        0.2222      0.5455         0.8194           0.3704
501 satir, tam okumali          0.7605        0.7407      0.3774         0.7857           0.4815
```

İlk satır eksikliğin büyüklüğünü veriyor: tabloda az okumalı abone oranı 0,3349, ağdaki gerçek
oran 0,3695, aradaki 0,0345 tümüyle tabloya hiç girmeyen 69 aboneden geliyor.

İkinci tablo aynı mekanizmanın bir adım ilerisidir: eğitim yalnız tam okumalı 501 satırdan
kurulduğunda az okumalı alt grupta duyarlılık 0,7407'ye **çıkıyor**, ama kesinlik 0,5455'ten
0,3774'e, doğruluk 0,8443'ten 0,7605'e iniyor. Model o alt grubu ayırt edemediği için neredeyse
hepsini işaretliyor. Zararın yönü duyarlılıkta yukarı, kesinlikte aşağıdır; tek bir sayıya bakan
biri bunu iyileşme sanır. Bütündeki doğruluk yalnız 0,0337 oynuyor.

#### Etiket: Kayıt Kimi Kaçırdı

Etiket yanlılığı tabloda kimin bulunduğuyla değil, yanına **ne yazıldığıyla** ilgilidir. Şüphe
etiketi bir kayıt sürecinin çıktısıdır ve o süreç her alt grupta aynı bilgiye sahip değildir.

```python
r = uretec(TOHUM + 62000)
kacan = 0
for x in EGT:                            # KURGU kayit sureci: yalniz bu olcumde
    x["kayitli"] = x["supheli"]
    if x["donem"] < 3 and x["supheli"] and r() < 0.4:
        x["kayitli"], kacan = 0, kacan + 1
poz = sum(1 for x in EGT if x["donem"] < 3 and x["supheli"])
print(f"az okumali egitim satiri {sum(1 for x in EGT if x['donem'] < 3)}, supheli "
      f"{poz}, kayda gecmeyen {kacan}; tam okumalilarda kayda gecmeyen 0")
WK = egit(EGT, "kayitli")
print(f"\n{'egitilen etiket':<26}{'az dogruluk':>12}{'az duyarlilik':>14}"
      f"{'az kesinlik':>12}{'butun dogruluk':>15}{'butun duyarlilik':>17}")
satir("gercek durum", W)
satir("kayitli etiket", WK)
```

```
az okumali egitim satiri 255, supheli 44, kayda gecmeyen 19; tam okumalilarda kayda gecmeyen 0

egitilen etiket            az dogruluk az duyarlilik az kesinlik butun dogruluk butun duyarlilik
gercek durum                    0.8443        0.2222      0.5455         0.8194           0.3704
kayitli etiket                  0.8323        0.0370      0.3333         0.8056           0.2778
```

Eğitim kümesindeki 255 az okumalı satırın 44'ü şüpheli ve bunların 19'u kayda geçmiyor; kaçan
kayıt toplam 756 satırın yüzde 2,5'i. Etkisi küçük değil: az okumalı alt grupta duyarlılık
0,0370'e iniyor, yani model oradaki 27 şüpheliden yalnız birini yakalıyor. Kesinlik de 0,3333'e
düşüyor; bu mekanizma iki ölçüyü birden bozuyor.

Asıl güçlük ölçünün kendisindedir. Model kayıtlı etiketle eğitilip **kayıtlı etiketle**
ölçülseydi hiçbir şey görünmezdi; kaçan 19 şüpheli ayrılmış kümede de kaçmış olurdu ve sayı yüksek
çıkardı. Eksik satır sayılabilir, yanlış etiket sayılamaz.

#### Dağıtım: Model Kime Uygulandı

Üçüncü yanlılık modelin içinde değil kullanımındadır. Her aboneye bir puan verilir, ama saha ekibi
hepsini ziyaret edemez; yalnız en yüksek puanlılara gider. Model o zaman herkese değil **bir alt
kümeye** uygulanmış olur.

```python
SIRA = sorted(AYR, key=lambda x: -olasilik(W, x))
sup_az, sup_tam = sum(x["supheli"] for x in AZ), sum(x["supheli"] for x in TAM)


def kapasite(kap):
    u = SIRA[:kap]
    ua = sum(1 for x in u if x["donem"] < 3)
    return (ua / len(AZ), (kap - ua) / len(TAM),
            sum(1 for x in u if x["donem"] < 3 and x["supheli"]) / sup_az,
            sum(1 for x in u if x["donem"] == 3 and x["supheli"]) / sup_tam,
            sum(x["supheli"] for x in u) / (sup_az + sup_tam))


print(f"{'kapasite':>9}{'az uygulanan':>17}{'tam uygulanan':>17}"
      f"{'az duyarlilik':>17}{'tam duyarlilik':>17}{'butun duyarlilik':>17}")
for kap in (40, 60, 80):
    print(f"{kap:>9}" + "".join(f"{v:>17.4f}" for v in kapasite(kap)))
k40 = kapasite(40)
print(f"\n{'yanlilik':<24}{'az duyarlilik':>15}{'butun duyarlilik':>18}"
      f"{'butun dogruluk':>16}")
for ad, w in (("yok (temel olcum)", W), ("veri", WT), ("etiket", WK)):
    a, b = olc(w, AZ), olc(w, AYR)
    print(f"{ad:<24}{a[1]:>15.4f}{b[1]:>18.4f}{b[0]:>16.4f}")
print(f"{'dagitim (kapasite 40)':<24}{k40[2]:>15.4f}{k40[4]:>18.4f}{'-':>16}")
```

```
 kapasite     az uygulanan    tam uygulanan    az duyarlilik   tam duyarlilik butun duyarlilik
       40           0.0359           0.1009           0.1111           0.3210           0.2685
       60           0.0599           0.1484           0.2222           0.3951           0.3519
       80           0.0958           0.1899           0.3333           0.4568           0.4259

yanlilik                  az duyarlilik  butun duyarlilik  butun dogruluk
yok (temel olcum)                0.2222            0.3704          0.8194
veri                             0.7407            0.4815          0.7857
etiket                           0.0370            0.2778          0.8056
dagitim (kapasite 40)            0.1111            0.2685               -
```

Kırk ziyaretlik kapasitede model az okumalıların 0,0359'una, tam okumalıların 0,1009'una
uygulanıyor; uygulanma oranı arada neredeyse üç kat fark ediyor. Sonuç duyarlılıktan okunur: az
okumalılarda 0,1111, tam okumalılarda 0,3210. Model, eşik ve eğitim kümesi değişmedi; yalnız kaç
kişiye gidildiği değişti ve açıklık 0,2099'a çıktı. Kapasite 80'de açıklık 0,1235'e iniyor:
dağıtım yanlılığı kapasitenin yan ürünüdür.

Son tablo dersin toplamıdır. Aynı alt grubun aynı sayısı üç mekanizmayla 0,7407, 0,0370 ve 0,1111
değerlerine gidiyor — biri yukarı, ikisi aşağı — ve bütündeki doğruluk en çok 0,0337 oynuyor.
Üçünün ayrı sayılması zorunludur, çünkü her biri ayrı çözüm ister: eksik satır toplamak, kayıt
sürecini denetlemek, kapasiteyi bölüştürmek. On üç alt gruba bakıldığı için bu farkların bir
bölümü yalnız bakma sayısından da doğabilir; M26/K05'in çoklu karşılaştırma dersi bunun payını
ölçmüştü ve alt grup sayısı her derste bu yüzden yazılır.

#### Özet

- Bütünde 0,8194 doğruluk ve 0,3704 duyarlılık veren doğrusal model on üç alt grupta on üç ayrı
  davranış gösteriyor: doğruluk batıda 0,9841, doğuda 0,7108 ve iki alt grupta hiç işaretleme
  yapılmadığı için kesinlik tanımsız kalıyor.
- Veri yanlılığı tabloya kimin girdiğidir: hiç okuma üretmeyen 69 abone yüzünden az okumalıların
  payı 0,3695 yerine 0,3349 okunuyor ve eğitim yalnız tam okumalılardan kurulduğunda kesinlik
  0,5455'ten 0,3774'e iniyor.
- Etiket yanlılığı yanına ne yazıldığıdır: kayda geçmeyen 19 şüpheli duyarlılığı 0,0370'e
  düşürüyor ve etiketin dışında bir ölçüt olmadan görünmüyor.
- Dağıtım yanlılığı kime uygulandığıdır: kırk ziyaretlik kapasitede model az okumalıların
  0,0359'una, tam okumalıların 0,1009'una uygulanıyor ve açıklık 0,2099'a çıkıyor.
- Üç mekanizma aynı sayıyı üç ayrı yöne taşırken bütündeki doğruluk en çok 0,0337 oynuyor.

#### Sonraki Adım

Bu derste bir alt grubun sayısı öbüründen düşük çıktığında bunun bir zarar olduğu varsayıldı ve
açıklık doğrudan raporlandı. Oysa açıklığın hangi ölçüde ölçüleceği kendi başına bir karardır.
Seçilme oranlarını eşitlemek, yakalanan şüpheli oranlarını eşitlemek ve işaretlenenlerin ne
kadarının gerçekten şüpheli olduğunu eşitlemek üç ayrı şeydir. Sonraki ders bu üç ölçütü yapı
adlarıyla kurar, eşiği her birini düzeltecek biçimde oynatır ve öbürlerinin ne kadar bozulduğunu
sayar. Çıkan sonuç bir ayar hatası değildir.

### Adalet Ölçütleri

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/adalet-olcutleri

Üç adalet ölçütünün aynı anda sağlanamadığının sayılması: taban oranı 0,4578 olan doğu bölgesi ile 0,1663 olan diğer dört bölge arasında tek eşikte oran açıklığı 0,3984, yakalama açıklığı 0,4842, isabet açıklığı 0,1242. Aynı sayıda abone işaretlenirken eşik çiftini oran eşitliğine ayarlamak isabet açıklığını 0,4800'e, yakalama eşitliğine ayarlamak 0,4262'ye, isabet eşitliğine ayarlamak ise yakalama açıklığını 0,7038'e çıkarıyor. Seçilme oranının duyarlılık ile taban oranın çarpımının kesinliğe bölümü olduğu kimliği doğrulanıyor ve iki ölçüt eşitlendiğinde seçilme oranlarının oranının taban oranların oranı olan 2,7535'e kilitlendiği gösteriliyor; kapasite sabitken üçünü birlikte veren eşik çifti yok, en iyi deneme 0,2727 açıklık bırakıyor.

Önceki ders bir alt grubun sayısı öbüründen düşük çıktığında bunun bir zarar olduğunu varsaydı ve
açıklığı doğrudan raporladı. Hangi sayının açıklığı sorusu ise açıkta kaldı. İki alt grupta
işaretlenen abonelerin **oranını** eşitlemek, yakalanan şüphelilerin **oranını** eşitlemek ve
işaretlenenlerin ne kadarının gerçekten şüpheli olduğunu eşitlemek üç ayrı taleptir. Üçü de
makul, üçü de ölçülebilir ve üçü aynı model üzerinde aynı anda karşılanamaz.

Bu ders o üç ölçütü kurar ve aralarındaki çatışmayı sayar. Sonuç bir ayar hatası değildir: iki
grubun taban oranları farklı olduğu sürece ölçütlerin tanımları birbirini dışlar. Kursun ikinci
iddiası budur ve burada bir kimlikle gösterilir.

- **ME9.** Küme, bölme, model ve alt grup tanımları önceki dersten aynen sürer: 756 satırlık
  eğitim kümesi, 504 abonelik ayrılmış küme, on iki sütunlu doğrusal model, **on üç alt grup**.
- **ME10.** Çatışmanın ölçüldüğü iki grup **bölge ekseninden** alınır: A doğu bölgesi, B geri
  kalan dört bölge. Seçimin gerekçesi taban oran farkıdır; batı bölgesi tek başına alınamaz,
  çünkü ayrılmış kümede tek bir şüphelisi vardır.
- **ME11.** **Oran eşitliği**, iki grupta işaretlenen abone oranlarının eşitliğidir.
- **ME12.** **Yakalama eşitliği**, iki grupta duyarlılıkların eşitliğidir: şüphelilerin ne
  kadarının işaretlendiği.
- **ME13.** **İsabet eşitliği**, iki grupta kesinliklerin eşitliğidir: işaretlenenlerin ne
  kadarının gerçekten şüpheli olduğu.
- **ME14.** Ölçütü sağlamanın aracı **gruba ayrı eşik** vermektir. Model, ağırlıkları ve puanları
  hiç değişmez; yalnız hangi puandan sonra işaretleneceği değişir.
- **ME15.** Eşik çiftleri 0,02'den 0,98'e 0,01 adımlı bir ızgarada aranır ve **işaretlenen toplam
  abone sayısı sabit tutulur** (63 abone, en çok üç kayma). Bu kısıt olmadan her ölçüt hiç kimseyi
  işaretlemeyerek sağlanır ve karşılaştırma anlamsızlaşır.
- **ME16.** Açıklık, iki grubun sayısı arasındaki mutlak farktır; sıfıra ne kadar yaklaştığından
  çok **öbür iki açıklığın ne yaptığı** okunur.

#### Üç Ölçüt, Üç Ayrı Eşitlik

Kurulum önceki dersin modelini yeniden üretir, ayrılmış kümedeki her aboneye bir puan verir ve
beş bölgeyi tek eşikte yan yana koyar.

```python
# adalet.py — MODELDIR. Ayni KURGU abone tablosu, ayni tohum, ayni bolme ve
# onceki dersin on iki sutunlu dogrusal modeli; esik disinda hicbir sey degismez.
import math
import statistics

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


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

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


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


ABONE, VERI = [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r, v = uretec(TOHUM + 7000 + k["no"]), []
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        v.append(0.0 if r() < 0.038 else math.floor(
            k["bolge"][2] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100)
        r()
    if not v:
        continue
    ort, oyn, r = sum(v) / len(v), max(v) - min(v), uretec(TOHUM + 51000 + k["no"])
    z = (0.052 * (ort - 20) + 0.85 * (min(v) == 0.0) + 0.026 * oyn
         + 0.24 * (k["hane"] >= 5) - 0.20 * (k["memnuniyet"] >= 4) + k["bolge"][3]
         + 0.9 * (k["no"] - 10001) / 1399 + (r() + r() + r() - 1.5) * 1.30)
    x = {"hane": k["hane"], "memnuniyet": k["memnuniyet"], "donem": len(v),
         "ort_tuketim": round(ort, 2), "oynaklik": round(oyn, 2), "il": k["bolge"][0],
         "sifir_okuma": int(min(v) == 0.0), "supheli": int(z > 1.35)}
    x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3)
    for b in BOLGE:
        x["b_" + b[0]] = int(k["bolge"][0] == b[0])
    VERI.append(x)


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, AYR = K[:756], K[756:]
ALAN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
        "kisi_basi", "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]
ORT = {a: statistics.fmean(x[a] for x in EGT) for a in ALAN}
SAP = {a: max(1e-9, statistics.pstdev([x[a] for x in EGT])) for a in ALAN}


def olcekli(x):
    return [1.0] + [(x[a] - ORT[a]) / SAP[a] for a in ALAN]


def sikistir(z):
    if z >= 0:
        return 1.0 / (1.0 + math.exp(-z)) if z < 700 else 1.0
    e = math.exp(z) if z > -700 else 0.0
    return e / (1.0 + e)


def egit(kume, etiket):                  # MODELDIR: dogrusal model, egim inisi
    X = [olcekli(x) for x in kume]
    Y = [x[etiket] for x in kume]
    w = [0.0] * len(X[0])
    for _ in range(200):
        g = [0.0] * len(w)
        for i in range(len(X)):
            h = sikistir(sum(w[j] * X[i][j] for j in range(len(w)))) - Y[i]
            for j in range(len(w)):
                g[j] += h * X[i][j]
        for j in range(len(w)):
            w[j] -= 0.3 * g[j] / len(X)
    return w


def olasilik(w, x):
    return sikistir(sum(a * b for a, b in zip(w, olcekli(x))))


def gruplar(x):
    t = 10 if x["ort_tuketim"] <= 10 else 25 if x["ort_tuketim"] <= 25 else 40
    return ["bolge " + x["il"], "tarife %d" % t,
            "hane " + ("1-2" if x["hane"] <= 2 else "3-4" if x["hane"] <= 4 else "5+"),
            "okuma " + ("az" if x["donem"] <= 2 else "tam")]


W = egit(EGT, "supheli")
PUAN = [(olasilik(W, x), x["supheli"], x["il"]) for x in AYR]
A = [p for p in PUAN if p[2] == "dogu"]
B = [p for p in PUAN if p[2] != "dogu"]


def olc(s, e):                           # secilme, duyarlilik, kesinlik, dogru, isaretli
    sup = sum(y for _, y, _ in s)
    n = sum(1 for p, _, _ in s if p > e)
    dp = sum(y for p, y, _ in s if p > e)
    return (n / len(s), dp / sup, dp / n if n else float("nan"),
            sum(1 for p, y, _ in s if (p > e) == bool(y)), n)


print(f"egitim {len(EGT)}, ayrilmis {len(AYR)}, bakilan alt grup "
      f"{len({g for x in AYR for g in gruplar(x)})}, taban "
      f"{sum(x['supheli'] == 0 for x in AYR) / len(AYR):.4f}")
print(f"{'bolge':<10}{'n':>5}{'supheli':>9}{'taban oran':>12}{'secilme':>10}"
      f"{'duyarlilik':>12}{'kesinlik':>10}")
for b in ("kuzey", "guney", "dogu", "bati", "merkez"):
    s = [p for p in PUAN if p[2] == b]
    m = olc(s, 0.5)
    print(f"{b:<10}{len(s):>5}{sum(y for _, y, _ in s):>9}"
          f"{sum(y for _, y, _ in s) / len(s):>12.4f}{m[0]:>10.4f}{m[1]:>12.4f}{m[2]:>10.4f}")
ta = sum(y for _, y, _ in A) / len(A)
tb = sum(y for _, y, _ in B) / len(B)
a0, b0 = olc(A, 0.5), olc(B, 0.5)
print(f"\nA = dogu: n {len(A)}, taban oran {ta:.4f} | B = diger dort bolge: "
      f"n {len(B)}, taban oran {tb:.4f}, oranlarin orani {ta / tb:.4f}")
print(f"tek esik 0.50, isaretlenen {a0[4] + b0[4]}: oran acikligi "
      f"{abs(a0[0] - b0[0]):.4f}, yakalama acikligi {abs(a0[1] - b0[1]):.4f}, "
      f"isabet acikligi {abs(a0[2] - b0[2]):.4f}")
```

```
egitim 756, ayrilmis 504, bakilan alt grup 13, taban 0.7857
bolge         n  supheli  taban oran   secilme  duyarlilik  kesinlik
kuzey       144       23      0.1597    0.0694      0.1739    0.4000
guney       117       17      0.1453    0.0256      0.1176    0.6667
dogu         83       38      0.4578    0.4578      0.6842    0.6842
bati         63        1      0.0159    0.0000      0.0000       nan
merkez       97       29      0.2990    0.1237      0.2759    0.6667

A = dogu: n 83, taban oran 0.4578 | B = diger dort bolge: n 421, taban oran 0.1663, oranlarin orani 2.7535
tek esik 0.50, isaretlenen 63: oran acikligi 0.3984, yakalama acikligi 0.4842, isabet acikligi 0.1242
```

Tablonun okunması gereken sütunu **taban orandır**: doğuda şüpheli oranı 0,4578, batıda 0,0159.
Bu fark modelin ürettiği değil kurgunun içinde duran bir şeydir; doğu bölgesinin gizli puanı 0,30
daha yüksektir. Model bu farkı görüyor ve doğuda abonelerin 0,4578'ini, güneyde 0,0256'sını
işaretliyor.

Alt satır dersin başlangıç noktasıdır. Tek bir eşikle üç açıklık da sıfırdan uzaktır: oran
açıklığı 0,3984, yakalama açıklığı 0,4842, isabet açıklığı 0,1242. Hangisinin düzeltileceği bir
seçim hâline gelir, çünkü üçü ayrı taraftan bakar: oran eşitliği bir abonenin komşularından daha
sık işaretlenmemesini, yakalama eşitliği hiçbir bölgede şüphelilerin öbüründen çok gözden
kaçmamasını, isabet eşitliği ise işaretlenmenin her bölgede aynı şeyi ifade etmesini ister.

#### Birini Düzeltmek Öbürünü Bozar

Ölçütü sağlamanın yolu iki gruba ayrı eşik vermektir. Aşağıdaki arama, işaretlenen toplam abone
sayısını sabit tutarak her ölçütü tek tek sıfıra en yakın noktaya çeker ve öbür iki açıklığı
yanına yazar.

```python
GRID = [i / 100 for i in range(2, 99)]
CA = {e: olc(A, e) for e in GRID}
CB = {e: olc(B, e) for e in GRID}
HEDEF = a0[4] + b0[4]


def esitle(k):                           # k: 0 secilme, 1 duyarlilik, 2 kesinlik
    en = None
    for ea in GRID:
        u = CA[ea]
        for eb in GRID:
            v = CB[eb]
            if abs(u[4] + v[4] - HEDEF) > 3 or v[2] != v[2] or u[2] != u[2]:
                continue
            f, d = abs(u[k] - v[k]), (u[3] + v[3]) / len(AYR)
            if en is None or f < en[0] - 1e-12 or (abs(f - en[0]) < 1e-12 and d > en[3]):
                en = (f, ea, eb, d)
    return en


def yaz(ad, ea, eb):
    u, v = CA[ea], CB[eb]
    print(f"{ad:<22}{ea:>7.2f}{eb:>7.2f}{u[4] + v[4]:>12}"
          f"{abs(u[0] - v[0]):>12.4f}{abs(u[1] - v[1]):>14.4f}{abs(u[2] - v[2]):>12.4f}"
          f"{(u[3] + v[3]) / len(AYR):>10.4f}")


print(f"{'yapilandirma':<22}{'esik A':>7}{'esik B':>7}{'isaretli':>12}"
      f"{'oran acik':>12}{'yakalama acik':>14}{'isabet acik':>12}{'dogruluk':>10}")
yaz("tek esik", 0.5, 0.5)
for k, ad in ((0, "oran esitligi"), (1, "yakalama esitligi"), (2, "isabet esitligi")):
    f, ea, eb, d = esitle(k)
    yaz(ad, ea, eb)
```

```
yapilandirma           esik A esik B    isaretli   oran acik yakalama acik isabet acik  dogruluk
tek esik                 0.50   0.50          63      0.3984        0.4842      0.1242    0.8194
oran esitligi            0.81   0.40          60      0.0017        0.0632      0.4800    0.7857
yakalama esitligi        0.76   0.40          63      0.0379        0.0105      0.4262    0.7877
isabet esitligi          0.34   0.65          66      0.6365        0.7038      0.0000    0.7976
```

Her satırda köşegen üstündeki sayı sıfıra iniyor ve öbürleri yükseliyor. Oran eşitliği isteniyorsa
doğuya 0,81, geri kalana 0,40 eşiği verilir; işaretlenen abone oranları 0,0017 farkla eşitlenir,
ama isabet açıklığı 0,1242'den 0,4800'e çıkar — doğuda işaretlenen abonelerin 0,9000'i gerçekten
şüpheliyken geri kalanda 0,4200'ü şüphelidir. Yakalama eşitliği isteniyorsa eşikler 0,76 ve 0,40
olur, duyarlılıklar 0,0105 farkla buluşur, isabet açıklığı 0,4262'de kalır. İsabet eşitliği
isteniyorsa doğuya 0,34, geri kalana 0,65 verilir; kesinlikler tam eşitlenir ama yakalama açıklığı
0,7038'e fırlar, çünkü doğuda şüphelilerin 0,7895'i, geri kalanda 0,0857'si yakalanır.

Bedelin bir kısmı doğruluktan gelir: bütün doğruluk üç yapılandırmada 0,7857, 0,7877 ve 0,7976'ya
iniyor ve oran eşitliğinde model tabanın tam üstünde duruyor. Ama asıl bedel doğrulukta değil öbür
iki açıklıktadır; hiçbir yapılandırma üç sütunu birden küçültemiyor.

#### Bu Bir Ayar Hatası Değil

Tablodaki örüntü daha iyi bir arama ya da daha ince bir ızgarayla düzelmez, çünkü kaynağı
tanımların kendisidir. Üç ölçüt bağımsız değildir; aralarında bir kimlik vardır. Bir grupta
seçilme oranı $s$, duyarlılık $d$, kesinlik $k$ ve taban oran $t$ ise, işaretlenen doğru sayısı
iki yoldan yazılabilir ve

$$s = \frac{d \cdot t}{k}$$

çıkar. Aşağıdaki blok önce bu kimliği iki grupta doğruluyor, sonra yakalama ile isabeti
**birlikte** eşitlemeyi deniyor.

```python
print(f"\nkimlik: secilme = duyarlilik * taban oran / kesinlik   (esik 0.50)")
for ad, m, t in (("A", a0, ta), ("B", b0, tb)):
    print(f"  {ad}: {m[1] * t / m[2]:.6f} = {m[0]:.6f}")


def birlikte(tol):
    en = None
    for ea in GRID:
        u = CA[ea]
        for eb in GRID:
            v = CB[eb]
            if v[2] != v[2] or u[2] != u[2]:
                continue
            if tol and abs(u[4] + v[4] - HEDEF) > tol:
                continue
            f = max(abs(u[1] - v[1]), abs(u[2] - v[2]))
            if en is None or f < en[0] - 1e-12:
                en = (f, ea, eb)
    return en


SUP = sum(y for _, y, _ in PUAN)
print(f"\nyakalama ile isabeti birlikte esitleme denemesi ({SUP} supheli var)")
print(f"{'kapasite kisiti':<20}{'esik A':>7}{'esik B':>7}{'en buyuk aciklik':>18}"
      f"{'isaretli':>10}{'yakalanan':>11}{'secilme orani':>15}")
for tol, ad in ((0, "yok"), (3, "63 kayma 3"), (15, "63 kayma 15")):
    f, ea, eb = birlikte(tol)
    u, v = CA[ea], CB[eb]
    yak = round(u[1] * sum(y for _, y, _ in A)) + round(v[1] * sum(y for _, y, _ in B))
    print(f"{ad:<20}{ea:>7.2f}{eb:>7.2f}{f:>18.4f}{u[4] + v[4]:>10}{yak:>11}"
          f"{u[0] / v[0]:>15.4f}")
print(f"taban oranlarin orani {ta / tb:.4f}")
```

```

kimlik: secilme = duyarlilik * taban oran / kesinlik   (esik 0.50)
  A: 0.457831 = 0.457831
  B: 0.059382 = 0.059382

yakalama ile isabeti birlikte esitleme denemesi (108 supheli var)
kapasite kisiti      esik A esik B  en buyuk aciklik  isaretli  yakalanan  secilme orani
yok                    0.86   0.82            0.0120         2          2         5.0723
63 kayma 3             0.74   0.43            0.2727        60         33         1.8445
63 kayma 15            0.72   0.46            0.2486        48         29         2.7816
taban oranlarin orani 2.7535
```

Kimlik iki grupta da altıncı basamağa kadar tutuyor. Sonucu şudur: duyarlılık ile kesinlik iki
grupta eşitlenirse $s_A / s_B = t_A / t_B$ olur, yani seçilme oranlarının oranı taban oranların
oranına, burada 2,7535'e **kilitlenir**. Oran eşitliği bu oranın 1 olmasını ister. İkisi ancak
taban oranlar eşitse ya da hiç kimse işaretlenmiyorsa birlikte doğru olabilir.

Alt tablo bunu deneyerek gösteriyor. Kapasite kısıtı kaldırıldığında arama gerçekten üç açıklığı
birden küçük yapan bir eşik çifti buluyor — 0,86 ve 0,82 — ama o noktada 504 abonenin yalnız
ikisi işaretleniyor ve 108 şüphelinin ikisi yakalanıyor. Eşitlik hiçbir şey yapmayarak
sağlanmıştır. Kapasite 63'e sabitlendiğinde en iyi deneme 0,2727 açıklık bırakıyor; 48 abonelik
daha gevşek bir kısıtta açıklık 0,2486'ya iniyor ve seçilme oranlarının oranı 2,7816 ile taban
oranların oranı olan 2,7535'e oturuyor — kimliğin öngördüğü yere.

Buradan çıkan kural bir öneri değil bir sınırdır: **taban oranlar farklı olduğu sürece üç ölçüt
aynı anda sağlanamaz.** Yapılacak iş ölçütü seçmek, seçimi yazmak ve öbür iki açıklığı sayıyla
birlikte raporlamaktır; "adil model" diye tek bir sayı yoktur.

#### Özet

- Doğu bölgesinde şüpheli oranı 0,4578, geri kalan dört bölgede 0,1663; bu taban oran farkı
  dersin bütün sonuçlarını belirler ve tek eşikte üç açıklık da büyüktür: oran 0,3984, yakalama
  0,4842, isabet 0,1242.
- İşaretlenen abone sayısı sabit tutulduğunda oran eşitliği isabet açıklığını 0,4800'e, yakalama
  eşitliği 0,4262'ye, isabet eşitliği ise yakalama açıklığını 0,7038'e çıkarıyor; bütün doğruluk
  0,7857 ile 0,7976 arasına iniyor.
- Seçilme oranı, duyarlılık ile taban oranın çarpımının kesinliğe bölümüne eşittir; iki ölçüt
  eşitlendiğinde seçilme oranlarının oranı taban oranların oranına, 2,7535'e kilitlenir.
- Kapasite sabitken üçünü birlikte veren eşik çifti yoktur: en iyi deneme 0,2727 açıklık
  bırakıyor, kısıt kaldırıldığında ise eşitlik yalnız iki abone işaretleyerek sağlanıyor.

#### Sonraki Adım

İki derste ölçülen şey modelin **kime ne yaptığıydı**. Modelin, üzerinde eğitildiği kayıtlar
hakkında **ne söylediği** hiç sorulmadı. Eğitim kümesindeki tek bir abonenin tabloya girip çıkması
çıktıyı ne kadar oynatıyor ve abone numarasını silmek o aboneyi gerçekten görünmez kılıyor mu.
Sonraki ders bunları sayar: tek bir kaydın çıktıda bıraktığı iz ölçülür, gürültü eklemenin
doğruluktan ne götürdüğü süpürülür ve kimliksizleştirilmiş bir tabloda kaç abonenin kendi alan
birleşiminde tek başına kaldığı sayılır.

### Mahremiyet Koruyan Öğrenme

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/mahremiyet-koruyan-ogrenme

Modelin kendi eğitim kayıtları hakkında ne söylediğinin savunma tarafından sayılması: abone numarası silinmiş 1.260 satırlık tabloda dört alt grup ekseni 72 birleşim üretiyor ve 6 kayıt tek başına kalıyor, altıncı alan eklendiğinde bu sayı 1.242'ye, yani 0,9857'ye çıkıyor. Tek bir eğitim kaydının çıkarılması doğrusal modelin çıktısını en çok 0,0313 oynatıyor ve iki tahmini değiştiriyor; aynı kayıt hücre tablosuna dayanan modelde çıktıyı 0,7778 oynatıyor ve 14 tahmini değiştiriyor, çünkü 66 hücrenin 13'ünde tek bir kayıt var. Gürültü on düzeyde süpürüldüğünde doğrusal modelin izini örtmek 0,04 gürültü ve 0,0022 doğruluk istiyor, hücre modelininki 0,80 gürültü ve tabanın 0,1669 altına düşmek istiyor.

İki derste ölçülen şey modelin dışarıya, yani üzerine uygulandığı abonelere ne yaptığıydı.
Modelin **içeriye**, yani üzerinde eğitildiği kayıtlara doğru ne sızdırdığı sorulmadı. Eğitim
kümesindeki bir abone tabloya girdiğinde modelin çıktısı değişiyorsa, o çıktı o abone hakkında
bir şey taşıyor demektir. Taşıdığı şeyin büyüklüğü ölçülebilir.

Bu ders o ölçümü yapar ve iki soruyla sınırlıdır. Birincisi: bir tablodan abone numarasını
silmek o aboneyi görünmez kılar mı. İkincisi: tek bir kaydın çıkarılması modelin çıktısını ne
kadar oynatır ve o oynamayı örtmenin doğruluktan bedeli nedir. Kişisel verinin ne olduğu,
saklama süresi ve analizin sınırı M25/K05 ile M26/K01'in Verinin Yapısı konusunda ölçülmüştü;
tekrarlanmaz. Burada ölçülen şey yalnız **modelin** ve **tablonun** kendi davranışıdır.

- **ME17.** Küme, bölme, model ve alt grup tanımları önceki iki dersten aynen sürer: 756 satırlık
  eğitim kümesi, 504 abonelik ayrılmış küme, **on üç alt grup**, taban 0,7857.
- **ME18.** Tablo **kimliksizleştirilmiş** kabul edilir: abone numarası sütunu yoktur. Geriye
  kalan alanlar ölçümden ve abone kaydından gelen sıradan alanlardır.
- **ME19.** Birleştirilebilirlik ölçüsü **kaç kaydın kendi alan birleşiminde tek kaldığıdır**.
  Bu bir kimliklendirme yordamı değil, tablonun kendi üzerinde yapılan bir sayımdır.
- **ME20.** İkinci bir model karşılaştırma için kurulur: **hücre tablosu**. Dört alt grup ekseni
  bir hücre verir, hücredeki şüpheli oranı çıktıdır. Küçük ve zayıf bir modeldir; buradaki işi
  yapısı gereği az kayda dayanan bir çıktının nasıl davrandığını göstermektir.
- **ME21.** **Kayıt duyarlılığı**, tek bir eğitim kaydı çıkarıldığında modelin ayrılmış kümedeki
  çıktısında görülen en büyük oynamadır. Doğrusal modelde her ölçüm bir yeniden eğitim istediği
  için **on altı kayıt** örneklenir; hücre modelinde 756 kaydın hepsi tam olarak hesaplanır.
- **ME22.** **Gürültü ekleme**, yayımlanan çıktıya eksi ve artı yönde eşit olasılıkla bir sayı
  eklemektir. Gürültü ölçeği on düzeyde süpürülür ve her düzeyde yirmi kez çekilip ortalanır.
- **ME23.** "Gürültünün üstünde kalan kayıt", izi gürültü ölçeğinin alabileceği en büyük değeri
  aşan kayıttır. Sayı düştükçe tek tek kayıtların çıktıdaki payı gürültünün içinde kalır.
- **ME24.** Ölçüm bütünüyle savunma tarafındadır: hiçbir çıkarım yordamı kurulmaz, yalnız
  korunacak büyüklükler sayılır.

#### Numarayı Silmek Ne Siler

İlk soru modelden önce tabloya sorulur. Abone numarası silindiğinde geriye kalan alanların
birleşimi kaç kaydı yalnız bırakıyor. Aşağıdaki blok alanları teker teker ekliyor ve her adımda
kaç ayrı birleşim oluştuğunu, kaç kaydın o birleşimde tek kaldığını sayıyor.

```python
# mahremiyet.py — MODELDIR. Ayni KURGU abone tablosu, ayni tohum ve ayni bolme;
# olculen sey savunma tarafindadir: tablonun ve modelin kendi davranisi.
import math
import statistics

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


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

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


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


ABONE, VERI = [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() >= 0.046:
        ABONE.append({"no": 10001 + i, "bolge": b, "hane": hane, "memnuniyet": memnun})
for k in ABONE:
    r, v = uretec(TOHUM + 7000 + k["no"]), []
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        v.append(0.0 if r() < 0.038 else math.floor(
            k["bolge"][2] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100)
        r()
    if not v:
        continue
    ort, oyn, r = sum(v) / len(v), max(v) - min(v), uretec(TOHUM + 51000 + k["no"])
    z = (0.052 * (ort - 20) + 0.85 * (min(v) == 0.0) + 0.026 * oyn
         + 0.24 * (k["hane"] >= 5) - 0.20 * (k["memnuniyet"] >= 4) + k["bolge"][3]
         + 0.9 * (k["no"] - 10001) / 1399 + (r() + r() + r() - 1.5) * 1.30)
    x = {"hane": k["hane"], "memnuniyet": k["memnuniyet"], "donem": len(v),
         "ort_tuketim": round(ort, 2), "oynaklik": round(oyn, 2), "il": k["bolge"][0],
         "sifir_okuma": int(min(v) == 0.0), "supheli": int(z > 1.35)}
    x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3)
    for b in BOLGE:
        x["b_" + b[0]] = int(k["bolge"][0] == b[0])
    VERI.append(x)


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, AYR = K[:756], K[756:]
ALAN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
        "kisi_basi", "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]
ORT = {a: statistics.fmean(x[a] for x in EGT) for a in ALAN}
SAP = {a: max(1e-9, statistics.pstdev([x[a] for x in EGT])) for a in ALAN}


def olcekli(x):
    return [1.0] + [(x[a] - ORT[a]) / SAP[a] for a in ALAN]


def sikistir(z):
    if z >= 0:
        return 1.0 / (1.0 + math.exp(-z)) if z < 700 else 1.0
    e = math.exp(z) if z > -700 else 0.0
    return e / (1.0 + e)


def egit(kume, etiket):                  # MODELDIR: dogrusal model, egim inisi
    X = [olcekli(x) for x in kume]
    Y = [x[etiket] for x in kume]
    w = [0.0] * len(X[0])
    for _ in range(200):
        g = [0.0] * len(w)
        for i in range(len(X)):
            h = sikistir(sum(w[j] * X[i][j] for j in range(len(w)))) - Y[i]
            for j in range(len(w)):
                g[j] += h * X[i][j]
        for j in range(len(w)):
            w[j] -= 0.3 * g[j] / len(X)
    return w


def olasilik(w, x):
    return sikistir(sum(a * b for a, b in zip(w, olcekli(x))))


from collections import Counter, defaultdict


def gruplar(x):
    t = 10 if x["ort_tuketim"] <= 10 else 25 if x["ort_tuketim"] <= 25 else 40
    return ["bolge " + x["il"], "tarife %d" % t,
            "hane " + ("1-2" if x["hane"] <= 2 else "3-4" if x["hane"] <= 4 else "5+"),
            "okuma " + ("az" if x["donem"] <= 2 else "tam")]


ALANLAR = ["bolge", "tarife basamagi", "hane buyuklugu", "okuma sayisi",
           "memnuniyet", "ortalama tuketim"]


def anahtar(x, k):                       # kimliksizlestirilmis kaydin ilk k alani
    return tuple((gruplar(x) + [x["memnuniyet"], x["ort_tuketim"]])[:k])


print(f"kayit {len(VERI)}, abone numarasi tabloda yok, bakilan alt grup "
      f"{len({g for x in AYR for g in gruplar(x)})}")
print(f"{'alan':>5} {'eklenen alan':<18}{'birlesim':>10}{'tek kalan kayit':>17}{'oran':>9}")
for k in range(1, 7):
    c = Counter(anahtar(x, k) for x in VERI)
    tek = sum(1 for x in VERI if c[anahtar(x, k)] == 1)
    print(f"{k:>5} {ALANLAR[k - 1]:<18}{len(c):>10}{tek:>17}{tek / len(VERI):>9.4f}")
```

```
kayit 1260, abone numarasi tabloda yok, bakilan alt grup 13
 alan eklenen alan        birlesim  tek kalan kayit     oran
    1 bolge                      5                0   0.0000
    2 tarife basamagi           15                1   0.0008
    3 hane buyuklugu            41                4   0.0032
    4 okuma sayisi              72                6   0.0048
    5 memnuniyet               247               69   0.0548
    6 ortalama tuketim        1251             1242   0.9857
```

İlk dört satır kursun alt grup eksenleridir ve kaba alanlardır: 1.260 kayıt yalnız 72 birleşime
düşüyor, tek kalan kayıt 6. Beşinci alan bu sayıyı 69'a çıkarıyor. Altıncı alan, yani virgülden
sonra iki basamak taşıyan ortalama tüketim, tabloyu tek adımda 1.251 birleşime bölüyor ve
kayıtların **0,9857'si** kendi birleşiminde tek başına kalıyor.

Okunacak şey son satırın büyüklüğü değil, dördüncü satırdan altıncıya geçişteki sıçramadır.
Kimliksizleştirme bir sütunu siler; birleştirilebilirliği silmez. Bir tablodaki alanların **sayısı
ve çözünürlüğü**, o tablonun ne kadar kimliksiz olduğunu numaranın varlığından daha çok belirler.
Sürekli bir alanı basamağa yuvarlamak bu sayıyı doğrudan düşürür ve bunun bedeli modelin
gördüğü ayrıntıdır.

#### Tek Bir Kaydın Bıraktığı İz

İkinci soru modele sorulur. Bir eğitim kaydı çıkarılıp model yeniden eğitildiğinde ayrılmış
kümedeki çıktı ne kadar oynuyor. Aşağıdaki blok bunu iki modelde ölçüyor: on iki sütunlu doğrusal
model ve dört eksenin verdiği hücre tablosu. İkinci model için ölçüm tam olarak yapılabilir,
çünkü bir kaydın çıkarılması yalnız kendi hücresinin oranını değiştirir.

```python
def hucre(x):
    return tuple(gruplar(x))


SAY = defaultdict(lambda: [0, 0])        # MODELDIR: hucre tablosu, hucre orani soyler
for x in EGT:
    h = SAY[hucre(x)]
    h[0], h[1] = h[0] + 1, h[1] + x["supheli"]
KUR = sum(x["supheli"] for x in EGT) / len(EGT)
AYR_H = Counter(hucre(x) for x in AYR)


def horan(x):
    v = SAY.get(hucre(x))
    return KUR if v is None else v[1] / v[0]


D, hdeg = [], 0
for x in EGT:
    n, k = SAY[hucre(x)]
    q = (k - x["supheli"]) / (n - 1) if n > 1 else KUR
    D.append(abs(k / n - q))
    if (k / n > 0.5) != (q > 0.5):
        hdeg = max(hdeg, AYR_H[hucre(x)])
D.sort(reverse=True)
W = egit(EGT, "supheli")
P0 = [olasilik(W, x) for x in AYR]
r = uretec(TOHUM + 71000)
IZ = []
for _ in range(16):
    x = EGT[int(r() * len(EGT))]
    w = egit([y for y in EGT if y is not x], "supheli")
    P1 = [olasilik(w, y) for y in AYR]
    IZ.append((max(abs(a - b) for a, b in zip(P0, P1)),
               sum((a > 0.5) != (b > 0.5) for a, b in zip(P0, P1))))
IZ.sort(reverse=True)
tabAY = sum(x["supheli"] == 0 for x in AYR) / len(AYR)
print(f"hucre {len(SAY)}, en kucuk hucre {min(v[0] for v in SAY.values())} kayit, "
      f"tek kayitlik hucre {sum(1 for v in SAY.values() if v[0] == 1)}, "
      f"iki ve alti {sum(1 for v in SAY.values() if v[0] <= 2)}")
print(f"taban {tabAY:.4f}, birakilan kayit {len(IZ)} (dogrusal), {len(D)} (hucre)")
print(f"\n{'model':<22}{'dogruluk':>10}{'en buyuk iz':>13}{'ortanca iz':>12}"
      f"{'degisen tahmin':>16}")
print(f"{'dogrusal model':<22}"
      f"{sum((p > 0.5) == x['supheli'] for p, x in zip(P0, AYR)) / len(AYR):>10.4f}"
      f"{IZ[0][0]:>13.4f}{IZ[len(IZ) // 2][0]:>12.4f}{max(v[1] for v in IZ):>16}")
print(f"{'hucre modeli':<22}"
      f"{sum((horan(x) > 0.5) == x['supheli'] for x in AYR) / len(AYR):>10.4f}"
      f"{D[0]:>13.4f}{D[len(D) // 2]:>12.4f}{hdeg:>16}")
```

```
hucre 66, en kucuk hucre 1 kayit, tek kayitlik hucre 13, iki ve alti 22
taban 0.7857, birakilan kayit 16 (dogrusal), 756 (hucre)

model                   dogruluk  en buyuk iz  ortanca iz  degisen tahmin
dogrusal model            0.8194       0.0313      0.0030               2
hucre modeli              0.7917       0.7778      0.0074              14
```

İki satır arasındaki fark yirmi beş kata yaklaşıyor. Doğrusal modelde bir kaydın çıkarılması 504
abonenin hiçbirinde olasılığı 0,0313'ten fazla oynatmıyor ve en fazla iki tahmini değiştiriyor;
ortanca iz 0,0030, yani kayıtların yarısından fazlası çıktıda neredeyse hiç iz bırakmıyor. Bunun
sebebi modelin her çıktısını 756 kaydın **hepsinden** üretmesidir; tek bir satırın payı on üç
ağırlığa dağılıyor.

Hücre modelinde aynı ölçüm 0,7778 veriyor. Sebebi ikinci satırın başındaki sayılardır: 66
hücrenin 13'ünde tek bir kayıt var, 22'sinde iki ya da daha az. Tek kayıtlık bir hücrede
yayımlanan oran o tek kaydın etiketinin kendisidir. O hücrenin kararı çevrildiğinde ayrılmış
kümede 14 abonenin tahmini değişiyor. Kural buradan çıkar ve modelden bağımsızdır: **bir çıktı ne
kadar az kayda dayanıyorsa o kayıtlar o çıktıda o kadar açıktadır.** Aynı sayı önceki dersteki
küçük alt grup uyarısının öbür yüzüdür — ölçülemeyecek kadar küçük bir alt grup, aynı zamanda
gizlenemeyecek kadar küçük bir alt gruptur.

#### Gürültünün Bedeli

İzi küçültmenin doğrudan yolu yayımlanan çıktıya gürültü eklemektir. Gürültü izi örter ama
doğruluğu da götürür. Aşağıdaki süpürme on gürültü düzeyinde iki modelin doğruluğunu ve o düzeyin
üstünde iz bırakan kayıt sayısını yan yana basıyor.

```python
print(f"\n{'gurultu':>8}{'dogrusal dogruluk':>19}{'hucre dogruluk':>16}"
      f"{'dogrusal ustte':>16}{'hucre ustte':>13}")
for b in (0.00, 0.02, 0.04, 0.08, 0.12, 0.20, 0.30, 0.45, 0.60, 0.80):
    dl = hl = 0.0
    for t in range(20):                  # gurultu yirmi kez cekilir, ortalama basilir
        rd = uretec(TOHUM + 74000 + t * 13)
        dl += sum(((p + b * (2 * rd() - 1)) > 0.5) == x["supheli"]
                  for p, x in zip(P0, AYR)) / len(AYR)
        rh = uretec(TOHUM + 75000 + t * 13)
        gp = {h: min(1.0, max(0.0, v[1] / v[0] + b * (2 * rh() - 1)))
              for h, v in SAY.items()}
        hl += sum((gp.get(hucre(x), KUR) > 0.5) == x["supheli"] for x in AYR) / len(AYR)
    print(f"{b:>8.2f}{dl / 20:>19.4f}{hl / 20:>16.4f}"
          f"{sum(1 for v, _ in IZ if v > b):>16}{sum(1 for v in D if v > b):>13}")
```

```

 gurultu  dogrusal dogruluk  hucre dogruluk  dogrusal ustte  hucre ustte
    0.00             0.8194          0.7917              16          679
    0.02             0.8184          0.7792               1          246
    0.04             0.8172          0.7792               0          140
    0.08             0.8151          0.7792               0           59
    0.12             0.8126          0.7780               0           34
    0.20             0.8043          0.7696               0           25
    0.30             0.7910          0.7584               0           12
    0.45             0.7560          0.7265               0           11
    0.60             0.6908          0.6779               0            1
    0.80             0.6436          0.6188               0            0
```

Doğrusal model için hesap ucuzdur. On altı kaydın hiçbiri 0,04 gürültünün üstünde iz bırakmıyor
ve o düzeyde doğruluk 0,8194'ten 0,8172'ye, yani 0,0022 iniyor — taban çizgisinin hâlâ 0,0315
üstünde. Gürültü ölçeği 0,30'a çıkarıldığında doğruluk 0,7910 ile tabanın hemen üstüne, 0,45'te
0,7560 ile tabanın altına düşüyor. Yani bedelin tamamı örtme işinden değil, gereğinden fazla
örtmekten geliyor.

Hücre modelinde aynı hesap ödenemiyor. En büyük izi örtmek için gürültü ölçeğinin 0,80'e
çıkarılması gerekiyor; o düzeyde doğruluk 0,6188 ve taban çizgisinin **0,1669 altında**. Daha
kötüsü, model daha 0,02 gürültüde 0,7792'ye inip tabanın altına düşüyor — çünkü gürültüsüz hali
zaten tabanı yalnız 0,0060 geçiyordu. Elinde ödenecek pay olmayan bir model gürültünün bedelini
karşılayamaz.

İki sütun birlikte okunduğunda dersin sonucu çıkar. Mahremiyetin bedeli sabit bir sayı değildir;
**modelin yapısına ve taban çizgisinin ne kadar üstünde durduğuna bağlıdır.** Çıktısını çok
kayıttan üreten ve tabanı rahatça geçen bir model, tek tek kayıtların izini neredeyse bedelsiz
örtebilir. Çıktısını az kayıttan üreten ve tabana yapışık duran bir model, aynı korumayı ancak
kendini işe yaramaz hale getirerek satın alabilir.

#### Özet

- Abone numarası silinmiş 1.260 satırlık tabloda dört kaba alan 72 birleşim üretiyor ve 6 kayıt
  tek kalıyor; altıncı alan eklendiğinde tek kalan kayıt 1.242'ye, yani 0,9857'ye çıkıyor.
- Kimliksizleştirme bir sütunu siler, birleştirilebilirliği silmez; belirleyici olan alanların
  sayısı ve çözünürlüğüdür.
- Tek bir eğitim kaydının çıkarılması doğrusal modelin çıktısını en çok 0,0313 oynatıyor ve iki
  tahmini değiştiriyor; ortanca iz 0,0030.
- Aynı ölçüm hücre modelinde 0,7778 veriyor ve 14 tahmini değiştiriyor, çünkü 66 hücrenin 13'ünde
  tek bir kayıt var: bir çıktı ne kadar az kayda dayanıyorsa o kayıtlar o çıktıda o kadar
  açıktadır.
- Gürültünün bedeli modele göre değişiyor: doğrusal modelde izi örtmek 0,04 gürültü ve 0,0022
  doğruluk isterken, hücre modelinde 0,80 gürültü ve taban çizgisinin 0,1669 altına düşmek
  istiyor.

#### Sonraki Adım

Üç derste zarar üç ayrı biçimde ölçüldü ve üçünde de azaltılacak bir kalem bulundu: yanlılığın
kaynağı ayrıldı, adalet ölçütü seçildi ve seçimin bedeli sayıldı, kayıt izi ölçülüp gürültüyle
örtüldü. Ölçülenlerin hiçbiri şu ana kadar modeli **kullanacak kişiye** ulaşmıyor. Bu dersteki üç
tabloyu görmemiş biri, modeli devraldığında hangi alt gruplarda ölçülmediğini, hangi eşikle hangi
adalet ölçütünün seçildiğini ve çıktıya gürültü eklenip eklenmediğini nereden bilecek. Sonraki
ders bu soruyu bir sayıya çevirir: modeli devralan kişinin sorabileceği soru kümesinden kaçı
yazılı bir beyanla kapanıyor ve hangileri cevapsız kalıyor.

### Model Belgeleme

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/model-belgeleme

Modeli devralan kişinin sorularından kaçının yazılı beyanla kapandığının sayılması: aynı model sınama kümesinde bütünde 0,7778 doğruluk ve taban çizgisinin 0,0198 üstünü verirken, dört eksende kurulan 14 alt grubun ölçülebilen 12'sinde en iyi 0,9688 ve en kötü 0,6111 okunuyor, alt grup açıklığı 0,3576 ve üç alt grup kendi tabanının altında kalıyor. Yirmi iki soruluk devir soru kümesinden yalnız bütünde ölçülen sayıyı taşıyan beyan 5'ini, alt grup tablosunu ekleyen beyan 12'sini, kullanım sınırını da yazan beyan 18'ini kapatıyor; kalan 4 soru hiçbir sürümde kapanmıyor çünkü hiçbiri bir ölçüm sorusu değil. Beş kullanım kararında ilk sürüm 4, ikincisi 1 yanlış karar ürettiriyor, üçüncüsü ölçülmeyen alt grup için bilinmiyor diyebildiği için hiç yanlış karar ürettirmiyor.

Üç ders zararı ölçtü ve azaltmayı denedi: yanlılığın üç kaynağı ayrı ayrı sayıldı, üç adalet
ölçütünün aynı anda sağlanamadığı gösterildi, tek bir kaydın çıktıyı ne kadar oynattığı ve
gürültünün doğruluktan ne götürdüğü yan yana basıldı. Bu ölçülerin hiçbiri modeli **kullanacak
kişiye** ulaşmıyor. Ölçüm defterde kalıyor; karar başka bir masada veriliyor.

Bu ders o masaya ulaşan şeyi ölçer. Ulaşan şey **model belgesidir**: modelin ne ölçüldüğünü, kimin
için ölçüldüğünü ve nerede kullanılmayacağını söyleyen yazılı beyan. Belgenin iyiliği niteliğiyle
değil, **kaç soruyu kapattığıyla** sayılır. M26/K06 raporun okuyucuya ne geri okuttuğunu ölçmüştü;
buradaki okuyucu bir rapor okuru değil, modeli devralan kişidir.

- **ME31.** Küme, etiket ve model M27/K01–K07'den devralınır ve **kurgudur**: 1.260 abone,
  756/252/252 bölme, sınama kümesinde taban çizgisi 0,7579.
- **ME32.** Ölçü doğruluktur ve taban çizgisi eğitim kümesinin en sık sınıfıdır. İkisi de her alt
  grupta **yeniden** hesaplanır.
- **ME33.** Alt gruplar dört eksende tanımlıdır: bölge, tarife basamağı, hane büyüklüğü, okuma
  sayısı. **Bu ders tarife eksenini kursun üç basamağı yerine dört basamağa böler ve okuma
  eşiğini bir döneme çeker; alt grup sayısı bu yüzden kursun sabit on üçü değil on dörttür.**
  Tanım bir karardır ve **kaç alt gruba bakıldığı** yazılır.
- **ME34.** Yirmi aboneden küçük alt grup **ölçülmez**; eşik bir karardır ve kursun yirmi
  beşlik ölçütünden ayrıdır.
- **ME35.** Devralan kişinin soru kümesi **kurgudur**: yirmi iki soru. Her soru tek bir beyan
  kalemine bağlıdır ve o kalem beyanda varsa kapanmış sayılır.
- **ME36.** Üç beyan sürümü iç içedir: A yalnız bütünde ölçülen sayıyı, B alt grup tablosunu da,
  C kullanım sınırını da taşır. Hiçbiri bir şablon değildir; kalem listesidir.
- **ME37.** Kullanım kararı yordamı yalnız beyanı okur: alt grup satırı varsa onu, yoksa bütünde
  ölçülen sayıyı kullanır. Ölçülmemiş bir alt grup için doğru yanıt "bilinmiyor"dur.

#### Aynı Sayı, On İki Alt Grup

```python
# belge.py — MODELDIR. M27/K01-K07'nin kurgu abone tablosu ayni tohumla (20260218)
# uretilir, uzerine KURGU kacak/ariza suphesi etiketi eklenir ve ayni sayi once
# butunde, sonra dort eksende tanimli alt gruplarda olculur.
import math

TOHUM, HAM, M32, ENAZ = 20260218, 1400, 0xFFFFFFFF, 20
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)]
ALAN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
        "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]


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


VERI = []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() < 0.046:
        continue
    no = 10001 + i
    r, v = uretec(TOHUM + 7000 + 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(
            b[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 + no)
    z = (0.052 * (ort - 20) + 0.85 * (min(v) == 0.0) + 0.026 * oyn
         + 0.24 * (hane >= 5) - 0.20 * (memnun >= 4) + b[3]
         + 0.9 * (no - 10001) / 1399 + (r() + r() + r() - 1.5) * 1.30)
    x = {"hane": hane, "memnuniyet": memnun, "donem": len(v), "bolge": b[0],
         "ort_tuketim": round(ort, 2), "oynaklik": round(oyn, 2),
         "sifir_okuma": int(min(v) == 0.0), "supheli": int(z > 1.35)}
    for q in BOLGE:
        x["b_" + q[0]] = int(b[0] == q[0])
    VERI.append(x)


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


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


def agac(s, derinlik, enaz=2):
    def safsizlik(u):
        p = sum(x["supheli"] for x in u) / len(u) if u else 0.0
        return 2 * p * (1 - p)
    p, en = sum(x["supheli"] for x in s) / len(s), None
    if derinlik and len(s) >= 2 * enaz and 0.0 < p < 1.0:
        for a in 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 = safsizlik(s) - (len(sol) * safsizlik(sol) + len(sag) * safsizlik(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)}


M = agac(EGT, 6)
EN_SIK = int(sum(x["supheli"] for x in EGT) * 2 > len(EGT))


def olc(s):
    """Ayni kumede taban cizgisi (en sik sinif) ve modelin dogrulugu."""
    d = 0
    for x in s:
        u = M
        while "tahmin" not in u:
            u = u["sol"] if x[u["alan"]] < u["esik"] else u["sag"]
        d += u["tahmin"] == x["supheli"]
    return sum(x["supheli"] == EN_SIK for x in s) / len(s), d / len(s)


EKSEN = [("bolge", lambda x: x["bolge"]),
         ("tarife basamagi", lambda x: "basamak %d" % (
             1 + (x["ort_tuketim"] >= 10) + (x["ort_tuketim"] >= 25)
             + (x["ort_tuketim"] >= 40))),
         ("hane buyuklugu", lambda x: "1-2 kisi" if x["hane"] <= 2 else
          ("3-4 kisi" if x["hane"] <= 4 else "5+ kisi")),
         ("okuma sayisi", lambda x: "az okuma" if x["donem"] <= 1 else "tam okuma")]

t, m = olc(SIN)
print(f"sinama kumesi {len(SIN)} abone; butunde taban {t:.4f}, model {m:.4f}, "
      f"fark {m - t:+.4f}")
print(f"\n{'eksen':<16}{'alt grup':<12}{'abone':>6}{'taban':>8}{'model':>8}{'fark':>9}")
ALTGRUP, OLCULMEYEN = [], []
for ad, f in EKSEN:
    for g in sorted({f(x) for x in SIN}):
        alt = [x for x in SIN if f(x) == g]
        if len(alt) < ENAZ:
            OLCULMEYEN.append((g, len(alt)))
            continue
        at, am = olc(alt)
        ALTGRUP.append((g, len(alt), at, am))
        print(f"{ad:<16}{g:<12}{len(alt):>6}{at:>8.4f}{am:>8.4f}{am - at:>+9.4f}")
iyi, kotu = max(ALTGRUP, key=lambda u: u[3]), min(ALTGRUP, key=lambda u: u[3])
print(f"\n{len(EKSEN)} eksende {len(ALTGRUP) + len(OLCULMEYEN)} alt grup kuruldu; "
      f"{ENAZ} aboneden kucuk {len(OLCULMEYEN)} tanesi olculmedi "
      f"({', '.join(g + ' ' + str(n) for g, n in OLCULMEYEN)})")
print(f"olculen {len(ALTGRUP)} alt grupta en iyi {iyi[3]:.4f} ({iyi[0]}), en kotu "
      f"{kotu[3]:.4f} ({kotu[0]}), alt grup acikligi {iyi[3] - kotu[3]:.4f}; kendi "
      f"tabaninin altinda kalan {sum(1 for u in ALTGRUP if u[3] < u[2])} alt grup")
```

```
sinama kumesi 252 abone; butunde taban 0.7579, model 0.7778, fark +0.0198

eksen           alt grup     abone   taban   model     fark
bolge           bati            32  1.0000  0.9688  -0.0312
bolge           dogu            36  0.4722  0.6111  +0.1389
bolge           guney           58  0.8276  0.8793  +0.0517
bolge           kuzey           68  0.8235  0.7794  -0.0441
bolge           merkez          58  0.6552  0.6724  +0.0172
tarife basamagi basamak 2      194  0.8402  0.8299  -0.0103
tarife basamagi basamak 3       46  0.4565  0.6304  +0.1739
hane buyuklugu  1-2 kisi        73  0.7534  0.7945  +0.0411
hane buyuklugu  3-4 kisi       143  0.7692  0.7762  +0.0070
hane buyuklugu  5+ kisi         36  0.7222  0.7500  +0.0278
okuma sayisi    az okuma        22  0.8636  0.8636  +0.0000
okuma sayisi    tam okuma      230  0.7478  0.7696  +0.0217

4 eksende 14 alt grup kuruldu; 20 aboneden kucuk 2 tanesi olculmedi (basamak 1 11, basamak 4 1)
olculen 12 alt grupta en iyi 0.9688 (bati), en kotu 0.6111 (dogu), alt grup acikligi 0.3576; kendi tabaninin altinda kalan 3 alt grup
```

Bütünde okunan cümle tek satırdır: model 0,7778 doğruluk veriyor ve tabanı 0,0198 geçiyor. Alt grup
tablosu aynı modeli on iki ayrı yerde ölçüyor ve tek satır on iki cümleye ayrılıyor. En iyi ile en
kötü arasındaki **alt grup açıklığı 0,3576**; bütünde okunan farkın on sekiz katı. Üç alt grupta
model **kendi tabanının altında** kalıyor: kuzeyde 0,0441, batıda 0,0312, tarife basamağı 2'de
0,0103 geride. Batıda taban 1,0000, yani orada hiç şüpheli abone yok ve model bir aboneyi boşuna
işaretliyor. "Az okuma" alt grubunda fark tam **0,0000**: model o yirmi iki abonede en sık sınıfı
söylemekten farklı hiçbir şey yapmıyor. On dört alt grubun ikisi ise hiç ölçülmedi, çünkü sınama
kümesinde on bir ve bir aboneye düşüyorlar — ama bu, orada model kullanılmayacağı anlamına gelmez.

#### Devralan Kişinin Yirmi İki Sorusu

```python

# soru.py — modeli devralan kisinin soru kumesi KURGUDUR ve yirmi iki sorudur.
# Her soru, kendisini kapatan tek bir beyan kalemine baglanir; belge surumu bir
# kalem kumesidir ve kapanan soru sayisi kumeye bakilarak sayilir.
SORU = [
    ("model neyi tahmin ediyor", "olcu"),
    ("hangi sayi raporlandi", "butun"),
    ("bu sayi hangi kumede olculdu", "kume"),
    ("taban cizgisi ne ve model onu geciyor mu", "butun"),
    ("veri hangi donemleri kapsiyor", "kume"),
    ("modele hangi alanlar giriyor", "oznitelik"),
    ("etiket nasil uretildi", "etiket"),
    ("sayi hangi alt gruplarda olculdu", "altgrup_tanim"),
    ("kac eksende kac alt gruba bakildi", "altgrup_tanim"),
    ("en kotu alt grupta sayi ne", "altgrup_tablo"),
    ("alt grup acikligi ne kadar", "altgrup_tablo"),
    ("hangi alt grupta model kendi tabaninin altinda", "altgrup_tablo"),
    ("olculmeden birakilan alt grup var mi", "olculmeyen"),
    ("niye olculmedi", "olculmeyen"),
    ("model nerede kullanilmaz", "sinir"),
    ("cikti tek basina bir karar veriyor mu", "karar"),
    ("cikti hangi esikle karara ceviriliyor", "karar"),
    ("sayi ne zaman yeniden olculur", "yeniden"),
    ("abone cikti hakkinda nasil itiraz eder", "itiraz"),
    ("yanlis cikti aboneye ne yapar", "sonuc"),
    ("bu sayilari kim dogruladi", "dogrulayan"),
    ("model bozuldugunda kim geri alir", "geri_alma"),
]

A = {"olcu", "butun", "kume"}
B = A | {"oznitelik", "etiket", "altgrup_tanim", "altgrup_tablo"}
C = B | {"olculmeyen", "sinir", "karar", "yeniden"}
SURUM = [("A: yalniz butunde olculen sayi", A),
         ("B: A + alt grup tablosu", B),
         ("C: B + kullanim siniri beyani", C)]

print(f"{'belge surumu':<32}{'kalem':>6}{'kapanan':>9}{'acik':>6}{'kapali pay':>12}")
for ad, s in SURUM:
    k = sum(1 for _, alan in SORU if alan in s)
    print(f"{ad:<32}{len(s):>6}{k:>9}{len(SORU) - k:>6}"
          f"{k / len(SORU):>12.4f}")
KAPANMAYAN = [q for q, alan in SORU if alan not in C]
print(f"\nuc surumun hicbirinin kapatmadigi {len(KAPANMAYAN)} soru:")
for q in KAPANMAYAN:
    print(f"  - {q}")
```

```
belge surumu                     kalem  kapanan  acik  kapali pay
A: yalniz butunde olculen sayi       3        5    17      0.2273
B: A + alt grup tablosu              7       12    10      0.5455
C: B + kullanim siniri beyani       11       18     4      0.8182

uc surumun hicbirinin kapatmadigi 4 soru:
  - abone cikti hakkinda nasil itiraz eder
  - yanlis cikti aboneye ne yapar
  - bu sayilari kim dogruladi
  - model bozuldugunda kim geri alir
```

Üç kalemlik bir beyan yirmi iki sorunun beşini kapatıyor. Dört kalem eklemek kapanan soruyu on
ikiye, dört kalem daha eklemek on sekize çıkarıyor. Kapanan soru sayısı kalem sayısıyla düzgün
artmıyor: alt grup tablosu tek başına üç soruya birden yetiyor.

Asıl okunacak yer son listedir. Dört soru üç sürümün hiçbirinde kapanmıyor ve dördü de bir ölçüm
sorusu değil. İtiraz yolu, yanlış çıktının aboneye ne yaptığı, sayıyı kimin doğruladığı ve modeli
kimin geri alacağı — bunların yanıtı ne sınama kümesinde ne alt grup tablosunda vardır. Bir beyan
bu dördünü **kapatamaz**, ama **açık olduklarını yazabilir**. Açık bırakılanın sayılması da
beyanın ölçüsüdür.

#### Beyanın Değiştirdiği Karar

```python

# karar.py — devralan kisi bes kullanim karari verir ve yalniz belgeyi okur.
# Yordam once alt grup satirini arar; bulamazsa butunde olculen sayiya duser.
# C surumu olculmeyen alt gruplari kaydettigi icin "bilinmiyor" diyebilir.
SATIR = {u[0]: u for u in ALTGRUP}
YOK = dict(OLCULMEYEN)
BUTUN = "evet" if m > t else "hayir"


def yanit(surum, grup):
    if "altgrup_tablo" in surum and grup in SATIR:
        return "evet" if SATIR[grup][3] > SATIR[grup][2] else "hayir"
    if "olculmeyen" in surum and grup in YOK:
        return "bilinmiyor"
    return BUTUN


def gercek(grup):
    if grup in SATIR:
        return "evet" if SATIR[grup][3] > SATIR[grup][2] else "hayir"
    return "bilinmiyor"


KARAR = ["kuzey", "dogu", "bati", "az okuma", "basamak 4"]
print(f"{'alt grup':<12}{'olculen':>12}" +
      "".join(f"{'surum ' + ad.split(':')[0]:>12}" for ad, _ in SURUM))
for g in KARAR:
    print(f"{g:<12}{gercek(g):>12}" +
          "".join(f"{yanit(s, g):>12}" for _, s in SURUM))
print()
for ad, s in SURUM:
    y = sum(1 for g in KARAR if yanit(s, g) != gercek(g))
    print(f"{ad:<32}{len(KARAR) - y} dogru, {y} yanlis karar")
print(f"\nbutunde model tabani {m - t:+.4f} geciyor; kuzeyde "
      f"{SATIR['kuzey'][3] - SATIR['kuzey'][2]:+.4f}, batida "
      f"{SATIR['bati'][3] - SATIR['bati'][2]:+.4f}, az okumada "
      f"{SATIR['az okuma'][3] - SATIR['az okuma'][2]:+.4f}")
```

```
alt grup         olculen     surum A     surum B     surum C
kuzey              hayir        evet       hayir       hayir
dogu                evet        evet        evet        evet
bati               hayir        evet       hayir       hayir
az okuma           hayir        evet       hayir       hayir
basamak 4     bilinmiyor        evet        evet  bilinmiyor

A: yalniz butunde olculen sayi  1 dogru, 4 yanlis karar
B: A + alt grup tablosu         4 dogru, 1 yanlis karar
C: B + kullanim siniri beyani   5 dogru, 0 yanlis karar

butunde model tabani +0.0198 geciyor; kuzeyde -0.0441, batida -0.0312, az okumada +0.0000
```

Soru "modeli bu alt grupta kullanmak taban çizgisinden iyi bir şey katıyor mu" sorusudur ve beş kez
soruluyor. A sürümünü okuyan kişi beşinde de "evet" diyor, çünkü elinde tek bir sayı var ve o sayı
bütün için doğru; dördü yanlış çıkıyor. B sürümü dört kararı düzeltiyor ama beşincisinde yanılıyor:
tarife basamağı 4 tablosunda yok, yordam bütünde ölçülen sayıya düşüyor ve **ölçülmemiş bir alt
grup için ölçülmüş gibi** yanıt veriyor.

Beşinci satır dersin sayısıdır. C sürümünün B'den tek farkı, ölçülmeyen iki alt grubu ve niçin
ölçülmediğini kaydetmesidir. O kayıt yeni bir başarım getirmiyor; getirdiği tek şey "bilinmiyor"
diyebilme yetkisidir ve yanlış kararı sıfıra indiriyor.

Kursun kuralı bu tablonun içinde çalışıyor. A sürümündeki 0,7778 yanlış hesaplanmış değil, kimin
için ölçüldüğü yazılmadığı için okunamayan bir sayıdır.

#### Özet

- Aynı model sınama kümesinde bütünde 0,7778 doğruluk verip tabanı 0,0198 geçerken, dört eksende
  kurulan 14 alt grubun ölçülebilen 12'sinde en iyi 0,9688 ve en kötü 0,6111 okuyor; alt grup
  açıklığı 0,3576, yani bütünde okunan farkın on sekiz katı.
- Üç alt grupta model kendi tabanının altında kalıyor (kuzey 0,0441, batı 0,0312, tarife basamağı
  2'de 0,0103 geride) ve "az okuma" alt grubunda fark tam 0,0000.
- Yirmi iki soruluk devir soru kümesinden A sürümü 5, B sürümü 12, C sürümü 18 soru kapatıyor;
  kalem sayısı arttıkça kapanan soru düzgün artmıyor.
- Dört soru hiçbir sürümde kapanmıyor ve dördü de ölçüm sorusu değil; bir beyan onları kapatamaz
  ama açık olduklarını yazabilir ve açık bırakılanın sayılması da beyanın ölçüsüdür.
- Beş kullanım kararında A sürümü 4, B sürümü 1 yanlış karar ürettiriyor; C sürümünün tek üstünlüğü
  ölçülmeyen alt grubu kaydedip "bilinmiyor" diyebilmesi ve bu, yanlış kararı sıfıra indiriyor.

#### Sonraki Adım

Bu dersin belgesi ölçülen sayıyı taşıyor, ama o sayının **ikinci kez üretilebileceğini** hiçbir
yerde söylemiyor. On dört dersin sayıları tek bir tohumla, tek bir bölmeyle, tek bir eşikle
üretildi; bu kalemlerden biri sabitlenmezse hangi sayının ne kadar oynayacağı sorulmadı. Sonraki
ders M26/K03'ün hazırlama defterinden M27/K05'in eğitim döngüsüne kadar biriken kalemleri toplar,
sabitlenmemiş tek bir kalemin sınama sayısını kaç abone kaydırdığını ölçer ve M27'nin tam kalem
listesini verir. O ders aynı zamanda kursu ve müfredatı kapatır.

### Yeniden Üretilebilirlik

Source: https://academia.sh/tr/kurslar/model-etik-ve-yorum/yeniden-uretilebilirlik

Aynı sayının ikinci kez üretilmesi için sabitlenmesi gereken kalemin sayılması ve sabitlenmemiş tek kalemin ne kadar oynattığı: değerlendirmenin kendi 9 kaleminin 6'sı tek başına sınama sayısını oynatıyor, en büyük oynama 0,0370 ile 7 abone; aynı kalemlerin 8'i alt grup açıklığını oynatıyor ve en büyük oynama 0,0989 ile bütünde okunanın 2,7 katı. Alt grup en az boyu serbest bırakıldığında iki başlık sayısı da hiç değişmiyor ama ölçülen alt grup 12'den 11'e iniyor. M26/K03'ün 39, M26/K04'ün 9, M26/K06'nın 11, M27/K02'nin 4 ve M27/K05'in 8 kaleminin üstüne değerlendirmenin 9 kalemi eklenir ve M27'nin tam listesi 80 olur. Kurs kapanışı on beş dersi bütünde ve en kötü alt grupta, müfredat kapanışı M27'nin sekiz kursunu ve 121 dersini tek tabloda toplar.

Önceki ders bir beyanın yirmi iki sorudan on sekizini kapattığını saydı. Beyanın taşıdığı sayı tek
bir koşumdan geldi: bir tohum, bir bölme, bir derinlik, bir eşik. O koşum ikinci kez yapıldığında
aynı sayının çıkacağı hiçbir yerde gösterilmedi.

Bu ders iki sayı basar. Birincisi **toplam kalem sayısıdır**: aynı sınama sayısının yeniden
üretilmesi için kaç karar yazılı olmalı. İkincisi **sabitlenmemiş tek kalemin oynattığı sayıdır**.
Kalem sayısı M26/K03, M26/K04, M26/K06, M27/K02 ve M27/K05'ten **devralınır**; bu ders yalnız
**değerlendirmenin kendi** kalemlerini ekler ve toplamı verir.

- **ME38.** Küme, etiket ve model M27/K01–K07'den devralınır ve **kurgudur**; hazırlama kalemleri
  M26/K03'te sabitlendi ve bu derste sabit kalır.
- **ME39.** Bir kalemi **serbest bırakmak** onu silmek değil, **eşit ölçüde savunulabilir** başka
  bir değere geçirmektir. Alternatifler kurgudur ve hiçbiri yanlış değildir.
- **ME40.** Her koşumda iki sayı okunur: sınama kümesinde bütünde ölçülen doğruluk ve önceki dersin
  dört ekseninde ölçülen **alt grup açıklığı**.
- **ME41.** Kalemler tek tek serbest bırakılır; biri serbestken öbür sekizi sabit kalır.
- **ME42.** Oynama abone sayısına çevrilirken o koşumun **kendi** sınama kümesi boyu kullanılır,
  çünkü bölme kalemi serbest kaldığında küme boyu da değişir.
- **ME43.** Kayan noktalı karşılaştırma `1e-9` eşiğiyle yapılır; bu eşik dört basamağa yuvarlanmış
  bir doğruluk farkının çok altındadır.

#### Değerlendirmenin Kendi Kalemleri

```python
# uretilebilirlik.py — MODELDIR. Kurgu abone tablosu ayni tohumla (20260218)
# uretilir; hazirlama kalemleri M26/K03'te sabitlenmisti ve burada sabit kalir.
# Degerlendirmenin kendi kalemleri tek bir sozlukte toplanir, kosum onu okur.
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)]
ALAN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
        "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]
VARSAYILAN = {"bolme_tohum": 90000, "egitim_payi": 0.60, "derinlik": 6,
              "yaprak_enaz": 2, "yaprak_esigi": 0.5, "aday_esik": 10,
              "altgrup_enaz": 20, "basamak": (10, 25, 40), "alan_sirasi": "dogal"}


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


VERI = []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    hane = 1 + ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    memnun = 1 + ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    if r() < 0.046:
        continue
    no = 10001 + i
    r, v = uretec(TOHUM + 7000 + 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(
            b[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 + no)
    z = (0.052 * (ort - 20) + 0.85 * (min(v) == 0.0) + 0.026 * oyn
         + 0.24 * (hane >= 5) - 0.20 * (memnun >= 4) + b[3]
         + 0.9 * (no - 10001) / 1399 + (r() + r() + r() - 1.5) * 1.30)
    x = {"hane": hane, "memnuniyet": memnun, "donem": len(v), "bolge": b[0],
         "ort_tuketim": round(ort, 2), "oynaklik": round(oyn, 2),
         "sifir_okuma": int(min(v) == 0.0), "supheli": int(z > 1.35)}
    for q in BOLGE:
        x["b_" + q[0]] = int(b[0] == q[0])
    VERI.append(x)


def kos(**serbest):
    """Kalem sozlugunu okuyup sinama dogrulugunu ve alt grup acikligini verir."""
    a = dict(VARSAYILAN, **serbest)
    r, s = uretec(TOHUM + a["bolme_tohum"]), list(VERI)
    for i in range(len(s) - 1, 0, -1):
        j = int(r() * (i + 1))
        s[i], s[j] = s[j], s[i]
    n = int(len(s) * a["egitim_payi"])
    egt, sin = s[:n], s[n + (len(s) - n) // 2:]
    alanlar = ALAN if a["alan_sirasi"] == "dogal" else ALAN[::-1]

    def agac(u, derinlik):
        p, en = sum(x["supheli"] for x in u) / len(u), None
        if derinlik and len(u) >= 2 * a["yaprak_enaz"] and 0.0 < p < 1.0:
            g = 2 * p * (1 - p)
            for alan in alanlar:
                d = sorted({x[alan] for x in u})
                for v in (d[1:] if len(d) < a["aday_esik"] else
                          [d[int(i * len(d) / a["aday_esik"])]
                           for i in range(1, a["aday_esik"])]):
                    sol = [x for x in u if x[alan] < v]
                    sag = [x for x in u if x[alan] >= v]
                    if min(len(sol), len(sag)) < a["yaprak_enaz"]:
                        continue
                    q = 0.0
                    for y in (sol, sag):
                        w = sum(x["supheli"] for x in y) / len(y)
                        q += len(y) * 2 * w * (1 - w) / len(u)
                    if en is None or g - q > en[0]:
                        en = (g - q, alan, v, sol, sag)
        if en is None or en[0] <= 1e-9:
            return {"tahmin": int(p > a["yaprak_esigi"])}
        return {"alan": en[1], "esik": en[2], "sol": agac(en[3], derinlik - 1),
                "sag": agac(en[4], derinlik - 1)}

    M = agac(egt, a["derinlik"])

    def dogruluk(u):
        d = 0
        for x in u:
            k = M
            while "tahmin" not in k:
                k = k["sol"] if x[k["alan"]] < k["esik"] else k["sag"]
            d += k["tahmin"] == x["supheli"]
        return d / len(u)

    b1, b2, b3 = a["basamak"]
    eksen = [lambda x: x["bolge"],
             lambda x: "basamak %d" % (1 + (x["ort_tuketim"] >= b1)
                                       + (x["ort_tuketim"] >= b2)
                                       + (x["ort_tuketim"] >= b3)),
             lambda x: "1-2" if x["hane"] <= 2 else
             ("3-4" if x["hane"] <= 4 else "5+"),
             lambda x: "az" if x["donem"] <= 1 else "tam"]
    olculen = []
    for f in eksen:
        for g in sorted({f(x) for x in sin}):
            alt = [x for x in sin if f(x) == g]
            if len(alt) >= a["altgrup_enaz"]:
                olculen.append(dogruluk(alt))
    return (dogruluk(sin), max(olculen) - min(olculen), len(olculen),
            len(sin))


TEMEL, ACIK, SAYI, N = kos()
print(f"butun kalemler sabitken sinama {TEMEL:.4f}, alt grup acikligi {ACIK:.4f}; "
      f"{N} abonelik sinama kumesinde olculen alt grup {SAYI}")
```

```
butun kalemler sabitken sinama 0.7778, alt grup acikligi 0.3576; 252 abonelik sinama kumesinde olculen alt grup 12
```

Dokuz kalemin hiçbiri kod satırının içinde gizli değil; hepsi koşum işlevinin okuduğu tek bir
sözlükte duruyor. Sabitlemenin ilk koşulu budur: koda gömülü bir kalemin sabit mi serbest mi olduğu
sorulamaz.

#### Sabitlenmemiş Tek Kalem

```python

# supurme.py — her kalem TEK BASINA serbest birakilir: esit olcude savunulabilir
# baska bir degere gecirilir, oburleri sabit kalir. Iki sayi birden okunur:
# butunde olculen sinama dogrulugu ve alt grup acikligi.
SERBEST = [("bolme tohumu", "bolme_tohum", 90001),
           ("egitim payi", "egitim_payi", 0.70),
           ("agac derinligi", "derinlik", 5),
           ("yaprakta en az abone", "yaprak_enaz", 5),
           ("yaprak esigi", "yaprak_esigi", 0.45),
           ("aday esik sayisi", "aday_esik", 8),
           ("alt grup en az boyu", "altgrup_enaz", 30),
           ("tarife basamagi siniri", "basamak", (12, 28, 45)),
           ("oznitelik listesi sirasi", "alan_sirasi", "ters")]

print(f"{'serbest birakilan kalem':<26}{'yeni deger':<14}{'sinama':>8}"
      f"{'abone':>7}{'aciklik':>9}{'oynama':>9}{'alt grup':>10}")
OYNAMA = []
for ad, anahtar, deger in SERBEST:
    s, c, k, n = kos(**{anahtar: deger})
    OYNAMA.append((ad, abs(s - TEMEL), abs(c - ACIK), n))
    print(f"{ad:<26}{str(deger):<14}{s:>8.4f}{round(abs(s - TEMEL) * n):>7}"
          f"{c:>9.4f}{c - ACIK:>+9.4f}{k:>10}")
oyn = sum(1 for _, u, _, _ in OYNAMA if u > 1e-9)
en_s = max(OYNAMA, key=lambda t: t[1])
en_c = max(OYNAMA, key=lambda t: t[2])
print(f"\n{len(SERBEST)} kalemin {oyn} tanesi tek basina sinama sayisini oynatiyor; "
      f"en buyuk oynama {en_s[1]:.4f} ({en_s[0]}), {round(en_s[1] * en_s[3])} abone")
print(f"ayni kalemlerin {sum(1 for _, _, u, _ in OYNAMA if u > 1e-9)} tanesi alt grup "
      f"acikligini oynatiyor; en buyuk oynama {en_c[2]:.4f} ({en_c[0]}), "
      f"butunde okunan en buyuk oynamanin {en_c[2] / en_s[1]:.1f} kati")
```

```
serbest birakilan kalem   yeni deger      sinama  abone  aciklik   oynama  alt grup
bolme tohumu              90001           0.8056      7   0.3373  -0.0204        12
egitim payi               0.7             0.8148      7   0.4286  +0.0709        11
agac derinligi            5               0.7897      3   0.4565  +0.0989        12
yaprakta en az abone      5               0.7778      0   0.3601  +0.0024        12
yaprak esigi              0.45            0.7817      1   0.3723  +0.0146        12
aday esik sayisi          8               0.7579      5   0.4470  +0.0894        12
alt grup en az boyu       30              0.7778      0   0.3576  +0.0000        11
tarife basamagi siniri    (12, 28, 45)    0.7778      0   0.3854  +0.0278        13
oznitelik listesi sirasi  ters            0.7817      1   0.3601  +0.0024        12

9 kalemin 6 tanesi tek basina sinama sayisini oynatiyor; en buyuk oynama 0.0370 (egitim payi), 7 abone
ayni kalemlerin 8 tanesi alt grup acikligini oynatiyor; en buyuk oynama 0.0989 (agac derinligi), butunde okunan en buyuk oynamanin 2.7 kati
```

Dokuz kalemin altısı tek başına sınama sayısını oynatıyor ve en büyük oynama yedi abone ediyor.
Yedi abone az görünür; oysa modelin taban çizgisi üstündeki bütün farkı beş abonedir. Altıncı satır
bunu en sert biçimde yazıyor: aday eşik sayısı 10 yerine 8 olduğunda sınama doğruluğu **0,7579**,
yani taban çizgisinin tam kendisi çıkıyor. Tek bir gerekçesiz kalem, tabanı geçen bir modeli
geçmeyen bir modele çeviriyor.

Sağdaki iki sütun kursun kendi ölçüsüdür ve daha sert. Açıklıktaki en büyük oynama 0,0989, bütünde
okunanın **2,7 katı**. Alt grup açıklığı daha kırılgandır, çünkü küçük kümelerde ölçülür ve
uçlardan okunur.

Son sütun sabitlemenin görünmeyen yüzüdür. "Alt grup en az boyu" satırında iki başlık sayısı da
hiç oynamıyor, ama ölçülen alt grup 12'den 11'e iniyor; tarife basamağı sınırı serbest kaldığında
13'e çıkıyor. Bir kalem, rapor edilen sayıyı değiştirmeden **neyin ölçüldüğünü** değiştirebiliyor
ve önceki ders bunun kararı nasıl bozduğunu saymıştı.

#### M27'nin Tam Kalem Listesi

```python

# toplam.py — M27'nin tam kalem listesi. Ilk bes kaynak ONCEKI KURSLARDA sayildi
# ve burada yeniden hesaplanmaz; bu ders yalniz degerlendirmenin kalemlerini
# ekler ve toplami verir.
KAYNAK = [("hazirlama defteri (M26/K03)", 39),
          ("calisma ortami (M26/K04)", 9),
          ("raporun kendisi (M26/K06)", 11),
          ("hazirlama zinciri (M27/K02)", 4),
          ("egitimin kendisi (M27/K05)", 8),
          ("degerlendirmenin kendisi (bu ders)", len(SERBEST))]
for ad, n in KAYNAK:
    print(f"  {ad:<36}{n:>3} kalem")
print(f"  {'toplam':<36}{sum(n for _, n in KAYNAK):>3} kalem")
print(f"seksen kalemin biri sabitlenmedigi anda butunde okunan sayi "
      f"{round(en_s[1] * en_s[3])} abone, alt grup acikligi {en_c[2]:.4f} kayabiliyor")
```

```
  hazirlama defteri (M26/K03)          39 kalem
  calisma ortami (M26/K04)              9 kalem
  raporun kendisi (M26/K06)            11 kalem
  hazirlama zinciri (M27/K02)           4 kalem
  egitimin kendisi (M27/K05)            8 kalem
  degerlendirmenin kendisi (bu ders)    9 kalem
  toplam                               80 kalem
seksen kalemin biri sabitlenmedigi anda butunde okunan sayi 7 abone, alt grup acikligi 0.0989 kayabiliyor
```

Seksen kalem tek bir listedir ve altı ayrı kursta parça parça sayılmıştır. Uzunluğu bir kusur
değil bir ölçüdür ve bu kararların hiçbiri kendiliğinden yazılmaz.

#### Özet

- Değerlendirmenin kendi kalemleri dokuzdur ve hepsi tek bir sözlükte durur; koda gömülü bir
  kalemin sabit mi serbest mi olduğu sorulamaz.
- Dokuz kalemin altısı tek başına sınama sayısını oynatıyor; en büyük oynama 0,0370 ile yedi abone
  ve bu, modelin taban çizgisi üstündeki beş abonelik farkından büyük. Aday eşik sayısı 8 olduğunda
  sınama doğruluğu taban çizgisinin tam kendisine, 0,7579'a iniyor.
- Aynı kalemlerin sekizi alt grup açıklığını oynatıyor; en büyük oynama 0,0989 ile bütünde
  okunanın 2,7 katı, çünkü açıklık küçük kümelerde ve uçlardan okunur.
- Alt grup en az boyu serbest bırakıldığında iki başlık sayısı da oynamıyor ama ölçülen alt grup
  12'den 11'e iniyor: bir kalem, rapor edilen sayıyı değiştirmeden neyin ölçüldüğünü
  değiştirebiliyor.
- M26/K03'ün 39, M26/K04'ün 9, M26/K06'nın 11, M27/K02'nin 4 ve M27/K05'in 8 kaleminin üstüne
  değerlendirmenin 9 kalemi eklenir ve M27'nin tam listesi 80 olur.

#### Kurs Kapanışı

On beş dersin her birinde aynı sayı iki kez okundu: bir kez bütünde, bir kez alt gruplarda.
Satırlar ortak birim taşımadığı için hücrelerde hangi ölçütle okunduğu yazılıdır ve her sayı kendi
dersinden alınmıştır.

| Ders | Bütünde | En kötü alt grupta | Açıklık |
|---|---|---|---|
| Değerlendirme 01 doğrulama stratejileri | doğruluk 0,7778, taban +0,0198 | 0,6111 | 0,3576 |
| Değerlendirme 02 ölçüt seçimi | bedel kazancı +0,0198 ya da +0,1984 | −0,4468 | 0,8606 |
| Değerlendirme 03 temel model | sekiz tabana göre −0,0119 … +0,5357 | doğuda −0,0833 | seçimin oynattığı 0,5476 |
| Değerlendirme 04 istatistiksel anlamlılık | fark +0,0198, payı sıfırı içeriyor | az okumada −0,0471 | 13 farkın 4'ü sıfırı dışarıda |
| Değerlendirme 05 dağılım kayması | taban üstü fark 0,0198 → 0,0066 | hiçbiri taban altında değil | 0,3576 → 0,2573 |
| Yorum 01 yorumlanabilirlik ihtiyacı | kapanan soru 8,58/12 | 7,25 soru | 1,64 soru |
| Yorum 02 öznitelik önemi | 12 sütunun 10'unda sıra ayrışıyor | en önemli sütunda 0,0162 | 0,1720 |
| Yorum 03 yerel açıklama yöntemleri | sadakat 0,9417 | 0,9027 | 0,0637 |
| Yorum 04 kısmi bağımlılık ve etkileşim | hane eğimi −0,0069 (düz) | doğuda −0,1891 | 0,3192 |
| Yorum 05 doğası gereği yorumlanabilir modeller | kural listesi 0,7897, aileye 0,0159 | merkezde 0,0862 uzak | 6 alt grup 0,02 içine giremiyor |
| Etik 01 yanlılık kaynakları | doğruluk 0,8194, duyarlılık 0,3704 | doğuda 0,7108 | 0,2733 |
| Etik 02 adalet ölçütleri | en iyi deneme 0,2727 açıklık bırakıyor | doğuda taban oran 0,4578 | yakalama 0,4842, isabet eşitliğinde 0,7038 |
| Etik 03 mahremiyet koruyan öğrenme | tek kaydın izi 0,0313 / 0,7778 | altıncı alanla tek kalan kayıt 0,9857 | gürültünün bedeli 0,0022'ye karşı 0,1669 |
| Etik 04 model belgeleme | doğruluk 0,7778; beyan 18/22 soru kapatıyor | 0,6111 (doğu) | 0,3576 |
| Etik 05 yeniden üretilebilirlik | 0,7778; tek kalem 7 abone oynatıyor | aday eşik 8'de 0,7579 | 0,3576; tek kalem 0,0989 oynatıyor |

Üçüncü sütun kursun kuralıdır: **bir sayı, kimin için ölçüldüğü yazılmadan okunamaz; alt grubu
yazılmayan başarım ölçülmemiş sayılır.** Hiçbir satırda açıklık sıfır çıkmadı.

M27'nin sekiz kursu aynı ekseni sekiz ayrı yerde okudu.

| Kurs | Ders | Ölçü ekseni | Birim |
|---|---|---|---|
| K01 Makine Öğrenmesine Giriş | 11 | ayrım | eğitimde ve ayrılmış kümede |
| K02 Veri Hazırlama ve Öznitelik Mühendisliği | 12 | özniteliğin kattığı fark | katkı |
| K03 Denetimli Öğrenme | 20 | ailenin kattığı ve bütçenin şişirdiği | denenen aday |
| K04 Denetimsiz Öğrenme | 11 | etiket yokken taban ne | kurulan taban |
| K05 Derin Öğrenme | 24 | kapasitenin kattığı ve eğitimin payı | ikinci koşum |
| K06 Doğal Dil İşleme ve Bilgisayarla Görme | 14 | alana özgü taban | alanın tabanı |
| K07 Pekiştirmeli Öğrenme ve Öneri Sistemleri | 14 | kararın kendi verisini değiştirmesi | toplanan veri |
| K08 Model Değerlendirme, Yorumlanabilirlik ve Etik | 15 | taban kim için | alt grup açıklığı |
| Toplam | 121 | | |

Yüz yirmi bir ders tek bir kuralı sekiz kez kurdu: **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.** Kural her
kursta aynı biçimde ödendi: modelin sayısının yanına daha aptal bir yordamın sayısı kondu ve farkın
nereden geldiği sorgulandı.

İkinci iddia da her kursta ödendi: **fark her zaman öğrenmeden gelmez.** Sızıntı, seçim payı, ayar
bütçesi, dengesiz sınıf ve son kursta alt grup tanımının kendisi de fark üretti.

Yüz yirmi bir derste bir model kuruldu, ölçüldü, açıklandı ve kime ne yaptığı sayıldı. Ama hepsi
**tek bir koşumda, tek bir makinede, bir defterin içinde** oldu. Modelin bir **sisteme** dönüşmesi
— sürüm alması, başkalarının çağırdığı bir yüz kazanması, bozulduğunda geri alınması ve maliyetinin
sayılması — hiç ele alınmadı. Sonraki müfredat, Yapay Zekâ Mühendisliği, bu soruyla açılır.

