---
title: 'İstatistiksel Analiz ve Keşifsel Veri Analizi'
source: 'https://academia.sh/tr/kurslar/kesifsel-analiz'
language: tr
updated: '2026-08-17T04:40:08+00:00'
license: 'CC BY-SA 4.0'
lessons: 13
outcomes:
    - 'Keşifsel veri analizini yapılandırılmış bir sırayla yürütür ve her adımda ne aradığını yazar'
    - 'Dağılım ve ilişki özetlerini ölçeğe uygun ölçütle sunar ve özetin gizlediğini gösterir'
    - 'İstatistiksel sınamayı varsayımlarıyla uygular, sonucu oynama payıyla birlikte raporlar'
---

# İstatistiksel Analiz ve Keşifsel Veri Analizi

Rapor edilen her farkın yanına o farkın ne kadar oynayabileceğinin yazılması: keşfin hipotez üretme işi, tek değişkenli dağılımda özetin gizlediği biçim, iki değişkenli ilişkide korelasyon katsayısının göremediği örüntü, korelasyon matrisinde karşılaştırma çokluğunun ürettiği sahte ilişki, ilk bakışta yakalanan veri sorunları, ortalama ile ortanca arasındaki kararın oynattığı sayı, dağılım karşılaştırmasında beş sayının gizledikleri, güven aralığının söylediği ve söylemediği, yeniden karıştırmaya dayalı hipotez sınaması ve varsayım denetimi, deney kümesinden çıkan karar sayısı, regresyon katsayısının yorum sınırı, kohort tanımının oynattığı elde tutma oranı ve gürültüden bulgu üretmenin sayılması.

## Keşifsel Analiz

Kümeyi tanımak için yürütülen sıranın her adımında ne arandığının ve o adımın hangi soruyu ürettiğinin sayılması: keşfin hipotez üretme işi ile doğrulama arasındaki ayrım, tek değişkenli incelemede merkezî eğilim özetinin gizlediği dağılım biçimi, iki değişkenli incelemede saçılım ve çapraz tablonun korelasyon katsayısından fazlasını göstermesi, korelasyon matrisinde karşılaştırma sayısının ürettiği sahte ilişki ve boyut azaltmanın rolü, gözle yapılan ilk denetimde yakalanan yığılma, kesilme ve yinelenme sorunları.

### Keşifsel Analizin Amacı

Source: https://academia.sh/tr/kurslar/kesifsel-analiz/kesifsel-analizin-amaci

Python ile Veri Analizi kursunun bıraktığı iki sayı yeniden ele alınır: doğu ortalaması 24,674 m³, kuzey 20,210 m³, fark 4,464 m³. Küme bir kütle değil örneklemdir — ağdaki 1.400 sayaçtan 1.329'u kayda girmiş, 3.987 olası okumadan 3.199'u gözlenmiştir, kapsam yüzde 80,2. Bölge etiketleri 2.000 kez rastgele yeniden dağıtıldığında hiçbir koşum 4,463 m³'e ulaşmaz; en uç karıştırma 1,754 m³ verir, yani gözlenen farkın payı 2.000'de 1'den küçüktür. Aynı yordam kuzey bölgesinin tek ve çift abone numaralı satırlarına uygulandığında gözlenen 0,232 m³'lük fark 2.000 koşumun 1.314'ünde aşılır. On denetimlik bir tarama 8 soru üretir ve 0 karar verir.

Python ile Veri Analizi kursu yirmi iki derste bir araç takımı kurdu ve her varsayılanını
yazdı. Kapanışta iki sayı kaldı: doğu bölgesinin ortalama tüketimi 24,674 m³, kuzeyin
20,210 m³. Rapor aradaki farkı 4,464 m³ olarak yazdı ve orada durdu. İki soru sorulmadı: bu
sayılar ağdaki bütün sayaçları mı özetliyor, yoksa okunabilmiş bir kısmını mı ve 4,464
m³'lük fark bir bölge farkı mı, yoksa rastlantının aynı büyüklükte üretebildiği bir
dalgalanma mı?

Bu ders o iki soruyu sorar ve kursun ölçü birimini kurar. Bundan sonra her sayının yanında
ikinci bir sayı durur: **oynama payı** — hiçbir şey değişmeden o değerin ne kadar
oynayabildiği. Kursun kuralı buradan çıkar: yanında oynama payı yazılmayan bir fark, bulgu
değil bir gözlemdir. **Payı yazılmayan sayı ölçülmemiş sayılır.**

- **EA1.** Küme **kurgudur** ve K03–K04'ten devralınır: 3.199 satırlık uzun biçimli okuma
  tablosu, 1.329 abone, üç dönem, beş bölge, 10/25/40 m³ tarife basamakları. Tohum koda
  yazılıdır, sayılar koşumdan koşuma aynıdır.
- **EA2. Keşifsel veri analizi (exploratory data analysis)** hipotez **üretir**,
  doğrulamaz. Çıktısı bir karar değil, cevaplanacak soruların listesidir; doğrulama ayrı
  bir iştir.
- **EA3.** Bu küme bir **kütle** değil, bir **örneklemdir**. Gözlenen her özet, kütlenin
  değil elde bulunan satırların özetidir ve başka bir örneklemde başka çıkardı.
- **EA4. Oynama payı** bu kursta **yeniden karıştırma (permutation)** ile ölçülür: grup
  etiketleri rastgele yeniden dağıtılır, aynı sayı yeniden hesaplanır ve gözlenen değerin
  kaç koşumda bir aşıldığı sayılır. Dağılım tablosu ya da kritik değer kullanılmaz.
- **EA5.** Payın çözünürlüğü **koşum sayısıyla sınırlıdır**. 2.000 koşumun hiçbirinde
  aşılmayan bir fark için söylenebilecek şey "payı sıfırdır" değil, "payı 2.000'de 1'den
  küçüktür".

#### Kütle mi, Örneklem mi

```python
# kesif.py — MODELDIR: K03 ve K04'un kurgu olcum agi ayni tohumla yeniden
# uretilir. Kume kurgudur; hicbir gercek abone, sayac ya da bolge temsil edilmez.
import math

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


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

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


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


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

OKUMA = []
for k in _abone + _elenen:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp(
            (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100
        if k["abone_no"] not in _gecerli:
            r()
            continue
        OKUMA.append({"abone_no": k["abone_no"], "bolge": k["bolge"],
                      "donem": DONEM[d], "tuketim_m3": t, "hane_kisi": k["hane_kisi"],
                      "memnuniyet": k["memnuniyet"],
                      "basamak": 1 if t < TARIFE[0] else 2 if t < TARIFE[1]
                      else 3 if t < TARIFE[2] else 4})
        r()


def ort(v: list[float]) -> float:
    return sum(v) / len(v)


def bolgenin(ad: str) -> list[float]:
    return [o["tuketim_m3"] for o in OKUMA if o["bolge"] == ad]


dogu, kuzey = bolgenin("dogu"), bolgenin("kuzey")
OLASI = len(_gecerli) * len(DONEM)
print(f"kurgu kume (tohum {TOHUM}): {len(OKUMA)} satir, {len(_gecerli)} abone")
print(f"dogu  {len(dogu):4d} satir, ortalama {ort(dogu):.3f} m3")
print(f"kuzey {len(kuzey):4d} satir, ortalama {ort(kuzey):.3f} m3")
print(f"gozlenen fark {ort(dogu) - ort(kuzey):.3f} m3")
print(f"agdaki sayac {HAM}, kayda giren abone {len(_gecerli)}, "
      f"hic girmeyen {HAM - len(_gecerli)}")
print(f"olasi okuma {OLASI}, gozlenen okuma {len(OKUMA)}, eksik {OLASI - len(OKUMA)}, "
      f"kapsam yuzde {100 * len(OKUMA) / OLASI:.1f}")
```

```
kurgu kume (tohum 20260218): 3199 satir, 1329 abone
dogu   557 satir, ortalama 24.674 m3
kuzey  921 satir, ortalama 20.210 m3
gozlenen fark 4.463 m3
agdaki sayac 1400, kayda giren abone 1329, hic girmeyen 71
olasi okuma 3987, gozlenen okuma 3199, eksik 788, kapsam yuzde 80.2
```

Son iki satır soruyu kapatıyor. Ağda 1.400 sayaç vardır, kayda giren abone sayısı 1.329'dur;
71 sayaç hiçbir satırda görünmez. Kayda giren aboneler üç dönem boyunca okunsaydı 3.987 satır
olurdu, gözlenen satır 3.199'dur ve kapsam yüzde 80,2'de kalır. Bu küme ağın tamamı değil,
ağdan **okunabilmiş** kısmıdır — yani bir örneklemdir ve rastgele seçilmiş bir örneklem de
değildir, çünkü hangi sayacın okunabildiğini seçen şey bir kura değil sahanın kendisidir.

Bunun sonucu doğrudandır: 24,674 m³ doğu bölgesinin ortalama tüketimi değil, doğu bölgesinde
**okunabilmiş 557 satırın** ortalamasıdır. Aynı ağdan başka bir hafta çekilen 557 satır başka
bir sayı verirdi. Sorunun kendisi burada değişiyor: "sayı doğru mu" sorusunun yerini "bu sayı
ne kadar oynar" sorusu alıyor.

Önceki kursun kapanışı farkı 4,464 m³ yazmıştı, koşan blok 4,463 m³ yazıyor: kapanış iki
yuvarlanmış sayıyı çıkardı, blok tam değerleri. Aradaki 0,001 m³ burada hiçbir şeyi
değiştirmez, ama rapor edilen sayının nasıl hesaplandığına bağlı olduğunun en küçük
örneğidir.

#### Farkın Oynama Payı

Fark gerçek mi diye sormanın bir yolu, farkın **olmadığı** bir dünyayı kurup orada aynı
büyüklükte bir farkın ne sıklıkla ortaya çıktığını saymaktır. Bölge etiketi tüketim hakkında
hiçbir şey söylemiyorsa, etiketleri rastgele yeniden dağıtmak sonucu değiştirmemelidir.

```python
# pay.py — oynama payi: bolge etiketleri rastgele yeniden dagitilir, ayni fark
# yeniden hesaplanir ve gozlenen degerin kac kosumda bir asildigi sayilir.
KOSUM = 2000
ESIK = 1e-9  # ayni fark iki yoldan hesaplaninca son basamak oynar; esitlik sinanmaz


def karistirma_payi(a: list[float], b: list[float], tohum: int):
    """Iki grubun degerleri tek havuzda toplanir. Her kosumda havuzun len(a)
    tanesi rastgele secilip birinci grup sayilir ve fark yeniden olculur."""
    r = uretec(tohum)
    havuz, na, nb = a + b, len(a), len(b)
    toplam, gozlenen = sum(havuz), ort(a) - ort(b)
    asan, en_uc = 0, 0.0
    for _ in range(KOSUM):
        h, s = havuz[:], 0.0
        for i in range(na):
            j = i + int(r() * (na + nb - i))
            h[i], h[j] = h[j], h[i]
            s += h[i]
        fark = s / na - (toplam - s) / nb
        if abs(fark) >= abs(gozlenen) - ESIK:
            asan += 1
        en_uc = max(en_uc, abs(fark))
    return gozlenen, asan, en_uc


def kuzey_yarisi(tek: bool) -> list[float]:
    return [o["tuketim_m3"] for o in OKUMA
            if o["bolge"] == "kuzey" and (o["abone_no"] % 2 == 1) == tek]


KARSILASTIRMA = [("dogu / kuzey", dogu, kuzey, TOHUM + 501),
                 ("kuzey: tek / cift abone no", kuzey_yarisi(True),
                  kuzey_yarisi(False), TOHUM + 502)]
EN = [28, 7, 7, 12, 12, 8]
y = lambda h: "".join(str(v).rjust(EN[i]) if i else str(v).ljust(EN[0])
                      for i, v in enumerate(h))
print(y(["karsilastirma", "n1", "n2", "gozlenen", "en uc", "asan"]))
asilan = {}
for ad, a, b, tohum in KARSILASTIRMA:
    g, asan, en_uc = karistirma_payi(a, b, tohum)
    asilan[ad] = asan
    print(y([ad, len(a), len(b), f"{g:.3f}", f"{en_uc:.3f}", asan]))
print(f"\n{KOSUM} kosum; asan = gozlenen kadar ya da daha buyuk fark ureten kosum")
for ad, asan in asilan.items():
    print(f"{ad:<28}pay " + (f"1/{KOSUM} degerinden kucuk" if asan == 0
                             else f"{asan / KOSUM:.3f}, 100 kosumun "
                                  f"{round(100 * asan / KOSUM)} tanesinde asildi"))
```

```
karsilastirma                    n1     n2    gozlenen       en uc    asan
dogu / kuzey                    557    921       4.463       1.754       0
kuzey: tek / cift abone no      452    469       0.232       1.647    1314

2000 kosum; asan = gozlenen kadar ya da daha buyuk fark ureten kosum
dogu / kuzey                pay 1/2000 degerinden kucuk
kuzey: tek / cift abone no  pay 0.657, 100 kosumun 66 tanesinde asildi
```

İki satır aynı yordamdan geçti ve zıt cevap verdi. Doğu ile kuzey arasındaki 4,463 m³'lük
farka 2.000 karıştırmanın hiçbiri ulaşamadı; en uç fark 1,754 m³'tür, gözlenenin yarısından
az. Bölge etiketi tüketim hakkında bir
şey söylüyor.

İkinci satır bir denetimdir. Abone numarasının tek ya da çift olması tüketimi etkileyemez;
bu kırılım tanım gereği gürültüdür ve araç bunu söylüyor: gözlenen 0,232 m³'lük fark 2.000
koşumun 1.314'ünde, yani yüz koşumun altmış altısında aşılmaktadır. Böyle bir farkı rapora
"kuzeyde tek numaralı aboneler daha çok tüketiyor" diye yazmak, karıştırmanın üçte iki
sıklıkla ürettiği bir şeyi bulgu saymak olur.

Çözünürlük sınırı ilk satırda görünüyor. Sıfır aşan koşum "pay sıfırdır" demek değildir;
2.000 koşumla ölçülebilen en küçük pay 2.000'de 1'dir ve gözlenen fark bunun altındadır.
Koşum sayısı on kat artırılsaydı sınır on kat inerdi. Payın kendisi de bir ölçümdür ve kendi
çözünürlüğüyle birlikte yazılır.

Yordamın söylemediği şey de yazılır. Karıştırma yalnız "bu büyüklükte bir fark etiketler
karışıkken ne sıklıkla çıkar" sorusuna cevap verir; farkın **nedenini** söylemez. Doğunun
tarife tabanı yüksek olabilir, hane büyüklüğü farklı olabilir, ya da doğuda okunabilen
sayaçlar sistematik olarak büyük aboneler olabilir. Küçük pay, açıklama yerine geçmez.

#### Keşif Karar Vermez, Soru Üretir

Bir farkın payını ölçmek keşfin sonu değil bir adımıdır. Keşfin işi kümeyi dolaşıp hangi
soruların sorulmaya değer olduğunu çıkarmaktır; aşağıdaki tarama bunu bir ölçüt listesi
olarak yazar ve eşiği aşan her ölçütü bir soruya çevirir.

```python
# soru.py — kesfin ciktisi bir karar degil, bir soru listesidir. Her denetim bir
# olcut hesaplar; esigi asan olcut bir karar degil, cevaplanacak bir soru uretir.
from collections import Counter


def ortanca(v: list[float]) -> float:
    s = sorted(v)
    n = len(s)
    return s[n // 2] if n % 2 else (s[n // 2 - 1] + s[n // 2]) / 2


T, S = [o["tuketim_m3"] for o in OKUMA], sorted(o["tuketim_m3"] for o in OKUMA)
bolge_say = Counter(o["bolge"] for o in OKUMA)
donem_say = Counter(o["donem"] for o in OKUMA)
basamak_say = Counter(o["basamak"] for o in OKUMA)
abone_say = Counter(o["abone_no"] for o in OKUMA)
memnun_say = Counter(o["memnuniyet"] for o in OKUMA)
pay = lambda k: 100 * k / len(OKUMA)

DENETIM = [
    ("tuketim", "sifir yazilmis okuma payi", pay(sum(1 for t in T if t == 0)),
     1.0, "ust", "sifir bir olcum mu, okunamamis sayac mi"),
    ("kapsam", "gozlenen / olasi okuma", 100 * len(OKUMA) / OLASI,
     95.0, "alt", "okunanlar okunamayanlardan farkli mi"),
    ("abone_no", "uc donemi tam olan abone payi",
     100 * sum(1 for v in abone_say.values() if v == 3) / len(abone_say),
     90.0, "alt", "eksik donem rastgele mi dagilmis"),
    ("bolge", "en kucuk / en buyuk bolge",
     100 * min(bolge_say.values()) / max(bolge_say.values()),
     60.0, "alt", "kucuk bolgenin payi ne kadar buyur"),
    ("bolge", "bolge etiketi bos satir payi",
     pay(sum(1 for o in OKUMA if not o["bolge"])), 0.0, "ust",
     "etiketsiz satirlar hangi bolgeye ait"),
    ("donem", "donemler arasi satir acikligi",
     100 * (max(donem_say.values()) - min(donem_say.values())) / max(donem_say.values()),
     10.0, "ust", "donem farki davranis mi, takvim mi"),
    ("tuketim", "ortalama - ortanca acikligi",
     100 * (ort(T) - ortanca(T)) / ortanca(T), 2.0, "ust",
     "dagilim carpik mi, hangi ozet raporlanir"),
    ("tuketim", "en buyuk deger / ucuncu ceyrek", max(S) / S[int(0.75 * len(S))],
     2.5, "ust", "uc degerler ortalamayi ne kadar tasir"),
    ("basamak", "en seyrek basamagin payi", pay(min(basamak_say.values())),
     5.0, "alt", "seyrek basamagin orani ne kadar oynar"),
    ("memnuniyet", "en kalabalik memnuniyet payi", pay(max(memnun_say.values())),
     30.0, "ust", "siralayici olcekte ortalama mesru mu"),
]

E = [12, 32, 8, 7]
z = lambda h: "".join(str(v).ljust(E[i]) if i < 2 else str(v).rjust(E[i])
                      for i, v in enumerate(h[:4])) + "  " + str(h[4])
print(z(["alan", "olcut", "deger", "esik", "uretilen soru"]))
soru = 0
for alan, olcut, deger, esik, yon, metin in DENETIM:
    tetik = deger > esik if yon == "ust" else deger < esik
    soru += tetik
    print(z([alan, olcut, f"{deger:.1f}", f"{esik:.1f}", metin if tetik else "-"]))
print(f"\n{len(DENETIM)} denetim yuruldu, {soru} soru uretildi, 0 karar verildi")
```

```
alan        olcut                              deger   esik  uretilen soru
tuketim     sifir yazilmis okuma payi            3.7    1.0  sifir bir olcum mu, okunamamis sayac mi
kapsam      gozlenen / olasi okuma              80.2   95.0  okunanlar okunamayanlardan farkli mi
abone_no    uc donemi tam olan abone payi       66.5   90.0  eksik donem rastgele mi dagilmis
bolge       en kucuk / en buyuk bolge           51.7   60.0  kucuk bolgenin payi ne kadar buyur
bolge       bolge etiketi bos satir payi         0.0    0.0  -
donem       donemler arasi satir acikligi       33.5   10.0  donem farki davranis mi, takvim mi
tuketim     ortalama - ortanca acikligi          3.9    2.0  dagilim carpik mi, hangi ozet raporlanir
tuketim     en buyuk deger / ucuncu ceyrek       2.1    2.5  -
basamak     en seyrek basamagin payi             1.8    5.0  seyrek basamagin orani ne kadar oynar
memnuniyet  en kalabalik memnuniyet payi        33.4   30.0  siralayici olcekte ortalama mesru mu

10 denetim yuruldu, 8 soru uretildi, 0 karar verildi
```

On denetim yürüdü ve sekiz soru çıktı. Tabloda tek bir karar yoktur: hiçbir satır "şu satırlar
elenmeli" ya da "şu bölge daha çok tüketiyor" demez. Keşfin çıktısı budur ve doğrulamadan
ayrıldığı yer tam burasıdır. Doğrulama tek bir soruyu alır ve ona bir cevap üretir; keşif
kümeyi dolaşır ve cevaplanacak soruların listesini üretir.

Eşiği aşmayan iki satır da bilgi taşıyor. Bölge etiketi boş satır yoktur, çünkü bölge abone
kaydından gelir ve Veri Toplama ve Hazırlama kursunda eşleştirilmiştir; en büyük değerin
üçüncü çeyreğe oranı 2,1'dir, yani üst uçta aşırı bir kopukluk yoktur. Denetimin geçmesi de
bir ölçüm sonucudur.

Eşiklerin kendisi de birer karardır. Yüzde 95'lik kapsam eşiği yerine yüzde 75 yazılsaydı
ikinci satır soru üretmezdi; ortalama–ortanca açıklığı için yüzde 2 yerine yüzde 5 seçilseydi
yedinci satır susardı. Tablodaki sekiz sayısı kümenin bir özelliği değil, kümeyle eşik
listesinin birlikte ürettiği bir sayıdır. Bu yüzden eşikler koda yazılır ve tabloda görünür.

Sekiz sorunun bedeli sonraki konuda ödenir. Keşif sırasında bakılan her kırılım, sınamanın
payını büyüten bir borçtur: on ölçüte bakıp en dikkat çekenini sınamak, tek bir ölçüte bakıp
onu sınamakla aynı şey değildir. Bu ders yalnız borcun açıldığını yazar.

#### Özet

- Küme bir kütle değil örneklemdir: 1.400 sayaçtan 1.329'u kayda girmiş, 3.987 olası okumadan
  3.199'u gözlenmiştir ve kapsam yüzde 80,2'dir.
- Doğu ile kuzey arasındaki gözlenen fark 4,463 m³'tür; bölge etiketleri 2.000 kez rastgele
  yeniden dağıtıldığında en uç fark 1,754 m³ kalır ve gözlenene hiçbir koşumda ulaşılmaz.
- Aynı yordam kuzeyin tek ve çift abone numaralı satırlarına uygulandığında gözlenen
  0,232 m³'lük fark 2.000 koşumun 1.314'ünde aşılır; araç gürültüyü gürültü olarak bildirir.
- Payın çözünürlüğü koşum sayısıdır: 2.000 koşumda hiç aşılmayan bir fark için söylenebilecek
  şey "payı sıfırdır" değil, "payı 2.000'de 1'den küçüktür".
- Keşfin çıktısı karar değil sorudur: on denetimlik tarama 8 soru üretmiş, 0 karar vermiştir
  ve bu sayı kümeyle eşik listesinin ortak ürünüdür.

#### Sonraki Adım

Bu ders iki bölge ortalamasının farkına baktı ve yanına payını yazdı. Ortalamanın kendisi
sorgulanmadı: 557 satırın ortalaması 24,674 m³ diye yazıldığında o satırların nasıl dağıldığı
hakkında hiçbir şey söylenmiş olmaz ve aynı ortalamayı veren dağılımlar birbirinden çok
farklı olabilir. Sonraki ders tek değişkenli incelemeyi ele alır: aynı ortalamayı veren iki
dağılım kurulur, beş sayı özeti ve aralık sayımları basılır, ortalama ile ortanca arasındaki
açıklığın çarpıklığı nasıl ele verdiği ve elenmeyen aykırı değerlerin özeti ne kadar
oynattığı sayılır.

### Tek Değişkenli İnceleme

Source: https://academia.sh/tr/kurslar/kesifsel-analiz/tek-degiskenli-inceleme

Doğu bölgesinin 557 okuması ile aynı ortalamayı (24,674 m³) ve aynı standart sapmayı (9,198) veren simetrik bir model dağılım yan yana konur ve rapor edilen iki sayının biçimi hiç anlatmadığı gösterilir: beş sayı özeti 0,00 / 19,23 / 24,12 / 29,85 / 51,90 ile 0,66 / 18,37 / 24,61 / 31,43 / 47,79 olarak ayrışır, çeyrekler açıklığı 10,62'ye karşı 13,06 çıkar, ortalama ile ortanca arasındaki açıklık 0,554'e karşı 0,064 kalır. Aralık sayımları beş sayının göremediğini verir: gözlemde ilk aralıkta 20, ikincisinde 1 değer vardır ve aralık genişliği 10 seçilirse bu kopukluk tek bir 21 sayısına gömülür. Çit dışındaki 30 değer elenmez, etkisi ölçülür: eleme doğu ortalamasını 25,154'e, doğu ile kuzey arasındaki farkı 4,463'ten 4,622 m³'e taşır.

Önceki ders iki bölge ortalamasının farkına baktı ve yanına payını yazdı: 4,463 m³'lük fark
2.000 karıştırmanın hiçbirinde ortaya çıkmadı. Ortalamanın kendisi ise hiç sorgulanmadı.
Doğu bölgesi için yazılan 24,674 m³, 557 okumanın tek bir sayıya sıkıştırılmış halidir ve o
557 sayının nasıl dizildiği hakkında hiçbir şey söylemez.

Bu ders bir sütunun tek başına nasıl incelendiğini ele alır ve ölçüsü şudur: **özetin
gizlediği biçim**. Aynı ortalamayı ve aynı standart sapmayı veren iki dağılım kurulur, ikisi
de aynı iki sayıyla raporlanır ve aralarındaki farkın rapora hiç girmediği gösterilir.

- **EA6.** Tek değişkenli inceleme (univariate) bir sütuna üç soru sorar: merkez nerede,
  değerler ne kadar dağınık ve dağılımın biçimi ne. Üçü birlikte yazılmadıkça sütun tarif
  edilmiş olmaz.
- **EA7. Beş sayı özeti** en küçük değer, birinci çeyrek, ortanca, üçüncü çeyrek ve en büyük
  değerdir. Çeyrekler açıklığı Ç3 ile Ç1 arasındaki uzaklıktır ve Veri Toplama ve Hazırlama
  kursunda tanımlanmıştır.
- **EA8. Çarpıklık (skewness)** bu kursta **ortalama ile ortanca arasındaki açıklıkla**
  ölçülür. Açıklık pozitifse uzun kuyruk sağdadır; ortalama kuyruğu izler, ortanca izlemez.
- **EA9. Aralık sayımları** dağılımın biçimini sayı olarak verir: her aralığın sınırları ve
  içine düşen değer sayısı basılır. **Aralık genişliği bir karardır** ve biçimi değiştirir.
- **EA10.** Aykırı değer bu kursta **elenmez**. Eleme Veri Toplama ve Hazırlama kursunun
  temizleme kararıydı ve ölçüsü satır sayısıydı; burada aynı değerler kümede kalır, yalnız
  özetin üzerindeki etkileri sayılır.

#### Merkez, Değişkenlik ve Biçim

```python
# dagilim.py — MODELDIR: K03 ve K04'un kurgu olcum agi ayni tohumla uretilir.
# Kume kurgudur; hicbir gercek abone, sayac ya da bolge temsil edilmez.
import math

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


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

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


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


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

OKUMA = []
for k in _abone + _elenen:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp(
            (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100
        if k["abone_no"] not in _gecerli:
            r()
            continue
        OKUMA.append({"abone_no": k["abone_no"], "bolge": k["bolge"],
                      "donem": DONEM[d], "tuketim_m3": t, "hane_kisi": k["hane_kisi"],
                      "memnuniyet": k["memnuniyet"],
                      "basamak": 1 if t < TARIFE[0] else 2 if t < TARIFE[1]
                      else 3 if t < TARIFE[2] else 4})
        r()


def ort(v: list[float]) -> float:
    return sum(v) / len(v)


def ss(v: list[float]) -> float:
    """Standart sapma; payda n-1, cunku elde bulunan bir orneklemdir."""
    m = ort(v)
    return math.sqrt(sum((x - m) ** 2 for x in v) / (len(v) - 1))


def ortanca(v: list[float]) -> float:
    s = sorted(v)
    n = len(s)
    return s[n // 2] if n % 2 else (s[n // 2 - 1] + s[n // 2]) / 2


def ceyrek(v: list[float], p: float) -> float:
    """Dogrusal aradegerlemeli ceyrek; K03'teki tanimla aynidir."""
    s = sorted(v)
    i = p * (len(s) - 1)
    a = int(i)
    return s[a] if a + 1 >= len(s) else s[a] + (s[a + 1] - s[a]) * (i - a)


def bolgenin(ad: str) -> list[float]:
    return [o["tuketim_m3"] for o in OKUMA if o["bolge"] == ad]


dogu, kuzey = bolgenin("dogu"), bolgenin("kuzey")
print(f"kurgu kume (tohum {TOHUM}): {len(OKUMA)} satir, {len(_gecerli)} abone")
print(f"dogu: {len(dogu)} satir, ortalama {ort(dogu):.3f} m3, "
      f"ortanca {ortanca(dogu):.2f} m3, standart sapma {ss(dogu):.3f}")
print(f"ortalama - ortanca = {ort(dogu) - ortanca(dogu):.3f} m3, "
      f"standart sapmanin {100 * (ort(dogu) - ortanca(dogu)) / ss(dogu):.1f} yuzdesi")
```

```
kurgu kume (tohum 20260218): 3199 satir, 1329 abone
dogu: 557 satir, ortalama 24.674 m3, ortanca 24.12 m3, standart sapma 9.198
ortalama - ortanca = 0.554 m3, standart sapmanin 6.0 yuzdesi
```

Bir sütun tek sayıyla tarif edilemez. Merkezî eğilim iki ayrı sayı verir: ortalama 24,674 m³,
ortanca 24,12 m³. **Değişkenlik** üçüncü sayıdır: standart sapma 9,198'dir, yani okumalar
merkezin çevresinde ortalama olarak dokuz metre küpten fazla dolaşır. Bu üç sayı henüz
biçimi söylemez, ama biçim hakkındaki ilk işareti verir.

İşaret, ortalama ile ortancanın ayrışmasıdır. Ortanca sıralamaya bakar ve bir değerin ne
kadar uzakta olduğunu umursamaz; ortalama her değerin uzaklığını taşır. İkisi arasındaki
0,554 m³'lük açıklık, uzun kuyruğun sağda olduğunu söyler: birkaç büyük okuma ortalamayı
yukarı çekmiş, ortancayı yerinde bırakmıştır. Açıklık standart sapmanın yüzde 6,0'sı
kadardır ve bu, çarpıklığın ölçüsü olarak doğrudan raporlanabilir.

#### Aynı Ortalama, Başka Dağılım

```python
# esdeger.py — ayni ortalamayi ve ayni standart sapmayi veren ikinci bir dagilim.
# Kurgudur: uc duzgun cekilisin toplami simetriktir, sonra dogunun ortalamasina
# ve standart sapmasina oturtulur. Amac karsilastirmadir, benzetim degil.
def simetrik(n: int, hedef_ort: float, hedef_ss: float, tohum: int) -> list[float]:
    r = uretec(tohum)
    ham = [r() + r() + r() - 1.5 for _ in range(n)]
    m, s = ort(ham), ss(ham)
    v = [round(hedef_ort + (x - m) * hedef_ss / s, 2) for x in ham]
    kayma = hedef_ort - ort(v)  # yuvarlama ortalamayi bir miktar kaydirir
    return [round(x + kayma, 2) for x in v]


MODEL = simetrik(len(dogu), ort(dogu), ss(dogu), TOHUM + 601)


def bes_sayi(v: list[float]) -> list[float]:
    return [min(v), ceyrek(v, 0.25), ortanca(v), ceyrek(v, 0.75), max(v)]


BAS = ["en kucuk", "C1", "ortanca", "C3", "en buyuk", "CAA", "ortalama", "carpiklik"]
G = [17] + [10] * 8
y = lambda h: "".join(str(v).ljust(G[i]) if not i else str(v).rjust(G[i])
                      for i, v in enumerate(h))
print(y(["dagilim"] + BAS))
for ad, v in [("dogu (gozlem)", dogu), ("model (simetrik)", MODEL)]:
    b = bes_sayi(v)
    print(y([ad] + [f"{x:.2f}" for x in b] + [f"{b[3] - b[1]:.2f}",
             f"{ort(v):.3f}", f"{ort(v) - ortanca(v):.3f}"]))
print(f"\niki dagilimin ortalamasi da {ort(dogu):.3f}, standart sapmasi da {ss(dogu):.3f}")
print(f"ortalama - ortanca acikligi: gozlem {ort(dogu) - ortanca(dogu):.3f}, "
      f"model {ort(MODEL) - ortanca(MODEL):.3f}")
```

```
dagilim            en kucuk        C1   ortanca        C3  en buyuk       CAA  ortalama carpiklik
dogu (gozlem)          0.00     19.23     24.12     29.85     51.90     10.62    24.674     0.554
model (simetrik)       0.66     18.37     24.61     31.43     47.79     13.06    24.674     0.064

iki dagilimin ortalamasi da 24.674, standart sapmasi da 9.198
ortalama - ortanca acikligi: gozlem 0.554, model 0.064
```

İki satır aynı iki sayıyla raporlanır. Ortalama üçüncü basamağa kadar aynıdır, standart sapma
da öyle. "Doğu bölgesinde ortalama tüketim 24,674 m³, standart sapma 9,198" cümlesi her ikisi
için de doğrudur ve ikisini birbirinden ayırmaz.

Beş sayı özeti ayırıyor. Gözlemin en küçük değeri 0,00, modelinki 0,66'dır. Gözlemin üçüncü
çeyreği 29,85, modelinki 31,43'tür. Asıl fark çeyrekler açıklığında: gözlemde 10,62, modelde
13,06. Aynı standart sapmayı veren iki dağılımdan birinin orta yarısı belirgin biçimde daha
dar. Bunun anlamı şudur: gözlemin standart sapmasını büyüten şey ortadaki dağınıklık değil,
uçlardaki birkaç değerdir.

Son sütun ölçüyü tek sayıya indiriyor. Çarpıklık gözlemde 0,554, modelde 0,064 — sekiz kattan
fazla. Simetrik bir dağılımda ortalama ile ortancanın örtüşmesi beklenir ve model bunu
yapıyor; kalan 0,064 çekilişten gelen artıktır. Gözlemde açıklık artık değildir, dağılımın
kendi biçimidir.

#### Biçim Sayı Olarak

```python
# aralik.py — dagilimin bicimi sayi olarak basilir: her aralikta kac deger var.
# Grafik cizilmez; aralik genisligi bir karardir ve bicimi degistirir.
def sayim(v: list[float], genislik: int, ust: int = 55) -> list[int]:
    k = [0] * (ust // genislik)
    for x in v:
        k[min(int(x // genislik), len(k) - 1)] += 1
    return k


GEN = 5
a5, m5 = sayim(dogu, GEN), sayim(MODEL, GEN)
print(f"{'aralik':>12}{'dogu':>8}{'model':>8}   dogu cubugu")
for i, (x, y2) in enumerate(zip(a5, m5)):
    print(f"[{i * GEN:2d},{(i + 1) * GEN:2d})".rjust(12) + f"{x:8d}{y2:8d}   "
          + "#" * round(x / 4))
a10 = sayim(dogu, 2 * GEN)
print(f"\ngenislik {GEN}: ilk iki aralik {a5[0]} ve {a5[1]}; "
      f"genislik {2 * GEN}: ilk aralik {a10[0]}")
print(f"sifir yazilmis okuma {sum(1 for x in dogu if x == 0)}, "
      f"[{GEN},{2 * GEN}) araligindaki gercek okuma {a5[1]}")
```

```
      aralik    dogu   model   dogu cubugu
     [ 0, 5)      20       7   #####
     [ 5,10)       1      32
     [10,15)      35      51   #########
     [15,20)     111      83   ############################
     [20,25)     135     112   ##################################
     [25,30)     119      98   ##############################
     [30,35)      71      92   ##################
     [35,40)      35      57   #########
     [40,45)      16      23   ####
     [45,50)      11       2   ###
     [50,55)       3       0   #

genislik 5: ilk iki aralik 20 ve 1; genislik 10: ilk aralik 21
sifir yazilmis okuma 20, [5,10) araligindaki gercek okuma 1
```

Aralık sayımları beş sayının göremediğini gösteriyor. İlk aralıkta 20 değer, ikincisinde 1
değer var. Bu bir kuyruk değil, bir kopukluktur: sıfıra yığılmış 20 kayıt ile gerçek okuma
bölgesi arasında neredeyse boş bir aralık duruyor. Sayım bunu söylüyor, çünkü sıfıra yığılan
20 kayıt sayaç okunamadığı için sıfır yazılmış satırlardır; ölçülmüş bir tüketim değil, bir
kayıt biçimidir. Modelde böyle bir kopukluk yoktur: 7 ve 32 ardışık ve düzgün gider.

Aralık genişliği bir karardır ve bu kararı değiştirmek biçimi değiştirir. Genişlik 10
seçildiğinde ilk aralık 21 değer taşır; 20 ile 1 tek bir sayının içinde erir ve kopukluk
tabloda kaybolur. Aynı veri, aynı yordam, iki farklı biçim. Bu yüzden aralık genişliği
raporun içinde yazılır, dipnotta değil.

#### Aykırı Değer Elenmez, Ölçülür

```python
# aykiri.py — cit disindaki degerler burada ELENMEZ. Veri Toplama ve Hazirlama
# kursunda eleme bir temizleme karariydi; burada degerler kalir, etkisi olculur.
def cit(v: list[float]) -> tuple[float, float]:
    q1, q3 = ceyrek(v, 0.25), ceyrek(v, 0.75)
    caa = q3 - q1
    return q1 - 1.5 * caa, q3 + 1.5 * caa


C = [9, 6, 9, 9, 10, 10, 10, 10, 8]
k = lambda h: "".join(str(v).ljust(C[i]) if not i else str(v).rjust(C[i])
                      for i, v in enumerate(h))
print(k(["kume", "n", "alt cit", "ust cit", "alt asan", "ust asan", "ortalama",
         "cit ici", "fark"]))
kalan = {}
for ad, v in [("dogu", dogu), ("kuzey", kuzey), ("model", MODEL)]:
    alt, ust = cit(v)
    kalan[ad] = [x for x in v if alt <= x <= ust]
    print(k([ad, len(v), f"{alt:.2f}", f"{ust:.2f}",
             sum(1 for x in v if x < alt), sum(1 for x in v if x > ust),
             f"{ort(v):.3f}", f"{ort(kalan[ad]):.3f}",
             f"{ort(kalan[ad]) - ort(v):+.3f}"]))
print(f"\ndogu / kuzey farki: butun satirlarla {ort(dogu) - ort(kuzey):.3f} m3, "
      f"cit disi elenseydi {ort(kalan['dogu']) - ort(kalan['kuzey']):.3f} m3")
print(f"dogu standart sapmasi {ss(dogu):.3f} -> {ss(kalan['dogu']):.3f}, "
      f"ortancasi {ortanca(dogu):.2f} -> {ortanca(kalan['dogu']):.2f}")
```

```
kume          n  alt cit  ust cit  alt asan  ust asan  ortalama   cit ici    fark
dogu        557     3.30    45.78        20        10    24.674    25.154  +0.480
kuzey       921     2.41    37.96        32        18    20.210    20.532  +0.321
model       557    -1.22    51.02         0         0    24.674    24.674  +0.000

dogu / kuzey farki: butun satirlarla 4.463 m3, cit disi elenseydi 4.622 m3
dogu standart sapmasi 9.198 -> 7.416, ortancasi 24.12 -> 24.22
```

Çit dışındaki değerler burada silinmiyor; tablo yalnız silinseydi ne olacağını sayıyor.
Doğuda çit dışında 30 satır vardır ve bunların 20'si **alt** çitin dışındadır. Eleme
ortalamayı düşürmez, 24,674'ten 25,154'e **çıkarır**, çünkü elenen satırların çoğu sıfır
yazılmış okumalardır. Aykırı değeri "büyük değer" saymanın yanıltıcı olduğu yer burasıdır.

Aynı karar kuzeyde ortalamayı 0,321 m³ oynatır ve iki oynama aynı yöne gitmediği için bölge
farkı da değişir: 4,463 m³ yerine 4,622 m³. Önceki dersin ölçtüğü fark, hiçbir yeni veri
gelmeden, tek bir çit kararıyla 0,159 m³ kaymıştır. Bu, örneklemden gelen paydan ayrı ve ona
eklenen bir oynamadır.

Model satırı ölçünün ne olduğunu netleştiriyor. Simetrik dağılımda çit dışında **hiçbir**
değer yoktur ve eleme ortalamayı tam olarak yerinde bırakır. Çit dışı sayısı verinin
"hatalı" olmasının değil, dağılımın biçiminin bir sonucudur; 30 sayısı doğunun kuyruklarını
ölçer, kalitesini değil.

Son satır ortancanın niçin dirençli sayıldığını gösteriyor. Otuz satır çıkarıldığında standart
sapma 9,198'den 7,416'ya iner, yani yüzde 19,4 düşer; ortanca 24,12'den 24,22'ye, yani 0,10
oynar. Değişkenlik ölçüsü uçlara bağlıdır, sıralama ölçüsü değildir.

#### Özet

- Bir sütun üç ölçüyle tarif edilir: doğu için ortalama 24,674 m³, ortanca 24,12 m³ ve
  standart sapma 9,198; aradaki 0,554 m³'lük açıklık biçim hakkındaki ilk işarettir.
- Aynı ortalamayı ve aynı standart sapmayı veren simetrik model dağılım, beş sayı özetinde
  ayrışır: çeyrekler açıklığı 10,62'ye karşı 13,06, çarpıklık 0,554'e karşı 0,064.
- Aralık sayımları beş sayının göremediğini verir: gözlemde ilk aralıkta 20, ikincisinde 1
  değer bulunur ve bu kopukluk sıfır yazılmış okumalardan gelir.
- Aralık genişliği bir karardır: genişlik 10 seçildiğinde ilk aralık 21 olur ve kopukluk
  tabloda görünmez.
- Çit dışındaki 30 satır elenmez; eleme doğu ortalamasını 25,154'e, doğu ile kuzey arasındaki
  farkı 4,463'ten 4,622 m³'e taşırdı ve standart sapmayı yüzde 19,4 düşürürdü.

#### Sonraki Adım

Bu ders tek bir sütuna baktı ve o sütunun biçimini sayıyla yazdı. Kümedeki soruların çoğu ise
tek sütunla cevaplanmaz: tüketim ile hane büyüklüğü birlikte mi artıyor, tarife basamağı ile
bölge arasında bir bağ var mı, memnuniyet düzeyi tüketimle nasıl ilişkileniyor. İki sütunun
birlikte incelenmesi yeni bir özet getirir — korelasyon katsayısı — ve o katsayı da tıpkı
ortalama gibi tek bir sayıya sıkıştırır. Sonraki ders iki değişkenli incelemeyi ele alır:
aynı katsayıyı veren iki farklı ilişki kurulur, çapraz tablo katsayının göremediğini gösterir
ve sıralayıcı ölçekte niçin sıra korelasyonunun doğru ölçüt olduğu yazılır.

### İki Değişkenli İnceleme

Source: https://academia.sh/tr/kurslar/kesifsel-analiz/iki-degiskenli-inceleme

Tüketim sütunu dört sütunla eşleştirilir ve her katsayının yanına payı basılır: hane kişi sayısıyla +0,010 ve memnuniyetle −0,010 katsayıları 2.000 karıştırmanın 1.189 ve 1.154'ünde aşılır, dönem sırasıyla çıkan −0,111 hiçbirinde aşılmaz, tarife basamağıyla çıkan +0,883 ise bir keşif değil bir tanımdır. Aynı +0,600 katsayısını veren üç kurgu ilişki yan yana konur: doğrusal olanın dilim ortalamaları 6,6'dan 24,9'a düzgün çıkar, eğrisel olanınki 39,8'e çıkıp 37,1'e döner, kaldıraçlı olanınki 20 civarında sabit kalır ve tek bir uç nokta çıkarıldığında katsayı −0,057'ye iner. Bölge ile tarife basamağının çapraz tablosu batıda dördüncü basamağın hiç görünmediğini, doğuda küme payının üç katına çıktığını sayar. Sıralayıcı ölçekte kodlama değiştiğinde katsayı memnuniyette mutlak değerce yüzde 79 oynar, sıra korelasyonu −0,0102'de durur.

Önceki ders tek bir sütuna baktı ve biçimini beş sayı ile aralık sayımlarıyla yazdı.
Soruların çoğu ise iki sütun ister: tüketim hane büyüklüğüyle birlikte mi artıyor, dönem
ilerledikçe düşüyor mu, memnuniyet düzeyiyle bir bağı var mı. İki sütun birlikte
incelendiğinde yeni bir özet çıkar — korelasyon katsayısı — ve o da bir yığın sayıyı tek
sayıya sıkıştırır.

Bu dersin ölçüsü **katsayının göremediği örüntüdür**. Aynı katsayıyı veren üç ayrı ilişki
kurulur, üçü de aynı sayıyla raporlanır ve aradaki farkın katsayıya hiç yansımadığı
gösterilir.

- **EA11.** İki değişkenli inceleme (bivariate) iki sütunu birlikte ele alır. **Korelasyon
  katsayısı** ortak değişimin iki ayrı değişimin çarpımına oranıdır ve yalnızca **doğrusal**
  birlikte değişimi ölçer.
- **EA12.** Katsayının yanına payı yazılır: sütunlardan biri rastgele yeniden dizilir ve aynı
  büyüklükte bir katsayının kaç koşumda bir ortaya çıktığı sayılır.
- **EA13.** Katsayı **saçılım grafiğinin (scatter plot)** yerini tutmaz. Saçılım burada
  çizilmez, **dilim ortalamalarıyla** basılır: sürücü sütun beş eşit parçaya bölünür ve her
  parçada ikinci sütunun ortalaması yazılır.
- **EA14. Çapraz tablo (cross tabulation)** iki kategorik sütunun birlikte sayımıdır.
  Sınıflayıcı ölçekte korelasyon katsayısı tanımlı değildir; ilişki hücre sayımlarından
  okunur.
- **EA15. Sıra korelasyonu** yalnızca sıraya bakar. Sıralayıcı ölçekte düzeylere verilen
  sayılar bir kodlama kararıdır — ölçek tanımları Veri Analitiğine Giriş kursunda kuruldu ve
  burada tekrarlanmaz. Katsayı bu karardan etkilenir, sıra korelasyonu etkilenmez.

#### Katsayı ve Payı

```python

# kesif.py — MODELDIR: K03 ve K04'un kurgu olcum agi ayni tohumla yeniden
# uretilir. Kume kurgudur; hicbir gercek abone, sayac ya da bolge temsil edilmez.
import math

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


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

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


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


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

OKUMA = []
for k in _abone + _elenen:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp(
            (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100
        if k["abone_no"] not in _gecerli:
            r()
            continue
        OKUMA.append({"abone_no": k["abone_no"], "bolge": k["bolge"],
                      "donem": DONEM[d], "tuketim_m3": t, "hane_kisi": k["hane_kisi"],
                      "memnuniyet": k["memnuniyet"],
                      "basamak": 1 if t < TARIFE[0] else 2 if t < TARIFE[1]
                      else 3 if t < TARIFE[2] else 4})
        r()

def ort(v: list[float]) -> float:
    return sum(v) / len(v)


def kor(x: list[float], y: list[float]) -> float:
    """Korelasyon katsayisi: ortak degisimin iki ayri degisimin carpimina orani."""
    mx, my = ort(x), ort(y)
    sx = math.sqrt(sum((a - mx) ** 2 for a in x))
    sy = math.sqrt(sum((b - my) ** 2 for b in y))
    return sum((a - mx) * (b - my) for a, b in zip(x, y)) / (sx * sy)


def siralar(v: list[float]) -> list[float]:
    """Esit degerler ortalama sira alir; siralayici olcegin gerektirdigi budur."""
    yer: dict[float, list[int]] = {}
    for k, i in enumerate(sorted(range(len(v)), key=lambda j: v[j])):
        yer.setdefault(v[i], []).append(k + 1)
    return [ort(yer[x]) for x in v]


def sira_kor(x: list[float], y: list[float]) -> float:
    return kor(siralar(x), siralar(y))


KOSUM = 2000
ESIK = 1e-9  # ayni katsayi iki yoldan hesaplaninca son basamak oynar


def kor_payi(x: list[float], y: list[float], tohum: int) -> tuple[int, float]:
    """y sutunu rastgele yeniden dizilir, katsayi her kosumda yeniden olculur."""
    r, gozlenen = uretec(tohum), kor(x, y)
    mx, my = ort(x), ort(y)
    bol = math.sqrt(sum((a - mx) ** 2 for a in x) * sum((b - my) ** 2 for b in y))
    dx, dy = [a - mx for a in x], [b - my for b in y]
    asan, en_uc = 0, 0.0
    for _ in range(KOSUM):
        h = dy[:]
        for i in range(len(h) - 1, 0, -1):
            j = int(r() * (i + 1))
            h[i], h[j] = h[j], h[i]
        c = sum(a * b for a, b in zip(dx, h)) / bol
        asan += abs(c) >= abs(gozlenen) - ESIK
        en_uc = max(en_uc, abs(c))
    return asan, en_uc


TUKETIM = [o["tuketim_m3"] for o in OKUMA]
CIFT = [("hane_kisi", [o["hane_kisi"] for o in OKUMA]),
        ("memnuniyet", [o["memnuniyet"] for o in OKUMA]),
        ("donem sirasi", [DONEM.index(o["donem"]) for o in OKUMA]),
        ("basamak", [o["basamak"] for o in OKUMA])]
def hiza(w: list[int], sol: int = 1):
    """Ilk `sol` sutun sola, kalanlar saga yaslanir."""
    return lambda h: "".join(str(v).ljust(w[i]) if i < sol else str(v).rjust(w[i])
                             for i, v in enumerate(h))


y = hiza([26, 7, 11, 12, 10, 8])
print(y(["cift", "n", "katsayi", "sira kats.", "en uc", "asan"]))
for i, (ad, v) in enumerate(CIFT):
    asan, en_uc = kor_payi(TUKETIM, v, TOHUM + 710 + i)
    print(y([f"tuketim / {ad}", len(v), f"{kor(TUKETIM, v):+.3f}",
             f"{sira_kor(TUKETIM, v):+.3f}", f"{en_uc:.3f}", asan]))
print(f"\n{KOSUM} kosum; en uc = karistirilmis kumelerde gorulen en buyuk katsayi")
```

```
cift                            n    katsayi  sira kats.     en uc    asan
tuketim / hane_kisi          3199     +0.010      +0.014     0.069    1189
tuketim / memnuniyet         3199     -0.010      -0.010     0.058    1154
tuketim / donem sirasi       3199     -0.111      -0.113     0.061       0
tuketim / basamak            3199     +0.883      +0.813     0.065       0

2000 kosum; en uc = karistirilmis kumelerde gorulen en buyuk katsayi
```

Yalnız katsayı sütununa bakılırsa ilk iki satır "zayıf ama var olan bir ilişki" gibi
okunabilir: +0,010 ve −0,010 sıfır değildir. Pay sütunu bunu kapatıyor. Karıştırılmış kümeler
bu büyüklükte bir katsayıyı 2.000 koşumun 1.189'unda ve 1.154'ünde üretiyor. İki satır da
gürültüdür.

Üçüncü satır ters yöne gidiyor. Dönem sırası ile tüketim arasındaki −0,111 de küçüktür, ama
karıştırılmış kümelerde görülen en büyük katsayı 0,061'dir ve 2.000 koşumun hiçbiri gözlenene
ulaşmıyor. Söyleyen şey katsayının büyüklüğü değil, karıştırma dağılımına göre nerede
durduğudur.

Dördüncü satır payın da tek başına yetmediğini gösteriyor. Tarife basamağı ile tüketim
arasındaki katsayı +0,883'tür ve payı sıfırdır, ama basamak tüketimden hesaplanır: 10, 25 ve
40 m³ sınırları onu belirler. Katsayı burada bir keşfi değil bir tanımı ölçüyor.

#### Aynı Katsayı, Üç Ayrı İlişki

```python
# ayni_katsayi.py — KURGU: ayni katsayiyi veren uc ayri iliski. Serbest parametre
# (gurultu agirligi, uc noktanin uzakligi) hedefe ikiye bolerek oturtulur.
N, HEDEF = 557, 0.600


def surucu(tohum: int):
    r = uretec(tohum)
    return ([round(4 + 16 * r(), 2) for _ in range(N)],
            [r() + r() + r() - 1.5 for _ in range(N)])


def ayarla(f, ust: float) -> float:
    """f(p) katsayiyi verir ve p ile tek yonlu degisir; hedefe ikiye bolunerek yaklasilir."""
    alt, artan = 0.0, f(ust) > f(0.0)
    for _ in range(50):
        o = (alt + ust) / 2
        if (f(o) < HEDEF) == artan:
            alt = o
        else:
            ust = o
    return (alt + ust) / 2


def karistir(x, taban, gurultu):
    w = ayarla(lambda p: kor(x, [t + p * g for t, g in zip(taban, gurultu)]), 200.0)
    return [round(t + w * g, 2) for t, g in zip(taban, gurultu)]


x1, g1 = surucu(TOHUM + 801)
y1 = karistir(x1, [1.4 * a for a in x1], g1)
x2, g2 = surucu(TOHUM + 802)
y2 = karistir(x2, [-0.16 * (a - 14.0) ** 2 + 40 for a in x2], g2)  # 14 m3'te tepe

r3 = uretec(TOHUM + 803)
x3 = [round(4 + 16 * r3(), 2) for _ in range(N - 1)]
y3 = [round(20 + 9 * (r3() + r3() + r3() - 1.5), 2) for _ in range(N - 1)]
uzak = ayarla(lambda k: kor(x3 + [20 + k], y3 + [20 + 3 * k]), 400.0)
x3, y3 = x3 + [round(20 + uzak, 2)], y3 + [round(20 + 3 * uzak, 2)]


def dilim_ort(x: list[float], y: list[float], d: int = 5) -> list[float]:
    s = sorted(zip(x, y))
    return [ort([b for _, b in s[i * len(s) // d:(i + 1) * len(s) // d]])
            for i in range(d)]


i_ = hiza([13, 11, 12])
print(i_(["iliski", "katsayi", "sira kats."]) + "   dilim ortalamalari (y)")
for ad, x, y in [("dogrusal", x1, y1), ("egrisel", x2, y2), ("kaldiracli", x3, y3)]:
    print(i_([ad, f"{kor(x, y):+.3f}", f"{sira_kor(x, y):+.3f}"]) + "   "
          + " ".join(f"{v:5.1f}" for v in dilim_ort(x, y)))
print(f"\nkaldiracli iliskide uc nokta ({x3[-1]}, {y3[-1]}); kalan {N - 1} noktanin "
      f"x araligi 4-20")
print(f"o tek nokta cikarilinca katsayi {kor(x3[:-1], y3[:-1]):+.3f} olur")
```

```
iliski           katsayi  sira kats.   dilim ortalamalari (y)
dogrusal          +0.600      +0.594     6.6  12.6  15.4  21.4  24.9
egrisel           +0.600      +0.559    27.8  34.9  38.8  39.8  37.1
kaldiracli        +0.600      -0.052    20.1  20.0  19.9  19.4  21.7

kaldiracli iliskide uc nokta (104.4, 273.2); kalan 556 noktanin x araligi 4-20
o tek nokta cikarilinca katsayi -0.057 olur
```

Üç ilişkinin katsayısı üçüncü basamağa kadar aynıdır ve "korelasyon katsayısı +0,600"
cümlesi üçünü birbirinden ayırmaz. Ayıran şey son sütundur: sürücü sütun beş dilime bölünüp
her dilimde ikinci sütunun ortalaması yazıldığında üç ayrı örüntü çıkıyor.

Doğrusal ilişkide dilim ortalamaları 6,6'dan 24,9'a düzgün tırmanıyor. Eğrisel ilişkide
27,8'den 39,8'e çıkıp 37,1'e dönüyor: ikinci sütun bir yere kadar artıyor, sonra azalıyor.
Katsayı bu dönüşü göremez, çünkü doğrusal birlikte değişimi ölçer ve dönüşün iki yanı
birbirini kısmen götürür. Sıra korelasyonu da göremiyor; 0,559 ile 0,594 arasındaki fark tek
başına uyarı sayılmaz.

Üçüncü satır en sert olanıdır. Dilim ortalamaları 20,1 — 20,0 — 19,9 — 19,4 çizgisinde
duruyor, son dilimde 21,7'ye sıçrıyor: bir eğilim değil, tek bir noktanın izi. Katsayıyı o
nokta taşıyor — 556 nokta 4 ile 20 arasında dururken biri (104,4, 273,2) konumundadır — ve o
nokta çıkarıldığında katsayı −0,057'ye iner.
Sıra korelasyonu bunu baştan söylüyor, çünkü sıralama bir noktanın uzaklığını umursamaz.

Ölçünün özeti şudur: katsayı iki boyutlu bir biçimi tek sayıya indirir ve neyi indirdiğini
söylemez; beş dilim ortalaması üç ilişkiyi de ayırır.

#### Kategorik ve Sıralayıcı Sütunlar

```python
# kategorik.py — capraz tablo iki kategorik sutunu birlikte sayar; bolge
# siniflayici bir olcektir ve korelasyon katsayisi bu cift icin tanimli degildir.
from collections import Counter

hucre = Counter((o["bolge"], o["basamak"]) for o in OKUMA)
BOLGELER = sorted({o["bolge"] for o in OKUMA})
KADEME = [1, 2, 3, 4]
c = hiza([9, 6] + [6] * 4 + [7] * 4)
print(c(["bolge", "n"] + [f"b{k}" for k in KADEME] + [f"%b{k}" for k in KADEME]))
for b in BOLGELER + ["kume"]:
    say = [sum(hucre[(x, k)] for x in (BOLGELER if b == "kume" else [b]))
           for k in KADEME]
    print(c([b, sum(say)] + say + [f"{100 * s / sum(say):.1f}" for s in say]))

# Siralayici olcekte duzeylere verilen sayilar bir karardir: kodlama degisince
# katsayi degisir, sira korelasyonu yalnizca siraya baktigi icin degismez.
SUTUN = [("basamak", [o["basamak"] for o in OKUMA],
          [("esit aralik", {1: 1, 2: 2, 3: 3, 4: 4}),
           ("ikiye katlanan", {1: 1, 2: 2, 3: 4, 4: 8}),
           ("basamak orta noktasi", {1: 5.0, 2: 17.5, 3: 32.5, 4: 45.0})]),
         ("memnuniyet", [o["memnuniyet"] for o in OKUMA],
          [("esit aralik", {d: d for d in range(1, 6)}),
           ("ikiye katlanan", {1: 1, 2: 2, 3: 4, 4: 8, 5: 16})])]
o_ = hiza([13, 23, 12, 12], 2)
print("\n" + o_(["sutun", "kodlama", "katsayi", "sira kats."]))
for ad_s, sut, kodlar in SUTUN:
    k = [kor(TUKETIM, [m[d] for d in sut]) for _, m in kodlar]
    for (ad, m), deger in zip(kodlar, k):
        print(o_([ad_s, ad, f"{deger:+.4f}",
                  f"{sira_kor(TUKETIM, [m[d] for d in sut]):+.4f}"]))
    oynama = 100 * (max(map(abs, k)) / min(map(abs, k)) - 1)
    print(f"{ad_s}: katsayi mutlak degerde {oynama:.0f} yuzde oynadi, "
          f"sira korelasyonu oynamadi")
```

```
bolge         n    b1    b2    b3    b4    %b1    %b2    %b3    %b4
bati        476    88   377    11     0   18.5   79.2    2.3    0.0
dogu        557    21   281   225    30    3.8   50.4   40.4    5.4
guney       645    59   538    48     0    9.1   83.4    7.4    0.0
kuzey       921    42   661   210     8    4.6   71.8   22.8    0.9
merkez      600    30   352   198    20    5.0   58.7   33.0    3.3
kume       3199   240  2209   692    58    7.5   69.1   21.6    1.8

sutun        kodlama                     katsayi  sira kats.
basamak      esit aralik                 +0.8832     +0.8125
basamak      ikiye katlanan              +0.8417     +0.8125
basamak      basamak orta noktasi        +0.8800     +0.8125
basamak: katsayi mutlak degerde 5 yuzde oynadi, sira korelasyonu oynamadi
memnuniyet   esit aralik                 -0.0103     -0.0102
memnuniyet   ikiye katlanan              -0.0184     -0.0102
memnuniyet: katsayi mutlak degerde 79 yuzde oynadi, sira korelasyonu oynamadi
```

Bölge sınıflayıcı bir ölçektir: kuzey ile doğu arasında sıra yoktur ve korelasyon katsayısı
hesaplanamaz. İlişki hücre sayımlarından okunur. Batıda 476 satırın yüzde 79,2'si ikinci
basamaktadır, dördüncü basamakta **hiç** satır yoktur; doğuda 557 satırın yüzde 5,4'ü
dördüncü basamaktadır. Küme genelinde bu pay yüzde 1,8'dir, yani doğunun payı üç katına
yakındır.

Tablonun kendi payı hücre sayımlarında görünür. Kuzeyin dördüncü basamağında 8, batının
üçüncüsünde 11 satır vardır; 8 satırlık bir hücrede tek bir satır oranı sekizde bir kadar
oynatır. Yüzdenin yanında kaç gözleme dayandığı yazılmadıkça tablo okunamaz.

Alt tablo sıralayıcı ölçeğin kararını ölçüyor. Tarife basamağı 1, 2, 3, 4 diye
numaralandırılabilir; ikiye katlanan bir dizi de, basamakların orta noktaları da aynı
sıralamayı verir. Katsayı yine de 0,8832 — 0,8417 — 0,8800 olarak değişir. Memnuniyette etki
daha büyüktür: mutlak değerce yüzde 79. Sıra korelasyonu iki sütunda da yerinde kalır.

Nedeni ölçeğin tanımındadır. Sıralayıcı ölçekte düzeyler arasındaki **uzaklık
ölçülmemiştir**, yalnızca sıra bilinir. Katsayı düzey sayılarını çarptığı için birinci ile
ikinci basamak arasındaki açıklığı üçüncü ile dördüncü arasındakine eşit sayar; ölçek bunu
desteklemez. Sıra korelasyonu kodlamadan bağımsızdır.

#### Özet

- Katsayı payıyla okunur: +0,010 ve −0,010 katsayıları 2.000 karıştırmanın 1.189 ve
  1.154'ünde aşılır, −0,111 hiçbirinde aşılmaz; büyüklük tek başına ayırt etmez.
- Payı sıfır olan katsayı da bulgu olmayabilir: +0,883, basamak tüketimden hesaplandığı için
  bir tanımı ölçer.
- Aynı +0,600 katsayısını veren üç ilişki dilim ortalamalarıyla ayrışır: 6,6'dan 24,9'a artış,
  39,8'e çıkıp 37,1'e dönen eğri ve 20 civarında düz çizgi.
- Kaldıraçlı ilişkide katsayıyı tek bir nokta taşır; o nokta çıkınca katsayı −0,057'ye iner.
- Sıralayıcı ölçekte kodlama katsayıyı oynatır — memnuniyette mutlak değerce yüzde 79 — sıra
  korelasyonu oynamaz.

#### Sonraki Adım

Bu ders tek bir çifte baktı ve katsayısına payını yazdı. Gerçek bir kümede çift sayısı ikide
kalmaz: dört sayısal sütun altı çift, altı sütun on beş çift üretir. Her çifte ayrı bakmak her
seferinde yeni bir soru sormaktır ve sorular çoğaldıkça rastlantının en az birinde yüksek
katsayı üretme şansı büyür. Sonraki ders korelasyon matrisini kurar, tümüyle bağımsız
üretilmiş sütunlarda kaç çiftin yüksek katsayı verdiğini sayar ve kaç bileşenin değişimin ne
kadarını taşıdığını hesaplar.

### Çok Değişkenli İnceleme

Source: https://academia.sh/tr/kurslar/kesifsel-analiz/cok-degiskenli-inceleme

Altı sütunluk bir korelasyon matrisi 15 çift taşır ve eşik dağılım tablosundan değil karıştırmadan gelir: 2.000 karıştırmada katsayı dağılımının yüzde 95'i 0,0354 çıkar ve 15 çiftin 5'i bu eşiği aşar — ama beşinden üçü tanım gereği, ikisi de abone numarası sütunu yüzünden aşar. Birbirinden tümüyle bağımsız üretilmiş sütunlarda çift sayısı 6'dan 190'a çıktığında eşiği aşan çift sayısı 0'dan 12'ye çıkar ve beklenen değer 9,5'tir; en yüksek katsayı 0,049 ile eşiğin belirgin üstündedir. Boyut azaltma tek soruya indirgenir: ölçüm ağı sütunlarında ilk iki bileşen değişimin yüzde 49,3'ünü, iki gizli sürücüden üretilen kümede yüzde 82,1'ini, bağımsız sütunlarda yalnız yüzde 35,0'ını taşır.

Önceki ders iki sütunu birlikte inceledi ve tek bir çiftin katsayısına payını yazdı. Gerçek
bir çözümlemede ise çiftler tek tek sorulmaz; bir tablo alınır ve bütün sayısal sütunların
katsayıları aynı anda hesaplanır. Altı sütun 15 çift üretir, yirmi sütun 190 çift. Her çift
ayrı bir sorudur ve her soru rastlantıya bir şans daha tanır.

Bu dersin ölçüsü **karşılaştırma sayısının ürettiği sahte ilişkidir**. Tümüyle bağımsız
üretilmiş sütunlarda kaç çiftin eşiği aştığı sayılır ve bu sayının sütun sayısıyla nasıl
büyüdüğü gösterilir. İkinci ölçü boyut azaltmanın kazancıdır ve tek bir soruya indirgenir:
kaç bileşen değişimin ne kadarını taşıyor.

- **EA16.** Çok değişkenli inceleme (multivariate) ikiden çok sütuna aynı anda bakar.
  $k$ sütunlu bir **korelasyon matrisi** $k(k-1)/2$ çift taşır; çift sayısı sütun sayısıyla
  karesel büyür.
- **EA17.** Matristeki her hücre ayrı bir sorudur. Tek bir çift için savunulabilir olan eşik,
  bütün çiftlere aynı anda uygulandığında **eşiği aşan çift sayısını** kendiliğinden büyütür.
- **EA18.** Eşik burada dağılım tablosundan değil **karıştırmadan** gelir: bir sütun kendi
  içinde 2.000 kez karıştırılır ve elde edilen katsayı dağılımının yüzde 95'i eşik alınır.
- **EA19. Boyut azaltma (dimensionality reduction)** bu derste tek bir soruyla geçer: **kaç
  bileşen değişimin ne kadarını taşıyor**. Yöntem seçimi, döndürme ve bileşenlerin yorumu
  yazılmaz.
- **EA20.** Bileşen payları **korelasyon matrisinin özdeğerlerinden** okunur; özdeğerlerin
  toplamı sütun sayısına eşittir ve pay olarak yazıldığında toplam 100 olur. Sütunlar
  birbirini tekrarlamıyorsa paylar eşite yakın dağılır.

#### Matris ve Eşiği

```python

# kesif.py — MODELDIR: K03 ve K04'un kurgu olcum agi ayni tohumla yeniden
# uretilir. Kume kurgudur; hicbir gercek abone, sayac ya da bolge temsil edilmez.
import math

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


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

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


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


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

OKUMA = []
for k in _abone + _elenen:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp(
            (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100
        if k["abone_no"] not in _gecerli:
            r()
            continue
        OKUMA.append({"abone_no": k["abone_no"], "bolge": k["bolge"],
                      "donem": DONEM[d], "tuketim_m3": t, "hane_kisi": k["hane_kisi"],
                      "memnuniyet": k["memnuniyet"],
                      "basamak": 1 if t < TARIFE[0] else 2 if t < TARIFE[1]
                      else 3 if t < TARIFE[2] else 4})
        r()

def ort(v: list[float]) -> float:
    return sum(v) / len(v)


def kor(x: list[float], y: list[float]) -> float:
    mx, my = ort(x), ort(y)
    sx = math.sqrt(sum((a - mx) ** 2 for a in x))
    sy = math.sqrt(sum((b - my) ** 2 for b in y))
    return sum((a - mx) * (b - my) for a, b in zip(x, y)) / (sx * sy)


def hiza(w: list[int], sol: int = 1):
    """Ilk `sol` sutun sola, kalanlar saga yaslanir."""
    return lambda h: "".join(str(v).ljust(w[i]) if i < sol else str(v).rjust(w[i])
                             for i, v in enumerate(h))


SUTUN = [("tuketim", [o["tuketim_m3"] for o in OKUMA]),
         ("basamak", [float(o["basamak"]) for o in OKUMA]),
         ("hane_kisi", [float(o["hane_kisi"]) for o in OKUMA]),
         ("memnuniyet", [float(o["memnuniyet"]) for o in OKUMA]),
         ("donem", [float(DONEM.index(o["donem"])) for o in OKUMA]),
         ("abone_no", [float(o["abone_no"]) for o in OKUMA])]
K = len(SUTUN)
m = hiza([12] + [11] * K)
print(m(["sutun"] + [a[:9] for a, _ in SUTUN]))
for i, (ad, x) in enumerate(SUTUN):
    print(m([ad] + [f"{kor(x, y):+.3f}" for _, y in SUTUN[:i + 1]]))

KOSUM = 2000


def esik_95(x: list[float], tohum: int) -> float:
    """Sutun kendi kendine karistirilir; |katsayi| dagiliminin yuzde 95'i esiktir."""
    r, n = uretec(tohum), len(x)
    mx = ort(x)
    d = [a - mx for a in x]
    kare = sum(a * a for a in d)
    deger = []
    for _ in range(KOSUM):
        h = d[:]
        for i in range(n - 1, 0, -1):
            j = int(r() * (i + 1))
            h[i], h[j] = h[j], h[i]
        deger.append(abs(sum(a * b for a, b in zip(d, h)) / kare))
    return sorted(deger)[int(0.95 * KOSUM)]


ESIK = esik_95(SUTUN[0][1], TOHUM + 901)
cift = [(SUTUN[i][0], SUTUN[j][0], kor(SUTUN[i][1], SUTUN[j][1]))
        for i in range(K) for j in range(i + 1, K)]
asan = [c for c in cift if abs(c[2]) >= ESIK]
print(f"\n{K} sutun, {len(cift)} cift; {KOSUM} karistirmada |katsayi| dagiliminin "
      f"yuzde 95'i {ESIK:.4f}")
print(f"esigi asan cift: {len(asan)} / {len(cift)}")
for a, b, v in sorted(asan, key=lambda c: -abs(c[2])):
    print(f"  {a} / {b}: {v:+.3f}")
```

```
sutun           tuketim    basamak  hane_kisi  memnuniye      donem   abone_no
tuketim          +1.000
basamak          +0.883     +1.000
hane_kisi        +0.010     +0.007     +1.000
memnuniyet       -0.010     -0.015     -0.004     +1.000
donem            -0.111     -0.116     +0.000     -0.006     +1.000
abone_no         +0.031     +0.041     +0.046     -0.001     -0.005     +1.000

6 sutun, 15 cift; 2000 karistirmada |katsayi| dagiliminin yuzde 95'i 0.0354
esigi asan cift: 5 / 15
  tuketim / basamak: +0.883
  basamak / donem: -0.116
  tuketim / donem: -0.111
  hane_kisi / abone_no: +0.046
  basamak / abone_no: +0.041
```

Altı sütun 15 çift üretti ve eşik 0,0354 çıktı. Eşik bir tablodan okunmadı: tüketim sütunu
kendi içinde 2.000 kez karıştırıldı, her koşumda katsayı yeniden hesaplandı ve elde edilen
dağılımın yüzde 95'i eşik olarak alındı. Bu eşiğin anlamı dardır ve tam olarak şudur — hiçbir
ilişki yokken, **tek bir çiftte**, yüz koşumun beşinde bu büyüklükte bir katsayı görülür.

Eşiği aşan beş çift var, ama beşi de aynı türden değil. Tüketim ile basamak arasındaki
+0,883 bir keşif değil bir tanımdır; basamak 10, 25 ve 40 m³ sınırlarıyla tüketimden
hesaplanır. Basamak ile dönem arasındaki −0,116, tüketim ile dönem arasındaki −0,111'in
aynısıdır, çünkü basamak tüketimin bir yeniden yazımıdır — iki satır aynı olguyu iki kez
sayar. Geriye abone numarasını içeren iki çift kalır: abone numarası bir kayıt numarasıdır,
hiçbir şeyin nedeni olamaz.

On beş çiftten beşi eşiği aştı ve rapora girecek bağımsız bulgu sayısı en fazla birdir.
Matris kendisi bir bulgu üretmez; sorulacak soruların sayısını büyütür ve büyüdükçe eşiği
aşan hücre bulmak kolaylaşır.

#### Çift Sayısı Bulgu Üretir

```python
# cokluk.py — KURGU: birbiriyle hicbir ilgisi olmayan sutunlar uretilir ve ayni
# esik butun ciftlere uygulanir. Aranan sey, esigi asan cift sayisidir.
def bagimsiz(k: int, n: int, tohum: int) -> list[list[float]]:
    r = uretec(tohum)
    return [[r() + r() + r() for _ in range(n)] for _ in range(k)]


BAGIMSIZ = bagimsiz(20, len(OKUMA), TOHUM + 902)
_m = [ort(s) for s in BAGIMSIZ]
_d = [[a - t for a in s] for s, t in zip(BAGIMSIZ, _m)]
_n = [math.sqrt(sum(a * a for a in s)) for s in _d]
ikili = lambda i, j: sum(a * b for a, b in zip(_d[i], _d[j])) / (_n[i] * _n[j])

g = hiza([8, 8, 12, 12, 12])
print(g(["sutun", "cift", "esigi asan", "beklenen", "en buyuk"]) + "   en buyuk cift")
for k in (4, 6, 8, 12, 20):
    ciftler = [(i, j) for i in range(k) for j in range(i + 1, k)]
    deger = {(i, j): abs(ikili(i, j)) for i, j in ciftler}
    enb = max(deger, key=deger.get)
    print(g([k, len(ciftler), sum(1 for v in deger.values() if v >= ESIK),
             f"{0.05 * len(ciftler):.1f}", f"{deger[enb]:.3f}"])
          + f"   sutun{enb[0] + 1} / sutun{enb[1] + 1}")
print(f"\nesik {ESIK:.4f}; sutunlarin hicbiri digerinden turetilmemistir")
```

```
sutun       cift  esigi asan    beklenen    en buyuk   en buyuk cift
4              6           0         0.3       0.021   sutun1 / sutun2
6             15           1         0.8       0.037   sutun2 / sutun6
8             28           2         1.4       0.048   sutun1 / sutun8
12            66           5         3.3       0.049   sutun6 / sutun12
20           190          12         9.5       0.049   sutun6 / sutun12

esik 0.0354; sutunlarin hicbiri digerinden turetilmemistir
```

Bu tablodaki sütunların hiçbiri diğerinden türetilmemiştir; hepsi ayrı çekilişlerden gelir
ve aralarında hiçbir ilişki yoktur. Buna rağmen dört sütunda 0, altı sütunda 1, sekiz
sütunda 2, yirmi sütunda **12** çift eşiği aşıyor.

Sayının nereden geldiği eşiğin tanımında yazılı. Eşik, tek bir çiftte yüz koşumun beşinde
aşılan değerdir; 190 çifte aynı eşik uygulanınca yaklaşık 190 × 0,05 = 9,5 çiftin aşması
beklenir. Gözlenen 12, beklenen 9,5'in yakınındadır. Yani eşiği aşan çiftler bir kusur
değil, eşiğin kendi tanımının doğrudan sonucudur.

Tehlike, bu tablodan tek bir satırın çekilip alınmasındadır. "Altıncı ve on ikinci sütun
arasında 0,049'luk bir ilişki bulundu, eşik 0,0354" cümlesi doğru sayılar içerir ve tümüyle
uydurmadır: o çift 190 çift arasından **en büyüğü olduğu için** seçilmiştir. Bir katsayının
yanında yalnız payı değil, **kaç çift arasından seçildiği** de yazılmak zorundadır. "Tek
çiftten biri" ile "190 çiftten en büyüğü" aynı cümle değildir.

Karşılaştırma sayısını küçültmenin bir yolu da eşiği yükseltmek değil, **sütun sayısını**
düşürmektir. Bu, sonraki bölümün konusudur.

#### Kaç Bileşen

```python
# bilesen.py — boyut azaltmanin tek sorusu: kac bilesen degisimin ne kadarini
# tasiyor. Paylar korelasyon matrisinin ozdegerlerinden okunur.
def ozdeger(A: list[list[float]]) -> list[float]:
    """Simetrik matrisin ozdegerleri: kose disi en buyuk oge sifira inene dek dondurulur."""
    n, M = len(A), [s[:] for s in A]
    for _ in range(200):
        p, q, en = 0, 1, 0.0
        for i in range(n):
            for j in range(i + 1, n):
                if abs(M[i][j]) > en:
                    p, q, en = i, j, abs(M[i][j])
        if en < 1e-12:  # kose disi ogeler bu esigin altina inince donme durur
            break
        th = (M[q][q] - M[p][p]) / (2 * M[p][q])
        t = (1.0 if th >= 0 else -1.0) / (abs(th) + math.sqrt(th * th + 1))
        c = 1 / math.sqrt(t * t + 1)
        s = t * c
        for k in range(n):
            kp, kq = M[k][p], M[k][q]
            M[k][p], M[k][q] = c * kp - s * kq, s * kp + c * kq
        for k in range(n):
            pk, qk = M[p][k], M[q][k]
            M[p][k], M[q][k] = c * pk - s * qk, s * pk + c * qk
    return sorted((M[i][i] for i in range(n)), reverse=True)


def ortak_surucu(tohum: int) -> list[list[float]]:
    """KURGU: alti sutun iki gizli surucuden ve gurultuden uretilir."""
    r = uretec(tohum)
    f1 = [r() + r() + r() - 1.5 for _ in range(len(OKUMA))]
    f2 = [r() + r() + r() - 1.5 for _ in range(len(OKUMA))]
    AGIRLIK = [(1.0, 0.0), (0.9, 0.2), (0.8, 0.3), (0.1, 1.0), (0.2, 0.9), (0.3, 0.8)]
    return [[a * x + b * y + 0.55 * (r() + r() + r() - 1.5) for x, y in zip(f1, f2)]
            for a, b in AGIRLIK]


KUME = [("olcum agi", [x for _, x in SUTUN]),
        ("ortak surucu", ortak_surucu(TOHUM + 903)),
        ("bagimsiz", bagimsiz(6, len(OKUMA), TOHUM + 904))]
b = hiza([14] + [9] * 6)
print(b(["kume"] + [f"b{i + 1}" for i in range(6)]) + "   ilk iki bilesen")
for ad, S in KUME:
    oz = ozdeger([[kor(a, c) for c in S] for a in S])
    toplam = sum(oz)
    print(b([ad] + [f"{100 * v / toplam:.1f}" for v in oz])
          + f"   {100 * (oz[0] + oz[1]) / toplam:.1f} yuzde")
print(f"\npaylarin toplami her satirda 100; ozdegerlerin toplami sutun sayisidir ({len(SUTUN)})")
```

```
kume                 b1       b2       b3       b4       b5       b6   ilk iki bilesen
olcum agi          31.9     17.4     16.7     16.2     15.9      1.9   49.3 yuzde
ortak surucu       55.2     26.9      4.9      4.7      4.3      4.0   82.1 yuzde
bagimsiz           17.8     17.2     16.7     16.4     16.3     15.5   35.0 yuzde

paylarin toplami her satirda 100; ozdegerlerin toplami sutun sayisidir (6)
```

Üç satır boyut azaltmanın ne zaman iş yaptığını gösteriyor. Ortak sürücüden üretilen kümede
altı sütun iki gizli değişkenden geliyor ve ilk iki bileşen değişimin yüzde 82,1'ini taşıyor;
altı sütun yerine iki sayı yazmak değişimin yüzde 17,9'unu bırakmak demektir. Bağımsız
sütunlarda paylar 17,8'den 15,5'e kadar neredeyse eşittir ve ilk iki bileşen yalnız yüzde
35,0 taşır: azaltılacak bir şey yoktur, çünkü sütunlar birbirini hiç tekrarlamaz.

Ölçüm ağı satırı ikisinin arasındadır. İlk bileşen yüzde 31,9 taşır, sonraki dördü ise 17,4
ile 15,9 arasında sıkışır. Asıl bilgi son sütundadır: altıncı bileşenin payı yüzde 1,9'a
düşmüştür. Bu düşüş bir tekrarın işaretidir ve tekrarın ne olduğu ilk tablodan bilinir —
tüketim ile basamak aynı şeyi iki kez yazar. Pay tablosu, hangi sütunların birbirini
tekrarladığını söylemez, ama **tekrar olup olmadığını** tek bakışta verir.

İki bölüm burada birleşiyor. Altı sütun 15 çift üretir; sütunlar iki bileşene indirilirse
çift sayısı 1'e iner. Boyut azaltmanın ölçülebilir kazancı budur: bakılacak hücre sayısını
düşürür ve böylece rastlantının eşiği aşma şansını da düşürür. Bedeli, bileşenlerin artık
"tüketim" ya da "hane kişi sayısı" gibi bir adı olmamasıdır. Yöntem seçimi ve bileşenlerin
yorumlanması bu dersin dışındadır.

#### Özet

- Altı sütunlu matris 15 çift taşır; eşik dağılım tablosundan değil karıştırmadan gelir ve
  2.000 koşumluk dağılımın yüzde 95'i olarak 0,0354 çıkar.
- Eşiği aşan beş çiftin üçü tanım gereği aşar (basamak tüketimden hesaplanır), ikisi abone
  numarası sütunundan gelir; bağımsız bulgu sayısı en fazla birdir.
- Birbiriyle hiç ilgisi olmayan sütunlarda çift sayısı 6'dan 190'a çıktığında eşiği aşan çift
  sayısı 0'dan 12'ye çıkar ve beklenen değer 9,5'tir.
- Bir katsayının yanına payıyla birlikte **kaç çift arasından seçildiği** yazılır; "tek
  çiftten biri" ile "190 çiftten en büyüğü" aynı iddia değildir.
- Bileşen payları boyut azaltmanın kazancını önceden söyler: ortak sürücülü kümede ilk iki
  bileşen yüzde 82,1, ölçüm ağında yüzde 49,3, bağımsız sütunlarda yüzde 35,0 taşır.

#### Sonraki Adım

Bu konunun dört dersi kümeye hep hesapla yaklaştı: ortalama alındı, dağılım sayıldı, katsayı
hesaplandı, matris kuruldu. Hepsinin ortak varsayımı, kümedeki değerlerin ölçülmüş değerler
olduğuydu. Oysa keşif sırasında ilk yakalanan şeyler çoğu zaman hesapla değil, tabloya
bakarken görülür: aynı değerin şüpheli sıklıkta tekrarı, bir üst sınırda biriken kayıtlar,
birlikte bulunmaması gereken alan bileşimleri, bir dönemin diğerlerinden belirgin biçimde
seyrek olması. Sonraki ders bu ilk denetimi ele alır ve her yakalanan sorunun hangi özeti ne
kadar oynattığını sayar.

### Veri Görsel Denetimi

Source: https://academia.sh/tr/kurslar/kesifsel-analiz/veri-gorsel-denetimi

Altı kurallık bir tarama ham kayıt katmanında dört sorun buluyor ve her biri ayrı bir özeti bozuyor: 0,00 değeri 119 kez tekrarlanıyor ve küme ortalamasını 19,693'te tutuyor, oysa okuma sayılmayan satırlar dışarıda bırakılsa 20,454 olurdu; 45,00 m³ tavanında 20 kayıt birikmiş ve en büyük yüzde 1'in ortalaması 46,597 yerine 44,663 görünüyor; 213 satır sıfır kişilik hanede ölçülmüş tüketim taşıyor ve kişi başına tüketim, karara göre 11,204 ya da 10,617 çıkıyor; dönemler arasındaki satır açıklığı yüzde 33,5 ve ilk dönem ortalaması dengeli aboneler alınınca 20,644'ten 20,868'e çıkıyor. Hiçbir satır silinmiyor. Konu kapanışında keşfin açtığı borç sayılıyor: beş kırılım alanı 23 tekil ve 209 ikili hücre, toplam 232 ayrı alt küme üretiyor ve bunların 33'ü 30 satırdan az.

Bu konunun ilk dört dersi kümeye hep hesapla yaklaştı: ortalama alındı, dağılım sayıldı,
katsayı hesaplandı, matris kuruldu. Hepsinin ortak varsayımı kayıttaki değerlerin ölçülmüş
değerler olmasıydı. Oysa keşif sırasında ilk yakalanan şeyler çoğu zaman hesapla değil,
tabloya bakarken görülür: aynı değerin şüpheli sıklıkta tekrarı, bir sınırda biriken
kayıtlar, birlikte bulunmaması gereken alan bileşimleri, bir dönemin diğerlerinden belirgin
biçimde seyrek olması.

Bu dersin ölçüsü **denetimin yakaladığı sorun sayısı ve her birinin bozduğu özettir**. Dört
sorun bulunur, her biri için tek soru sorulur — hangi sayıyı ne kadar oynatıyor — ve hiçbir
satır silinmez.

- **EA21.** Görsel denetim burada **çizim değil**, sayıya çevrilmiş bir taramadır: hangi değer
  kaç kez tekrarlanıyor, kayıtlar nerede birikiyor, hangi alan bileşimi var olamaz, hangi
  dilim seyrek.
- **EA22. Yığılma** aynı değerin beklenenden çok tekrarıdır; ölçüsü en sık görülen değerin
  satır payıdır. Sürekli bir büyüklükte aynı sayının yüzlerce kez çıkması bir ölçüm değil,
  bir kayıt uzlaşımıdır.
- **EA23. Kesilme** kayıtların bir üst ya da alt sınırda birikmesidir; ölçüsü o sınırdaki
  kayıt sayısıdır. Kesilme **onarılamaz**: kesilen değer kayıtta yoktur. Sayılabilecek tek
  şey kaç kaydın kesildiği ve hangi özetin ne kadar bozulduğudur.
- **EA24. İmkânsız birleşim**, tek tek geçerli iki alanın birlikte geçersiz olmasıdır;
  ölçüsü kuralı bozan satır sayısıdır.
- **EA25.** Bu derste hiçbir satır **silinmez**. Temizleme Veri Toplama ve Hazırlama kursunun
  işiydi ve orada ölçü satır sayısıydı; burada her sorun için iki hesap yan yana basılır ve
  aradaki fark yazılır.

#### Altı Kural, Dört Bulgu

```python

# kesif.py — MODELDIR: K03 ve K04'un kurgu olcum agi ayni tohumla yeniden
# uretilir. Kume kurgudur; hicbir gercek abone, sayac ya da bolge temsil edilmez.
import math
from collections import Counter

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


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

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


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


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

OKUMA = []
for k in _abone + _elenen:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp(
            (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100
        if k["abone_no"] not in _gecerli:
            r()
            continue
        OKUMA.append({"abone_no": k["abone_no"], "bolge": k["bolge"],
                      "donem": DONEM[d], "tuketim_m3": t, "hane_kisi": k["hane_kisi"],
                      "memnuniyet": k["memnuniyet"],
                      "basamak": 1 if t < TARIFE[0] else 2 if t < TARIFE[1]
                      else 3 if t < TARIFE[2] else 4})
        r()

def ort(v: list[float]) -> float:
    return sum(v) / len(v)


def hiza(w: list[int], sol: int = 1):
    """Ilk `sol` sutun sola, kalanlar saga yaslanir."""
    return lambda h: "".join(str(v).ljust(w[i]) if i < sol else str(v).rjust(w[i])
                             for i, v in enumerate(h))


# Ham kayit katmani MODELDIR: saha cihazi 45,00 m3'un ustunu okuyamaz ve tavani
# yazar. Analistin eline gecen tablo budur; OKUMA yalnizca kiyas icin durur.
TAVAN = 45.0
KAYIT = [dict(o, tuketim_m3=min(o["tuketim_m3"], TAVAN)) for o in OKUMA]
T = [k["tuketim_m3"] for k in KAYIT]
sik = Counter(T).most_common(1)[0]
donem_say = Counter(k["donem"] for k in KAYIT).values()
ikiz = Counter((k["abone_no"], k["donem"]) for k in KAYIT).values()

KURAL = [
    ("yigilma", "en sik degerin satir payi (yuzde)", 100 * sik[1] / len(T), 1.0,
     f"{sik[0]:.2f} degeri {sik[1]} kez tekrarlaniyor"),
    ("kesilme", "en buyuk degerdeki kayit sayisi", float(Counter(T)[max(T)]), 5.0,
     f"{max(T):.2f} m3 ust sinirinda {Counter(T)[max(T)]} kayit birikmis"),
    ("imkansiz birlesim", "hane 0 iken tuketim > 0 satir",
     float(sum(1 for k in KAYIT if k["hane_kisi"] == 0 and k["tuketim_m3"] > 0)), 1.0,
     "sifir kisilik hanede olculmus tuketim var"),
    ("donem boslugu", "donemler arasi satir acikligi",
     100 * (max(donem_say) - min(donem_say)) / max(donem_say), 10.0,
     f"en seyrek donem {min(donem_say)}, en yogunu {max(donem_say)} satir"),
    ("yinelenen kayit", "ayni abone-donem ciftinin satiri", float(max(ikiz)), 1.5,
     "-"),
    ("tanimsiz deger", "negatif tuketim yazan satir",
     float(sum(1 for t in T if t < 0)), 1.0, "-"),
]
d = hiza([20, 34, 9, 8], 2)
print(d(["sorun", "olculen", "deger", "esik"]) + "  bulgu")
sorun = 0
for ad, olcut, deger, esik, metin in KURAL:
    var = deger >= esik
    sorun += var
    print(d([ad, olcut, f"{deger:.1f}", f"{esik:.1f}"]) + "  " + (metin if var else "-"))
print(f"\n{len(KURAL)} kural yuruldu, {sorun} sorun bulundu; hicbiri satir silmiyor")
```

```
sorun               olculen                               deger    esik  bulgu
yigilma             en sik degerin satir payi (yuzde)       3.7     1.0  0.00 degeri 119 kez tekrarlaniyor
kesilme             en buyuk degerdeki kayit sayisi        20.0     5.0  45.00 m3 ust sinirinda 20 kayit birikmis
imkansiz birlesim   hane 0 iken tuketim > 0 satir         213.0     1.0  sifir kisilik hanede olculmus tuketim var
donem boslugu       donemler arasi satir acikligi          33.5    10.0  en seyrek donem 838, en yogunu 1260 satir
yinelenen kayit     ayni abone-donem ciftinin satiri        1.0     1.5  -
tanimsiz deger      negatif tuketim yazan satir             0.0     1.0  -

6 kural yuruldu, 4 sorun bulundu; hicbiri satir silmiyor
```

Kayıt katmanı bir modeldir ve neyi modellediği açıktır: saha cihazı 45,00 m³'ün üstünü
okuyamaz ve tavanı yazar. Analistin eline geçen tablo budur; kesilmemiş değerler yalnız
karşılaştırma için elde tutulur.

Dört bulgu dört ayrı türden. 0,00 değeri 3.199 satırın 119'unda, yani yüzde 3,7'sinde
geçiyor; sürekli bir büyüklükte bir sayının bu sıklıkta tekrarlanması ölçümden gelmez,
okunamayan sayaç için sıfır yazan bir kayıt uzlaşımından gelir. En büyük değerde 20 kayıt
birikmiş: iki ondalıklı bir büyüklükte tam olarak aynı en büyük değerin yirmi kez çıkması
tavanın imzasıdır. 213 satır sıfır kişilik hanede ölçülmüş tüketim taşıyor; `hane_kisi`
alanı tek başına geçerli, `tuketim_m3` alanı tek başına geçerli, birleşimleri geçersiz.
Dönemler arasındaki satır açıklığı yüzde 33,5.

Eşiği aşmayan iki kural da bilgi veriyor. Aynı abone ile dönem çifti hiçbir satırda ikiden
fazla geçmiyor ve negatif tüketim yazan satır yok. Bunlar aranıp bulunamamış sorunlardır ve
aranmış olmaları yazılır; yazılmadığında okur, denetimin o soruyu hiç sormadığını varsayar.

#### Her Sorunun Oynattığı Sayı

```python
# etki.py — her sorun icin ayni soru: hangi ozeti ne kadar oynatiyor. Hicbir
# satir silinmez; iki hesap yan yana basilir ve fark yazilir.
def kisi_basina(kayitlar, hane_sifiri_bir: bool) -> float:
    v = [k["tuketim_m3"] / (max(k["hane_kisi"], 1) if hane_sifiri_bir else k["hane_kisi"])
         for k in kayitlar if hane_sifiri_bir or k["hane_kisi"] > 0]
    return ort(v)


def donem_ort(kayitlar, donem: str, abone=None) -> float:
    return ort([k["tuketim_m3"] for k in kayitlar
                if k["donem"] == donem and (abone is None or k["abone_no"] in abone)])


tam = {a for a, c in Counter(k["abone_no"] for k in KAYIT).items() if c == len(DONEM)}
UST = round(0.01 * len(T))
ETKI = [
    ("yigilma", sik[1], "kume ortalamasi (m3)",
     ort(T), ort([t for t in T if t > 0]), "sifir yazilan satir okuma sayilmazsa"),
    ("kesilme", Counter(T)[max(T)], "en buyuk yuzde 1'in ortalamasi (m3)",
     ort(sorted(T)[-UST:]), ort(sorted(o["tuketim_m3"] for o in OKUMA)[-UST:]),
     "tavan olmasaydi (yalniz modelde bilinir)"),
    ("imkansiz birlesim", sum(1 for k in KAYIT if k["hane_kisi"] == 0),
     "kisi basina tuketim (m3)", kisi_basina(KAYIT, True), kisi_basina(KAYIT, False),
     "hane 0 satirlari disarida"),
    ("donem boslugu", len(KAYIT) - 3 * len(tam), "ilk donem ortalamasi (m3)",
     donem_ort(KAYIT, DONEM[0]), donem_ort(KAYIT, DONEM[0], tam),
     "yalniz uc donemi tam olan aboneler"),
]
e = hiza([20, 7])
print(e(["sorun", "satir"]) + "  " + "bozulan ozet".ljust(34)
      + "kayitta".rjust(10) + "sorunsuz".rjust(11) + "fark".rjust(9))
for ad, n, ozet, ham, duz, _ in ETKI:
    print(e([ad, n]) + "  " + ozet.ljust(34)
          + f"{ham:10.3f}{duz:11.3f}{duz - ham:+9.3f}")
print()
for ad, _, _, ham, duz, aciklama in ETKI:
    print(f"{ad:<20}{aciklama}; yuzde {100 * (duz - ham) / ham:+.1f}")
```

```
sorun                 satir  bozulan ozet                         kayitta   sorunsuz     fark
yigilma                 119  kume ortalamasi (m3)                  19.693     20.454   +0.761
kesilme                  20  en buyuk yuzde 1'in ortalamasi (m3)    44.663     46.597   +1.934
imkansiz birlesim       222  kisi basina tuketim (m3)              11.204     10.617   -0.586
donem boslugu           685  ilk donem ortalamasi (m3)             20.644     20.868   +0.224

yigilma             sifir yazilan satir okuma sayilmazsa; yuzde +3.9
kesilme             tavan olmasaydi (yalniz modelde bilinir); yuzde +4.3
imkansiz birlesim   hane 0 satirlari disarida; yuzde -5.2
donem boslugu       yalniz uc donemi tam olan aboneler; yuzde +1.1
```

Dört sorun dört ayrı özeti bozuyor ve hiçbiri diğerinin yerine geçmiyor. Sıfır yığılması
küme ortalamasını tutuyor: 19,693 yerine, okuma sayılmayan satırlar dışarıda bırakılsa 20,454
olurdu, yani yüzde 3,9. Bu sayı raporlanan her bölge ortalamasının içinde de vardır, çünkü
sıfırlar bütün bölgelere dağılmıştır.

Kesilmenin oynattığı sayı ortalama değil, üst uçtur. Küme ortalaması tavandan neredeyse hiç
etkilenmez, ama en büyük yüzde 1'in ortalaması 44,663'te kalır; tavan olmasaydı 46,597
olurdu. Bu ikinci sayı yalnız modelde bilinir. Sahada kesilen değer kayıtta yoktur ve geri
getirilemez; yapılabilecek tek şey "en yüksek 32 okumanın 20'si tavana dayanmıştır" cümlesini
sayının yanına yazmaktır. Kesilmiş bir sütunda en büyük değer, çeyrekler üstü her özet ve üst
uçla ilgili her karar, ölçülmüş değil kırpılmış bir sayıya dayanır.

İmkânsız birleşimde durum farklıdır: burada iki savunulabilir karar vardır ve ikisi de bir
sayı üretir. Sıfır kişilik hane 1 sayılırsa kişi başına tüketim 11,204 m³, o 222 satır
dışarıda bırakılırsa 10,617 m³ çıkar. Aradaki fark yüzde 5,2'dir ve hangisinin doğru olduğunu
veri söylemez; söyleyen şey hanenin gerçekte kaç kişi olduğudur, o da kayıtta yoktur.

Dönem boşluğunun oynattığı sayı en küçüğüdür ama yönü öğreticidir. İlk dönem ortalaması
kayıtta 20,644 m³'tür; yalnız üç dönemi tam olan aboneler alındığında 20,868 m³ olur.
Aradaki 0,224 m³ bir davranış farkı değil, bir **bileşim** farkıdır: erken düşen aboneler
ilk dönemde ortalamanın altında tüketmiştir. Dönemler arası düşüşü davranışa bağlayan bir
cümle, bu farkı hesaba katmadan yazılamaz.

#### Keşfin Açtığı Borç

```python
# borc.py — kesif asamasinda acilan kirilim sayisi: her hucre bakilabilir bir
# alt kume, her bakis sinamanin payini buyuten bir borctur.
ALAN = [("bolge", 5), ("donem", 3), ("basamak", 4), ("memnuniyet", 5),
        ("hane_kisi", 6)]
tekil = sum(k for _, k in ALAN)
ciftler = [(i, j) for i in range(len(ALAN)) for j in range(i + 1, len(ALAN))]
ikili = sum(ALAN[i][1] * ALAN[j][1] for i, j in ciftler)
kucuk, bos = 0, 0
for i, j in ciftler:
    a, b = ALAN[i][0], ALAN[j][0]
    say = Counter((k[a], k[b]) for k in KAYIT)
    bos += ALAN[i][1] * ALAN[j][1] - len(say)
    kucuk += sum(1 for v in say.values() if v < 30)
print(f"{len(ALAN)} kirilim alani, {len(ciftler)} alan cifti")
print(f"tekil kirilim hucresi : {tekil}")
print(f"ikili kirilim hucresi : {ikili}")
print(f"toplam bakilabilir alt kume: {tekil + ikili}")
print(f"bunlarin {kucuk} tanesi 30 satirdan az, {bos} tanesi bos")
print(f"kume 1 tablodur; kesif {tekil + ikili} ayri ozet cikarabilir")
```

```
5 kirilim alani, 10 alan cifti
tekil kirilim hucresi : 23
ikili kirilim hucresi : 209
toplam bakilabilir alt kume: 232
bunlarin 33 tanesi 30 satirdan az, 2 tanesi bos
kume 1 tablodur; kesif 232 ayri ozet cikarabilir
```

Beş kırılım alanı tek başına 23 hücre açıyor, ikili bileşimleri 209 hücre daha. Toplam 232
alt küme, hepsi aynı tablonun içinden çıkıyor ve her biri için bir ortalama, bir oran ya da
bir fark hesaplanabilir. Bunların 33'ü 30 satırdan azdır ve küçük hücrede pay büyür: yirmi
satırlık bir alt kümenin ortalaması, tek bir kaydın gelip gitmesiyle belirgin biçimde oynar.

Bu sayı bir kusur değil, keşfin doğasıdır. Keşif aşaması tam da bu hücreleri gezmek, hangisinin
dikkat çektiğine bakmak ve oradan soru üretmek için vardır. Ama gezilen her hücre, sonradan
yapılacak sınamanın payına eklenen bir borçtur — çünkü sınanacak soru, 232 hücrenin arasından
**en dikkat çekeni olduğu için** seçilmiştir.

#### Özet

- Altı kurallık tarama dört sorun buldu: yığılma (0,00 değeri satırların yüzde 3,7'sinde),
  kesilme (45,00 m³'te 20 kayıt), imkânsız birleşim (213 satır) ve dönem boşluğu (yüzde 33,5).
- Yığılma küme ortalamasını 19,693'te tutar; sıfırlar okuma sayılmazsa 20,454 olur, yani
  yüzde 3,9'luk bir açıklık her bölge ortalamasının içindedir.
- Kesilme ortalamayı neredeyse hiç oynatmaz ama en büyük yüzde 1'in ortalamasını 46,597
  yerine 44,663 gösterir ve **onarılamaz**; sayılabilecek tek şey kaç kaydın tavana dayandığıdır.
- İmkânsız birleşim iki savunulabilir karar bırakır: kişi başına tüketim 11,204 ya da 10,617
  m³, aradaki fark yüzde 5,2.
- Dönem boşluğu ilk dönem ortalamasını 20,644'ten 20,868'e taşır; bu bir davranış değil bir
  bileşim farkıdır.

#### Sonraki Adım

Bu konu beş derste bir şey yaptı: kümeyi tanıdı ve soru üretti. Bölgeler arasındaki 4,463
m³'lük farkın karıştırmayla üretilemediği görüldü, doğu dağılımının çarpık olduğu ve elenmeyen
çit dışı 30 satırın ortalamayı 0,480 m³ oynattığı ölçüldü, aynı katsayıyı veren üç ayrı
ilişkinin dilim ortalamalarıyla ayrıştığı gösterildi, bağımsız yirmi sütunda 190 çiftin
12'sinin eşiği aştığı sayıldı ve dört kayıt sorununun dört ayrı özeti bozduğu yazıldı.

Ortak eksik şudur: bu soruların **hiçbiri sınanmadı**. Keşif bir farkın var göründüğünü
söyler, o farkın raporlanmaya değer olup olmadığını söylemez; bir özetin çarpık olduğunu
söyler, hangi özetin raporlanacağına karar vermez. Üstelik keşfin kendisi bir borç bıraktı:
232 kırılım hücresi gezildi ve sınanacak soru bunların arasından seçildi. Sonraki konu,
Uygulamalı İstatistik, bu borcu ödemekle başlar — önce raporlanacak özetin seçimini ve o
seçimin oynattığı sayıyı ölçer, sonra farkın kendi aralığını ve sınamasını kurar.

## Uygulamalı İstatistik

Bir farkın gerçek mi gürültü mü olduğunun yeniden karıştırma ile sınanması ve sonucun oynama payıyla raporlanması: ortalama ile ortanca arasındaki kararın rapor edilen sayıyı oynatması, kutu ve yoğunluk özetlerinin beş sayıya sığdırdığı ile gizlediği, güven aralığının söylediği ve söylemediği, sınama seçimi ve varsayım denetimi, deney kümesinden çözümleme serbestliğiyle çıkan karar sayısı, regresyon katsayısının yorum sınırı ve etkinin ne kadarını açıkladığı, kohort tanımının oynattığı elde tutma oranı, seçim yanlılığı ve çok deneyerek bulunan farkın sayılması.

### Betimsel Özetlerin Seçimi

Source: https://academia.sh/tr/kurslar/kesifsel-analiz/betimsel-ozetlerin-secimi

Aynı 557 okumadan üç savunulabilir özet çıkıyor: ortalama 24,674 m³, ortanca 24,120 m³ ve yüzde on kırpılmış ortalama 24,581 m³, aradaki en büyük fark 0,554 m³. Geri koyarak örnekleme üçünün de oynama payını ölçüyor ve genişlikler 1,552, 1,762 ve 1,458 m³ çıkıyor: seçimin oynattığı fark, payların üçte biri kadardır ve üç aralık da 25 m³'lük tarife basamağını içine alır. Aynı hesap 557 okumalık gruptan 142 okumalık gruba inince seçim farkı 1,679 m³'e, pay genişliği 2,917 m³'e çıkar ve karar bu kez paydan bağımsız okunamaz.

Keşif aşaması bir karar üretmedi. Beş ders boyunca dağılımlar açıldı, kırılımlar denendi, ilişkiler
tarandı ve geriye bir soru listesi kaldı; listedeki soruların hiçbiri henüz sınanmadı. Keşifte
bakılan her kırılım da sınamaya bir borç bıraktı ve o borç konunun sonunda sayılacak.

Sınamanın ilk adımı, sanıldığı gibi bir sınama seçmek değildir. Ondan önce gelen ve çoğu zaman
atlanan bir adım vardır: sınanacak sayı hangi özetle yazılacak. Doğu bölgesinin okumaları için
"ortalama tüketim" istendiğinde en az üç savunulabilir cevap vardır ve üçü aynı kümeden üç ayrı
sayı verir. Bu dersin ölçüsü, bu seçimin rapordaki sayıyı kaç metre küp oynattığı ve o oynamanın
sayının kendi payının yanında ne kadar kaldığıdır.

- **UI1. Betimsel özet bir karardır.** Aynı küme için ortalama, ortanca ve kırpılmış ortalama üç
  ayrı sayı verir; hiçbiri diğerinin yaklaşık değeri değildir, üçü üç ayrı soruya cevaptır.
- **UI2. Her özetin bir oynama payı vardır** ve pay **geri koyarak örneklemeyle** ölçülür: küme
  kendi içinden aynı büyüklükte, geri koyarak, çok kez çekilir ve özet her çekilişte yeniden
  hesaplanır. Çekiliş sayısı yazılır; pay o sayıya da bağlıdır.
- **UI3.** Payı dar olan özet tek başına doğru özet değildir. Darlık, özetin **neyi** cevapladığını
  değiştirmez; yalnız o cevabın örneklemden örnekleme ne kadar oynadığını söyler.
- **UI4.** Seçimin oynattığı fark, payın yanında okunur. Paydan küçük bir fark üzerinde yürütülen
  tartışma, gürültü üzerinde yürütülen bir tartışmadır.
- **UI5.** Grup küçüldükçe pay büyür. Rapor edilen her özetin yanına **kaç gözleme dayandığı**
  yazılır; `n` yazılmayan özetin payı okunamaz.

#### Üç Özet, Üç Sayı

```python
# kume.py — MODELDIR: K03-K04'un kurgu olcum agi ayni tohumla yeniden uretilir.
# 3.199 satirlik uzun bicimli okuma tablosu, 1.329 abone, uc donem, bes bolge.
import math

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


def uretec(t):
    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


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

OKUMA = []
for a in _k + _e:
    r = uretec(TOHUM + 7000 + a["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(
            a["taban"] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100
        if a["abone_no"] not in GECERLI:
            r()
            continue
        OKUMA.append({"abone_no": a["abone_no"], "bolge": a["bolge"],
                      "donem": DONEM[d], "tuketim_m3": t})
        r()


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


def ortanca(v):
    s = sorted(v)
    n = len(s)
    return s[n // 2] if n % 2 else (s[n // 2 - 1] + s[n // 2]) / 2


def kirpilmis(v, p=0.10):
    s = sorted(v)
    k = int(len(s) * p)
    return ortalama(s[k:len(s) - k])


dogu = [o["tuketim_m3"] for o in OKUMA if o["bolge"] == "dogu"]
U = [ortalama(dogu), ortanca(dogu), kirpilmis(dogu)]
print(f"kurgu kume (tohum {TOHUM}): {len(OKUMA)} satir, {len(GECERLI)} abone")
print(f"dogu bolgesi: {len(dogu)} okuma, {sum(1 for x in dogu if x == 0.0)} sifir okuma")
print(f"ortalama {U[0]:.3f} | ortanca {U[1]:.3f} | kirpilmis(%10) {U[2]:.3f}")
print(f"ucu arasindaki en buyuk fark {max(U) - min(U):.3f} m3")
```

```
kurgu kume (tohum 20260218): 3199 satir, 1329 abone
dogu bolgesi: 557 okuma, 20 sifir okuma
ortalama 24.674 | ortanca 24.120 | kirpilmis(%10) 24.581
ucu arasindaki en buyuk fark 0.554 m3
```

Küme kurgudur ve K03–K04'ün ölçüm ağından aynı tohumla yeniden üretilmiştir; 3.199 satır ve 1.329
abone, önceki kursun bıraktığı sayıların aynısıdır. Doğu bölgesinin 24,674 m³'lük ortalaması da
oradan gelir ve bu kursun açılışında sorulan sayıdır.

Şimdi yanında iki sayı daha duruyor. Ortanca 24,120 m³'tür: okumalar sıralandığında ortada duran
değer, yani kümenin yarısının altında kaldığı sayı. Yüzde on kırpılmış ortalama 24,581 m³'tür: en
küçük 55 ve en büyük 55 okuma çıkarıldıktan sonra kalan 447 değerin ortalaması. Üçü de doğrudur,
üçü de aynı 557 okumadan çıkmıştır ve aralarındaki en büyük fark 0,554 m³'tür.

Ortalamanın ortancadan büyük olması bir bilgidir: dağılım sağa **çarpıktır**, yani birkaç büyük
okuma ortalamayı yukarı çeker. Yirmi sıfır okuma ise ters yönde iş görür ve ortalamayı aşağı
bastırır. Bu iki etki aynı sayının içinde birbirini kısmen götürür ve tek başına ortalamaya bakan
biri ikisini de göremez.

#### Payın Ölçülmesi

```python
# pay.py — oynama payi geri koyarak orneklemeyle olculur: kume kendi icinden
# ayni buyuklukte ve geri koyarak 1.000 kez cekilir, ozet her cekiliste yeniden
# hesaplanir, cikan 1.000 degerin orta yuzde 95'i alinir.
CEKILIS = 1000


def yuzdelik(s, p):
    i = p * (len(s) - 1)
    alt = int(i)
    ust = min(alt + 1, len(s) - 1)
    return s[alt] + (s[ust] - s[alt]) * (i - alt)


def pay(v, ozet, tohum, cekilis=CEKILIS):
    sec = uretec(tohum)
    n = len(v)
    d = sorted(ozet([v[int(sec() * n)] for _ in range(n)]) for _ in range(cekilis))
    return yuzdelik(d, 0.025), yuzdelik(d, 0.975)


E = [12, 10, 10, 10, 10]
y = lambda h: "".join(str(v).rjust(E[k]) if k else str(v).ljust(E[0])
                      for k, v in enumerate(h))
OZET = (("ortalama", ortalama), ("ortanca", ortanca), ("kirpilmis", kirpilmis))
print(y(["ozet", "sayi", "alt", "ust", "genislik"]))
for ad, f in OZET:
    a, b = pay(dogu, f, TOHUM + 101)
    print(y([ad, round(f(dogu), 3), round(a, 3), round(b, 3), round(b - a, 3)]))
print(f"\n{len(dogu)} gozlem, {CEKILIS} cekilis, ucu de ayni cekilisler uzerinde")
print("tarife basamagi 25 m3 uc araligin da icinde kaliyor")
```

```
ozet              sayi       alt       ust  genislik
ortalama        24.674    23.889    25.441     1.552
ortanca          24.12    23.248     25.01     1.762
kirpilmis       24.581    23.876    25.334     1.458

557 gozlem, 1000 cekilis, ucu de ayni cekilisler uzerinde
tarife basamagi 25 m3 uc araligin da icinde kaliyor
```

Geri koyarak örnekleme tek bir soruyu cevaplar: aynı ağdan aynı büyüklükte başka bir okuma kümesi
gelseydi bu özet ne çıkardı. Elde başka bir küme olmadığı için kümenin kendisi kütle yerine
konur, içinden geri koyarak 557 değer çekilir, özet yeniden hesaplanır ve bu 1.000 kez tekrarlanır.
Çıkan 1.000 değerin orta yüzde 95'i, o özetin **oynama payıdır**.

Üç özet aynı çekilişler üzerinde hesaplandı; aradaki fark özetten gelir, çekiliş kurasından değil.
Genişlikler 1,458 ile 1,762 m³ arasındadır. Seçimin oynattığı fark ise 0,554 m³'tü, yani en dar
payın bile üçte biri kadar. Üç özet arasında hangisinin yazılacağı tartışması, bu kümede payın
içinde kalan bir tartışmadır.

Bunun rapordaki karşılığı tek cümledir: doğu bölgesinin tüketimi 25 m³'lük tarife basamağının
altında mı. Üç sayı da altındadır, ama üç aralık da 25'i içine alır. Basamağın altında kalma
iddiası, hangi özet seçilirse seçilsin, payı yazılmadan savunulamaz. Payı yazılan bir raporda ise
iddia kendiliğinden yumuşar ve doğru biçimini alır: gözlenen üç sayı da basamağın altındadır, fakat
aynı ağdan gelecek başka bir okuma kümesinin basamağı aşması bu veriyle dışlanamaz.

#### Hangi Özet Neyi Cevaplıyor

```python
# secim.py — ozet secimi rapora ne yaziyor: toplam hacim ve kirpilan satirlar.
k = int(len(dogu) * 0.10)
print(f"ortalama x n = {ortalama(dogu) * len(dogu):.2f} m3 raporlanan hacim")
print(f"ortanca x n = {ortanca(dogu) * len(dogu):.2f} m3 ayni carpim, baska sayi")
print(f"iki hacim arasindaki fark {(ortalama(dogu) - ortanca(dogu)) * len(dogu):.2f} m3")
print(f"kirpilmis ortalama {2 * k} okumayi disarida birakir; bunlarin "
      f"{sum(1 for x in sorted(dogu)[:k] if x == 0.0)} tanesi sifir okumadir")
sifirsiz = [x for x in dogu if x > 0.0]
print(f"sifir okumalar hic sayilmazsa ortalama {ortalama(sifirsiz):.3f} m3 olur")
```

```
ortalama x n = 13743.34 m3 raporlanan hacim
ortanca x n = 13434.84 m3 ayni carpim, baska sayi
iki hacim arasindaki fark 308.50 m3
kirpilmis ortalama 110 okumayi disarida birakir; bunlarin 20 tanesi sifir okumadir
sifir okumalar hic sayilmazsa ortalama 25.593 m3 olur
```

Üç özetin üç ayrı soruya cevap verdiği burada görünür. Ortalama, kümenin **toplamını** taşır: 557
ile çarpıldığında 13.743,34 m³ çıkar ve bu, ağdan geçen hacmin kendisidir. Ortanca aynı çarpımda
13.434,84 m³ verir ve bu sayı hiçbir şeyin toplamı değildir; aradaki 308,50 m³ ortancanın hacim
sorusuna cevap vermediğinin ölçüsüdür. Faturalanacak hacim sorulduğunda ortanca yanlış özettir.

Kırpılmış ortalama üçüncü soruyu cevaplar: uç okumalara dayanıklı bir merkez. Bunu 110 okumayı
dışarıda bırakarak yapar ve dışarıda bıraktıklarının 20 tanesi sıfır okumadır. Payı en dar özet
budur, ama darlığın kaynağı kümenin kendisi değil, kümenin yüzde yirmisinin hesaba girmemesidir.
Dar pay burada bir üstünlük değil, bir kapsam daralmasının işaretidir.

Son satır kapsam kararının tek başına ne yaptığını gösterir. Sıfır okumalar hiç sayılmazsa
ortalama 25,593 m³ olur ve tarife basamağını aşar. Sıfır okumaların ne olduğu M26/K03'ün temizleme
dersinde ele alınmıştı; burada eleme yapılmaz, yalnız kapsam kararının özeti 0,919 m³ oynattığı ve
bu oynamanın seçim farkından büyük olduğu kaydedilir.

#### Grup Küçüldüğünde

```python
# kucuk.py — ayni uc ozet ve ayni pay, kucuk bir kirilimda yeniden hesaplanir.
alt = [o["tuketim_m3"] for o in OKUMA
       if o["bolge"] == "dogu" and o["donem"] == "2026-03"]
for ad, v in (("dogu / tumu", dogu), ("dogu / 2026-03", alt)):
    s = [f(v) for _, f in OZET]
    g = [b - a for a, b in (pay(v, f, TOHUM + 101) for _, f in OZET)]
    print(f"{ad}: n={len(v)}, secim farki {max(s) - min(s):.3f} m3, "
          f"pay genisligi {min(g):.3f} ile {max(g):.3f} m3 arasinda")
    print(f"    ortalama {s[0]:.3f} | ortanca {s[1]:.3f} | kirpilmis {s[2]:.3f}")
```

```
dogu / tumu: n=557, secim farki 0.554 m3, pay genisligi 1.458 ile 1.762 m3 arasinda
    ortalama 24.674 | ortanca 24.120 | kirpilmis 24.581
dogu / 2026-03: n=142, secim farki 1.679 m3, pay genisligi 2.527 ile 2.917 m3 arasinda
    ortalama 22.394 | ortanca 20.715 | kirpilmis 22.112
```

Aynı bölge, tek dönem: 142 okuma. Seçim farkı 0,554 m³'ten 1,679 m³'e çıktı, yani üç katına.
Payların genişliği de büyüdü ve 2,5–2,9 m³ bandına oturdu. İki büyüme birlikte okunur: küçük
kırılımda hem özetler birbirinden uzaklaşır hem de her birinin kendi oynaması artar.

Uzaklaşmanın kaynağı görünür durumda. Bu dönemde ortalama 22,394 m³, ortanca 20,715 m³'tür ve
aradaki 1,679 m³'lük açıklık, tek dönemlik kırılımda birkaç büyük okumanın ortalamayı çekmesinden
gelir. Kırpılmış ortalama 22,112 m³ ile ortalamanın yanında durur, çünkü çekmeyi yapan okumalar
kırpılan yüzde ondan fazladır.

Rapor bakımından sonuç şudur: 557 okumalık grupta özet seçimi payın içinde kalan bir ayrıntıdır,
142 okumalık grupta ise seçim farkı payın yarısını geçer ve karar artık paydan bağımsız
okunamaz. İkisinde de yazılması gereken şey aynıdır — sayının yanına `n` ve pay.

#### Payın Kendisi de Bir Sayıdır

```python
# cekilis.py — pay bir hesaptan degil bir kosumdan cikar; kosum sayisi degisince
# payin sinirlari da oynar. Ust sinir bu kursta 1.000 cekilistir.
for c in (200, 500, 1000):
    a, b = pay(dogu, ortalama, TOHUM + 101, c)
    print(f"{c:5d} cekilis: {a:.3f} - {b:.3f}, genislik {b - a:.3f} m3")
```

```
  200 cekilis: 23.955 - 25.406, genislik 1.451 m3
  500 cekilis: 23.949 - 25.426, genislik 1.477 m3
 1000 cekilis: 23.889 - 25.441, genislik 1.552 m3
```

Pay bir formülden değil bir koşumdan çıkar ve koşum sayısı değişince payın sınırları da oynar.
İki yüz çekilişte genişlik 1,451 m³, bin çekilişte 1,552 m³ olur; aradaki 0,101 m³ payın kendi
belirsizliğidir. Aralığın uçları en çok oynayan kısımdır, çünkü uçlar 1.000 değerin en dıştaki
yirmi beşincilerine dayanır ve o bölgede az sayıda çekiliş vardır.

Bu kursta çekiliş sayısı 1.000'i aşmaz. Sınır bir kolaylık değil bir kayıttır: rapor edilen pay,
kaç çekilişten çıktığı yazılmadan tam değildir. Aynı kural sonraki derslerde yeniden karıştırma
sayısı için de geçerli olacak ve orada payın çözünürlüğünü doğrudan koşum sayısı belirleyecek.

#### Özet

- Aynı 557 okuma üç savunulabilir özet verir: ortalama 24,674 m³, ortanca 24,120 m³, yüzde on
  kırpılmış ortalama 24,581 m³; seçimin oynattığı en büyük fark 0,554 m³'tür.
- Geri koyarak örnekleme, kümeyi kütle yerine koyup 1.000 kez geri koyarak çeker ve her özetin
  payını ölçer: genişlikler 1,552, 1,762 ve 1,458 m³ çıkar, yani seçim farkının üç katı.
- Payı en dar özet kırpılmış ortalamadır, ama darlık 110 okumanın hesaba girmemesinden gelir; dar
  pay doğru özet anlamına gelmez, kapsamın daraldığı anlamına gelir.
- Üç özet üç ayrı soruya cevap verir: ortalama toplamı taşır ve 557 ile çarpımı 13.743,34 m³'tür,
  ortancanın aynı çarpımı 13.434,84 m³ ile hiçbir hacme karşılık gelmez.
- Kırılım 557 okumadan 142 okumaya inince seçim farkı 1,679 m³'e, pay genişliği 2,917 m³'e çıkar;
  bu yüzden her özetin yanına dayandığı gözlem sayısı yazılır.

#### Sonraki Adım

Tek bir sayı seçildi ve payı yazıldı, ama tek sayı bir dağılımı anlatmaz. Rapordaki asıl soru çoğu
zaman iki grubun karşılaştırılmasıdır ve bu karşılaştırma alışkanlıkla beş sayı üzerinden yapılır:
en küçük, birinci çeyrek, ortanca, üçüncü çeyrek, en büyük. Sonraki ders bu beş sayının bir dağılımı
belirlemediğini gösterir — beş sayısı birbirinin aynısı olan iki küme kurulur, aralık sayımları
yan yana basılır ve birinin tek, diğerinin iki tepeli olduğu sayıyla ortaya çıkar. Ortancanın çentik
aralığı da yine geri koyarak örneklemeyle üretilir.

### Dağılım Karşılaştırması

Source: https://academia.sh/tr/kurslar/kesifsel-analiz/dagilim-karsilastirmasi

Kuzey bölgesinin 921 okuması beş sayıya iniyor ve aynı beş sayıyı veren ikinci bir küme kuruluyor: iki kutu özeti de 0,00 | 15,74 | 19,66 | 24,63 | 45,47, çeyrekler açıklığı 8,89 m³ ve çitler 2,405 ile 37,965 m³. Aralık sayımları ikisini ayırıyor — kuzeyde tek tepe 16–20 m³ aralığında, ikizde iki tepe 12–16 ve 24–28 m³ aralıklarında ve ortanca çukurda kalıyor. Aynı ortancanın çentik aralığı geri koyarak örneklemeyle 0,920 m³ ve 3,146 m³ çıkıyor, çit dışında kalan gözlem sayısı 50 ile 35 arasında değişiyor.

Önceki ders tek bir sayı seçti ve payını yazdı. Rapordaki soruların çoğu ise tek sayı değil,
karşılaştırma ister: iki bölgenin tüketim dağılımı birbirinden farklı mı. Bu karşılaştırma
alışkanlıkla beş sayı üzerinden yapılır — en küçük, birinci çeyrek, ortanca, üçüncü çeyrek, en
büyük — ve beş sayı bir kutu özeti olarak yan yana konur.

Bu derste kutu özeti ve **yoğunluk gösterimi** çizilmez; ikisi de veri yapısı olarak kurulur ve
sayı olarak basılır. Çizim, eksen ve tasarım kararları M26/K06'nın işidir. Buradaki soru daha
öncedir: beş sayı bir dağılımı belirler mi. Ölçü, beş sayısı birbirinin aynısı olan iki kümenin
aralık sayımlarında kaç tepe verdiğidir.

- **UI6. Kutu özeti beş sayı ve iki çittir.** Çeyrekler açıklığı üçüncü çeyrek ile birinci çeyreğin
  farkıdır; çitler bu açıklığın 1,5 katı kadar dışarıda durur. M26/K03'te bu beş sayı bir
  **eleme** kararıydı; burada eleme yoktur, sayılar dağılımın biçimini anlatmak için kullanılır.
- **UI7. Beş sayı bir dağılımı belirlemez.** Aynı beş sayıyı veren birden çok küme vardır ve
  aralarındaki fark kutu özetine hiç yansımaz.
- **UI8. Aralık sayımı yoğunluğun sayısal karşılığıdır.** Değer ekseni eşit genişlikte
  **aralık**lara bölünür ve her aralığa düşen gözlem sayılır; tepe sayısı bu sayımlardan okunur.
- **UI9. Çentik aralığı ortancanın payıdır** ve geri koyarak örneklemeyle üretilir: 1.000 çekilişte
  ortanca yeniden hesaplanır, çıkan değerlerin orta yüzde 95'i çentiktir.
- **UI10.** Çentiğin genişliği gözlem sayısına **ve** ortanca çevresindeki yoğunluğa bağlıdır. Aynı
  ortanca, ortanca çevresi seyrek olan bir kümede çok daha geniş bir çentik verir.
- **UI11.** İki çentiğin kesişip kesişmemesi bir gösterim ipucudur, sınama değildir; aralıkların
  kesişmesinin ne anlama geldiği sonraki dersin konusudur.

#### Kutu Özeti Bir Veri Yapısıdır

```python
# kume.py — MODELDIR: K03-K04'un kurgu olcum agi ayni tohumla yeniden uretilir.
# 3.199 satirlik uzun bicimli okuma tablosu, 1.329 abone, uc donem, bes bolge.
import math

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


def uretec(t):
    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


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

OKUMA = []
for a in _k + _e:
    r = uretec(TOHUM + 7000 + a["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(
            a["taban"] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100
        if a["abone_no"] not in GECERLI:
            r()
            continue
        OKUMA.append({"abone_no": a["abone_no"], "bolge": a["bolge"],
                      "donem": DONEM[d], "tuketim_m3": t})
        r()


def yuzdelik2(v, p):
    s = sorted(v)
    i = p * (len(s) - 1)
    a = int(i)
    b = min(a + 1, len(s) - 1)
    return s[a] + (s[b] - s[a]) * (i - a)


def bes_sayi(v):
    return [min(v), yuzdelik2(v, 0.25), yuzdelik2(v, 0.50),
            yuzdelik2(v, 0.75), max(v)]


def kutu(v):
    b = bes_sayi(v)
    ac = b[3] - b[1]
    return b, ac, b[1] - 1.5 * ac, b[3] + 1.5 * ac


kuzey = sorted(o["tuketim_m3"] for o in OKUMA if o["bolge"] == "kuzey")
b, ac, ac_alt, ac_ust = kutu(kuzey)
print(f"kuzey: {len(kuzey)} okuma")
print("bes sayi ozeti: " + " | ".join(f"{x:.2f}" for x in b))
print(f"ceyrekler acikligi {ac:.2f} m3, citler {ac_alt:.3f} ve {ac_ust:.3f} m3")
print(f"cit disinda {sum(1 for x in kuzey if x < ac_alt or x > ac_ust)} okuma var")
```

```
kuzey: 921 okuma
bes sayi ozeti: 0.00 | 15.74 | 19.66 | 24.63 | 45.47
ceyrekler acikligi 8.89 m3, citler 2.405 ve 37.965 m3
cit disinda 50 okuma var
```

Kutu özeti burada bir çizim değil, yedi sayıdan oluşan bir kayıttır: beş sayı, çeyrekler açıklığı
ve iki çit. Kuzey bölgesinin 921 okuması bu yediye indi. Ortanca 19,66 m³, çeyrekler açıklığı
8,89 m³, çitler 2,405 ile 37,965 m³ arasındadır ve bu sınırların dışında 50 okuma kalır.

Kümenin en küçük değerinin sıfır olması, alt çitin altında kalan okumaların çoğunun sıfır
okumalar olduğunu düşündürür. M26/K03 bu okumaları bir temizleme kararı olarak ele almıştı; burada
hiçbiri elenmez, yalnız kaç tanesinin çit dışında kaldığı sayılır. Çit bir eleme eşiği değil, bir
biçim ölçüsüdür.

Yedi sayı raporda az yer kaplar ve karşılaştırmayı hızlandırır. Bedeli ise bir sonraki bölümde
ölçülür: bu yedi sayı, 921 okumanın nasıl dizildiği hakkında sanıldığından çok daha azını söyler.

#### Aynı Beş Sayı, Başka Bir Küme

```python
# ikiz.py — KURGU: kuzeyin sirali degerleri her ceyrek diliminin icinde dilim
# ucuna dogru itilir. Sirali dizide 0., 230., 460., 690. ve 920. degerler yerinde
# kaldigi icin bes sayi ozeti birebir korunur, ic dagilim degisir.
def itele(dilim, uc, p=4):
    a, z = dilim[0], dilim[-1]
    u = [(x - a) / (z - a) for x in dilim]
    return [z - (z - a) * (1 - t) ** p if uc == "ust" else a + (z - a) * t ** p
            for t in u]


C = [0, 230, 460, 690, len(kuzey) - 1]
ikiz = (itele(kuzey[C[0]:C[1] + 1], "ust")[:-1]
        + itele(kuzey[C[1]:C[2] + 1], "alt")[:-1]
        + itele(kuzey[C[2]:C[3] + 1], "ust")[:-1]
        + itele(kuzey[C[3]:], "alt"))
b2, ac2, alt2, ust2 = kutu(ikiz)
print(f"ikiz kume: {len(ikiz)} deger (kurgu, kuzeyin sirali degerlerinden turetildi)")
print("bes sayi ozeti: " + " | ".join(f"{x:.2f}" for x in b2))
print(f"ceyrekler acikligi {ac2:.2f} m3, citler {alt2:.3f} ve {ust2:.3f} m3")
print(f"cit disinda {sum(1 for x in ikiz if x < alt2 or x > ust2)} deger var")
print(f"iki kutu ozeti ayni mi: {[round(x, 2) for x in b] == [round(x, 2) for x in b2]}")
```

```
ikiz kume: 921 deger (kurgu, kuzeyin sirali degerlerinden turetildi)
bes sayi ozeti: 0.00 | 15.74 | 19.66 | 24.63 | 45.47
ceyrekler acikligi 8.89 m3, citler 2.405 ve 37.965 m3
cit disinda 35 deger var
iki kutu ozeti ayni mi: True
```

İkiz küme kurgudur ve nasıl kurulduğu koddadır: sıralı dizi dört çeyrek dilimine ayrılır, her
dilimin içindeki değerler dilimin bir ucuna doğru itilir. İtme sıralamayı bozmaz ve dilim uçlarına
denk gelen değerler yerinde kalır, bu yüzden beş sayı birebir korunur. Alt ve üst yarının itme
yönü ters seçildiği için değerler ortancanın iki yanında birikir.

İki kutu özeti aynıdır: aynı ortanca, aynı çeyrekler, aynı çeyrekler açıklığı, aynı çitler. Kutu
özetini yan yana koyan bir rapor iki küme arasında hiçbir fark bildiremez. Bildirebileceği tek
şey son satırdadır ve o da beş sayının içinde değildir: çit dışındaki gözlem sayısı 50'den 35'e
inmiştir, yani aynı çitler iki kümede farklı sayıda değeri dışarıda bırakır.

Bu, kutu özetinin bir kusuru değil, kapsamıdır. Beş sayı **sıralamanın beş noktasını** bildirir;
o noktalar arasında değerlerin nasıl dağıldığı hakkında hiçbir şey söylemez ve söylemek üzere
tasarlanmamıştır. Kutu özetinin taşıdığı bilgi, 921 okumanın dördü dışında hepsinin sıralamadaki
yerinden bağımsızdır: dilim içindeki her düzenleme aynı yedi sayıyı verir.

İkiz kümenin gerçek ağda karşılığı olmayan bir kurgu olduğu bir kez daha yazılmalıdır. Amacı bir
bölgeyi taklit etmek değil, kutu özetinin ayırt edemediği farkın büyüklüğünü göstermektir. Aynı
etki gerçek kümelerde daha ölçülü biçimde ortaya çıkar ve genellikle iki farklı abone grubunun tek
satırda toplanmasından doğar.

#### Aralık Sayımları

```python
# aralik.py — yogunluk gosterimi sayi olarak: deger ekseni 4 m3'luk araliklara
# bolunur, her araliktaki gozlem sayilir. Metin cubugu on gozleme bir isarettir.
GEN, N = 4.0, 12


def sayim(v):
    c = [0] * N
    for x in v:
        c[min(int(x / GEN), N - 1)] += 1
    return c


def tepe(c):
    return [i for i in range(1, N - 1)
            if c[i] > c[i - 1] and c[i] > c[i + 1] and c[i] >= 0.3 * max(c)]


ck, ci = sayim(kuzey), sayim(ikiz)
for i in range(N):
    print(f"{i * GEN:5.0f}-{(i + 1) * GEN:<3.0f} {ck[i]:4d} {'#' * round(ck[i] / 10):<34}"
          f" {ci[i]:4d} {'#' * round(ci[i] / 10)}")
print(f"tepe sayisi: kuzey {len(tepe(ck))}, ikiz {len(tepe(ci))}")
print(f"ikizin tepeleri {[int(i * GEN) for i in tepe(ci)]} m3 araliklarinda, "
      f"ortanca {b2[2]:.2f} m3 ise cukurda")
```

```
    0-4     32 ###                                  32 ###
    4-8      0                                       0
    8-12    41 ####                                  0
   12-16   175 ##################                  318 ################################
   16-20   234 #######################             114 ###########
   20-24   182 ##################                  110 ###########
   24-28   130 #############                       329 #################################
   28-32    66 #######                              11 #
   32-36    37 ####                                  4
   36-40    16 ##                                    0
   40-44     5                                       2
   44-48     3                                       1
tepe sayisi: kuzey 1, ikiz 2
ikizin tepeleri [12, 24] m3 araliklarinda, ortanca 19.66 m3 ise cukurda
```

Kutu özetinin ayıramadığı iki küme, on iki sayı çiftiyle ayrıldı. Kuzeyde sayımlar 16–20 m³
aralığında tek bir tepeye çıkıyor ve iki yana düşüyor. İkizde iki tepe var: 318 değer 12–16 m³
aralığında, 329 değer 24–28 m³ aralığında ve arada 114 ile 110'a inen bir çukur duruyor.

Çukurun yeri önemlidir: ortanca 19,66 m³'tür ve tam bu çukurun içine düşer. İkiz kümede ortancaya
en yakın değerler en seyrek olanlardır. "Tipik abone 19,66 m³ tüketiyor" cümlesi kuzey için
savunulabilir, ikiz küme için ise doğru olduğu halde yanıltıcıdır — o değerin çevresinde neredeyse
kimse yoktur.

Aralık genişliği bir karardır ve bu kararın kendisi de sayıyı oynatır: 4 m³ yerine 10 m³ seçilseydi
iki tepe tek aralığa girer ve fark yine görünmezdi. Aralık genişliğinin görsel etkisi ve seçimi
M26/K06'nın konusudur; burada kaydedilen tek şey, seçilen genişliğin çıktının altında yazılı
olmasıdır.

#### Çentik Aralığı

```python
# centik.py — ortancanin payi: 1.000 kez geri koyarak cekilir, her cekiliste
# ortanca yeniden hesaplanir, cikan degerlerin orta yuzde 95'i centik araligidir.
CEKILIS = 1000


def yuzdelik(s, p):
    i = p * (len(s) - 1)
    a = int(i)
    z = min(a + 1, len(s) - 1)
    return s[a] + (s[z] - s[a]) * (i - a)


def centik(v, tohum, cekilis=CEKILIS):
    sec = uretec(tohum)
    n = len(v)
    d = sorted(yuzdelik2([v[int(sec() * n)] for _ in range(n)], 0.50)
               for _ in range(cekilis))
    return yuzdelik(d, 0.025), yuzdelik(d, 0.975)


merkez = [o["tuketim_m3"] for o in OKUMA if o["bolge"] == "merkez"]
for ad, v in (("kuzey", kuzey), ("ikiz", ikiz), ("merkez", merkez)):
    a, z = centik(v, TOHUM + 211)
    print(f"{ad:7s} n={len(v):4d} ortanca {yuzdelik2(v, 0.50):6.3f} "
          f"centik {a:.3f} - {z:.3f} genislik {z - a:.3f}")
ka, kz = centik(kuzey, TOHUM + 211)
ma, mz = centik(merkez, TOHUM + 211)
print(f"kuzey ile merkez centikleri kesisiyor mu: {ka < mz and ma < kz}")
```

```
kuzey   n= 921 ortanca 19.660 centik 19.230 - 20.150 genislik 0.920
ikiz    n= 921 ortanca 19.660 centik 18.203 - 21.349 genislik 3.146
merkez  n= 600 ortanca 21.535 centik 20.795 - 22.330 genislik 1.535
kuzey ile merkez centikleri kesisiyor mu: False
```

Çentik, ortancanın oynama payıdır ve önceki dersteki geri koyarak örneklemenin aynısıyla üretilir.
Kuzey ile ikiz kümenin ortancası aynı sayıdır, gözlem sayıları da aynıdır, buna rağmen çentikleri
0,920 ve 3,146 m³ genişliktedir. Aradaki üç buçuk kat, gözlem sayısından değil ortanca
çevresindeki yoğunluktan gelir: çukurda duran bir ortanca, çekilişten çekilişe çok daha uzağa
gider.

Bu, kutu özetinin eksiğinin sayısal ifadesidir. Beş sayıyı yan yana koyan iki kutu ayırt
edilemezken, aynı ortancanın payı üç katından fazla farklıdır. Ortancanın yanına çentiği yazılan
bir rapor, çizim yapılmadan da iki dağılımın aynı olmadığını bildirir. Çentik burada beş sayının
üzerine eklenen altıncı ve yedinci sayıdır ve maliyeti 1.000 çekilişlik tek bir koşumdur.

Son satır gerçek bir karşılaştırmadır: kuzey ile merkez bölgelerinin çentikleri kesişmiyor. Bunun
"iki bölgenin ortancası farklıdır" demek olup olmadığı burada karara bağlanmaz. Kesişme ve
kesişmeme üzerine kurulan yorum, sonraki dersin ilk sorusudur.

#### Özet

- Kutu özeti çizim değil kayıttır: beş sayı, çeyrekler açıklığı ve iki çit; kuzeyin 921 okuması
  0,00 | 15,74 | 19,66 | 24,63 | 45,47 değerlerine ve 8,89 m³'lük açıklığa iner.
- Aynı beş sayıyı veren ikinci bir küme kurulabilir; iki kutu özeti birebir aynıdır ve fark yalnız
  çit dışındaki gözlem sayısında görünür, 50'ye karşı 35.
- Aralık sayımları iki kümeyi ayırır: kuzeyde tek tepe 16–20 m³'te, ikizde iki tepe 12–16 ve
  24–28 m³ aralıklarında, ortanca ise 114 ve 110 sayımlı çukurun içindedir.
- Ortancanın çentiği geri koyarak örneklemeyle üretilir ve aynı ortanca için 0,920 m³ ile 3,146 m³
  genişliğinde çıkar; genişlik gözlem sayısına ve ortanca çevresindeki yoğunluğa bağlıdır.
- Kuzey ile merkezin çentikleri kesişmiyor; bu bir gösterim ipucudur ve tek başına bir sınama
  sonucu değildir.

#### Sonraki Adım

Bu derste iki kez aralık üretildi ve iki kez genişlik yazıldı, ama aralığın ne söylediği hiç
tanımlanmadı. Güven aralığı M15/K02'de bir araç olarak kullanılmıştı; sonraki ders aralığın
kendisini konu eder. Genişliğin gözlem sayısına nasıl bağlandığı ölçülür — gözlem sayısı dörde
katlandığında genişliğin ne olduğu sayılır — ve aralığın söylemedikleri açıkça yazılır. Sonunda iki
aralığın kesişmesi ele alınır: kesişme fark yok demek değildir ve bunun ispatı, farkın kendi
aralığının hesaplanmasıdır.

### Güven Aralığı Yorumu

Source: https://academia.sh/tr/kurslar/kesifsel-analiz/guven-araligi-yorumu

Doğu bölgesinin 24,674 m³'lük ortalaması geri koyarak örneklemeyle 23,894–25,431 m³ aralığına oturuyor ve genişlik 1,537 m³ çıkıyor, ama 557 okumanın yalnız 37 tanesi bu aralığın içinde: aralık gözlemlerin değil özetin aralığıdır. Gözlem sayısı 35'ten 139'a, 139'dan 557'ye çıkınca genişlik 6,601'den 3,009'a, oradan 1,459 m³'e iniyor. Kırk gözlemlik 120 örneklemin 113'ünde aralık kütle ortalamasını içeriyor. Kuzeyin iki dönemi 0,148 m³ boyunca kesişen iki aralık veriyor, farkın kendi aralığı ise 0,281–2,612 m³ ile sıfırı dışarıda bırakıyor.

Önceki iki derste iki kez aralık üretildi ve iki kez genişlik yazıldı, ama aralığın ne söylediği
tanımlanmadı. Güven aralığı bu müfredatta yeni değildir: deneyim ölçme kursunda bir **araç** olarak
kullanılmış, örneklem büyüklüğü ve çoklu karşılaştırma düzeltmesi orada hesaplanmıştı. O hesaplar
burada tekrarlanmaz. Bu derste aralığın kendisi konudur.

Aralık burada formülle değil **geri koyarak örneklemeyle** üretilir. Bu seçim bir kolaylık değildir:
formül yolu dağılım hakkında bir varsayım ister ve o varsayım okuma verisinde tartışmalıdır,
çekiliş yolu ise yalnız kümenin kendisini ister. Ölçü iki başlıkta toplanır: genişlik neye bağlıdır
ve aralık neyi söylemez. İkinci başlığın en pahalı maddesi sona bırakılır — iki aralığın kesişmesi,
iki ortalamanın farklı olmadığı anlamına gelmez ve bunun ispatı sayıyla verilir.

- **UI12. Güven aralığı bir ölçüm değil, bir yordamın çıktısıdır.** Kümeden aynı büyüklükte ve geri
  koyarak 1.000 kez çekilir, özet her çekilişte yeniden hesaplanır, çıkan değerlerin orta yüzde
  95'i aralık olarak yazılır.
- **UI13. Aralık gözlemlerin değil özetin aralığıdır.** Tek tek okumaların nerede durduğu hakkında
  hiçbir şey söylemez ve okumaların büyük çoğunluğu aralığın dışındadır.
- **UI14. Genişlik gözlem sayısına bağlıdır** ve gözlem sayısı dörde katlandığında genişlik yaklaşık
  yarıya iner. Hata payını yarılamanın bedeli dört katı gözlemdir.
- **UI15. Yüzde 95 tek bir aralığa değil yordama aittir.** Aynı yordamla kurulan aralıkların
  yaklaşık yüzde 95'i kütle değerini içerir; eldeki tek aralık için söylenebilecek şey budur.
- **UI16.** Aralık, kümenin kütleyi temsil ettiğini varsayar. Seçim yanlılığını ne ölçer ne
  düzeltir; yanlı bir kümede dar bir aralık, yanlış sayının çevresinde dar bir aralıktır.
- **UI17.** İki aralığın kesişmesi "fark yok" demek değildir. Fark ayrı bir sayıdır.
- **UI18.** Kararın okunduğu yer farkın kendi aralığıdır: sıfırın içeride olup olmadığına bakılır.

#### Aralık Nasıl Üretilir

```python
# kume.py — MODELDIR: K03-K04'un kurgu olcum agi ayni tohumla yeniden uretilir.
# 3.199 satirlik uzun bicimli okuma tablosu, 1.329 abone, uc donem, bes bolge.
import math

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


def uretec(t):
    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


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

OKUMA = []
for a in _k + _e:
    r = uretec(TOHUM + 7000 + a["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(
            a["taban"] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100
        if a["abone_no"] not in GECERLI:
            r()
            continue
        OKUMA.append({"abone_no": a["abone_no"], "bolge": a["bolge"],
                      "donem": DONEM[d], "tuketim_m3": t})
        r()


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


CEKILIS = 1000


def yuzdelik(s, p):
    i = p * (len(s) - 1)
    a = int(i)
    z = min(a + 1, len(s) - 1)
    return s[a] + (s[z] - s[a]) * (i - a)


def aralik(v, tohum, cekilis=CEKILIS):
    sec = uretec(tohum)
    n = len(v)
    d = sorted(ortalama([v[int(sec() * n)] for _ in range(n)]) for _ in range(cekilis))
    return yuzdelik(d, 0.025), yuzdelik(d, 0.975)


dogu = [o["tuketim_m3"] for o in OKUMA if o["bolge"] == "dogu"]
a, z = aralik(dogu, TOHUM + 301)
print(f"dogu ortalamasi {ortalama(dogu):.3f} m3, n={len(dogu)}, {CEKILIS} cekilis")
print(f"yuzde 95 guven araligi {a:.3f} - {z:.3f} m3, genislik {z - a:.3f} m3")
ic = sum(1 for x in dogu if a <= x <= z)
print(f"557 okumanin {ic} tanesi ({100 * ic / len(dogu):.2f} yuzde) bu araligin icinde")
```

```
dogu ortalamasi 24.674 m3, n=557, 1000 cekilis
yuzde 95 guven araligi 23.894 - 25.431 m3, genislik 1.537 m3
557 okumanin 37 tanesi (6.64 yuzde) bu araligin icinde
```

Yordam tek cümledir: elde kütle olmadığı için küme kütle yerine konur, içinden aynı büyüklükte ve
geri koyarak 1.000 kez çekilir, her çekilişte ortalama yeniden hesaplanır ve çıkan 1.000
ortalamanın orta yüzde 95'i aralık olarak yazılır. Doğu bölgesi için sonuç 23,894–25,431 m³'tür ve
hata payı, yani aralığın yarı genişliği, 0,769 m³'tür.

Son satır aralığın en sık karıştırılan yanını sayıya çeviriyor. Aralık 557 okumanın yalnız 37
tanesini içeriyor, yani yüzde 6,64'ünü. Aralık okumaların nerede olduğunu değil, **ortalamanın**
nerede olabileceğini bildirir. "Abonelerin yüzde 95'i 23,9 ile 25,4 m³ arasında tüketiyor" cümlesi
bu çıktıdan çıkarılamaz ve kümede yanlıştır.

Ayrım rapor dilinde şöyle korunur: aralık her zaman bir **özetin** adıyla yazılır — ortalamanın
aralığı, ortancanın çentiği, oranın aralığı. Adı yazılmadığında okuyucunun onu gözlemlerin aralığı
sanması beklenen bir yanlış anlamadır.

Yordamın tek varsayımı da açıkça durur: kümenin kütleyi temsil ettiği kabul edilir. Geri koyarak
örnekleme, elde olmayan kütle yerine eldeki kümeyi koyar ve bu değişimin bedeli küçük kümelerde
büyür. Kümede olmayan bir değer hiçbir çekilişte ortaya çıkamaz, bu yüzden aralık kümenin
görebildiği kadarını görür.

#### Genişlik Neye Bağlı

```python
# genislik.py — ayni bolgenin okumalari once karistirilir, sonra ic ice buyuyen
# uc altkume alinir: 35, 139, 557. Her adimda gozlem sayisi yaklasik dorde katlanir.
sec = uretec(TOHUM + 304)
kar = dogu[:]
for i in range(len(kar) - 1, 0, -1):
    j = int(sec() * (i + 1))
    kar[i], kar[j] = kar[j], kar[i]
onceki = None
for n in (35, 139, 557):
    alt = kar[:n]
    a2, z2 = aralik(alt, TOHUM + 305)
    g = z2 - a2
    ek = "" if onceki is None else f", bir onceki genisligin {g / onceki:.3f} kati"
    print(f"n={n:3d} ortalama {ortalama(alt):6.3f} aralik {a2:6.3f} - {z2:6.3f} "
          f"genislik {g:.3f}{ek}")
    onceki = g
```

```
n= 35 ortalama 24.242 aralik 20.825 - 27.426 genislik 6.601
n=139 ortalama 24.115 aralik 22.507 - 25.515 genislik 3.009, bir onceki genisligin 0.456 kati
n=557 ortalama 24.674 aralik 23.985 - 25.445 genislik 1.459, bir onceki genisligin 0.485 kati
```

Üç altküme iç içedir: 35 okuma 139'un içindedir, 139 da 557'nin. Gözlem sayısı her adımda yaklaşık
dörde katlanıyor ve genişlik her adımda yaklaşık yarıya iniyor — 6,601'den 3,009'a, oradan
1,459 m³'e. Oranlar 0,456 ve 0,485 çıkıyor, yani yarıya inmenin çevresinde.

Bunun planlamadaki karşılığı doğrudandır: hata payını yarılamak isteyen bir ölçüm dört katı gözlem
toplamak zorundadır. Otuz beş okumalık bir kırılımda ortalamanın 6,6 m³ genişliğinde bir aralığı
vardır ve o kırılımda 25 m³'lük tarife basamağı hakkında hiçbir şey söylenemez; aynı soruya
cevap verebilmek için gereken gözlem sayısı on altı katıdır. Bir kırılımı daha ince kesmenin bedeli
de burada görünür: her bölme gözlem sayısını düşürür ve düşen gözlem sayısı genişliği kökle ters
orantılı biçimde büyütür.

Ortalamaların da oynadığına dikkat edilmelidir: 24,242, 24,115 ve 24,674. Üç sayı da doğrudur ve
üçü de aynı bölgeden gelir. Aralarındaki fark, tam olarak aralığın ölçtüğü şeydir.

Genişliğin ikinci belirleyicisi kümenin kendi **değişkenliğidir**. Aynı gözlem sayısında, değerleri
birbirine yakın duran bir kırılım dar, geniş yayılmış bir kırılım ise geniş aralık verir. Analistin
elinde bu iki kaldıraçtan yalnız biri vardır: gözlem sayısı ölçüm planının konusudur, değişkenlik
ise ölçülen şeyin kendi özelliğidir. Bu yüzden dar aralık bir çözümleme başarısı değil, çoğunlukla
bir toplama kararının sonucudur.

#### Yüzde 95 Neyin Yüzde 95'i

```python
# kapsama.py — 557 okuma kutle kabul edilir, icinden 40 gozlemlik ornekler
# cekilir ve her ornek icin kisa bir aralik kurulur. Sayilan sey, araliklarin
# kacinin kutle ortalamasini icerdigidir.
KUTLE = ortalama(dogu)
sec = uretec(TOHUM + 308)
DENEME, ORNEK, KISA = 120, 40, 200
tutan = 0
for _ in range(DENEME):
    orn = [dogu[int(sec() * len(dogu))] for _ in range(ORNEK)]
    d = sorted(ortalama([orn[int(sec() * ORNEK)] for _ in range(ORNEK)])
               for _ in range(KISA))
    if yuzdelik(d, 0.025) <= KUTLE <= yuzdelik(d, 0.975):
        tutan += 1
print(f"kutle ortalamasi {KUTLE:.3f} m3 kabul edildi; {ORNEK} gozlemlik "
      f"{DENEME} ornekleme {KISA} cekilisle aralik kuruldu")
print(f"araliklarin {tutan} tanesi ({100 * tutan / DENEME:.1f} yuzde) kutle "
      f"ortalamasini iceriyor")
```

```
kutle ortalamasi 24.674 m3 kabul edildi; 40 gozlemlik 120 ornekleme 200 cekilisle aralik kuruldu
araliklarin 113 tanesi (94.2 yuzde) kutle ortalamasini iceriyor
```

Yüzde 95 sayısı eldeki tek aralığa ait değildir; **yordama** aittir. Bunu görmek için doğu
bölgesinin 557 okuması kütle sayıldı, içinden 40 gözlemlik 120 ayrı örneklem çekildi ve her biri
için aralık kuruldu. Kurulan 120 aralığın 113 tanesi kütle ortalamasını içeriyor, yani yüzde 94,2.

Cümlenin doğru biçimi budur: bu yordamla kurulan aralıkların yaklaşık yüzde 95'i kütle değerini
içerir. Eldeki tek aralık için "kütle ortalaması yüzde 95 olasılıkla içeridedir" denemez, çünkü
kütle ortalaması bir sayıdır ve ya içeridedir ya değildir; oynayan şey aralıktır, kütle değeri
değil.

Çıkan sayının 95 yerine 94,2 olması da bir bilgidir ve düzeltilmesi gereken bir sapma değildir. Kırk
gözlemlik örneklemlerde geri koyarak örnekleme aralığı bir miktar dar kurar; 120 deneme ile ölçülen
bu oranın kendi payı da yaklaşık iki puandır. Koşum sayısı büyütülse oran 95'e yaklaşır, ama
yaklaşmanın hızı da bu dersin ölçtüğü kuralın aynısına uyar.

Aralığın söylemedikleri bu koşumun dışında da kalır. Küme kütleyi temsil etmiyorsa — ağda yalnız
okunabilmiş sayaçlar varsa — aralık bu eksikliği ne görür ne düzeltir; dar bir aralık yalnızca
yanlış sayının çevresinde dar olur. Seçim yanlılığı bu konunun son dersinin işidir.

#### İki Aralığın Kesişmesi

```python
# kesisme.py — kuzeyin iki donemi: once iki ayri aralik, sonra farkin kendi
# araligi. Fark her cekiliste iki gruptan ayri ayri cekilerek yeniden hesaplanir.
k2 = [o["tuketim_m3"] for o in OKUMA
      if o["bolge"] == "kuzey" and o["donem"] == "2026-02"]
k3 = [o["tuketim_m3"] for o in OKUMA
      if o["bolge"] == "kuzey" and o["donem"] == "2026-03"]
a2, z2 = aralik(k2, TOHUM + 306)
a3, z3 = aralik(k3, TOHUM + 306)
print(f"kuzey 2026-02: n={len(k2)} ortalama {ortalama(k2):.3f} aralik {a2:.3f} - {z2:.3f}")
print(f"kuzey 2026-03: n={len(k3)} ortalama {ortalama(k3):.3f} aralik {a3:.3f} - {z3:.3f}")
print(f"iki aralik {min(z2, z3) - max(a2, a3):.3f} m3 boyunca kesisiyor")
sec = uretec(TOHUM + 307)
n2, n3 = len(k2), len(k3)
f = sorted(ortalama([k2[int(sec() * n2)] for _ in range(n2)])
           - ortalama([k3[int(sec() * n3)] for _ in range(n3)])
           for _ in range(CEKILIS))
fa, fz = yuzdelik(f, 0.025), yuzdelik(f, 0.975)
print(f"farkin kendi araligi: {ortalama(k2) - ortalama(k3):.3f} m3 "
      f"({fa:.3f} - {fz:.3f}), sifir iceride mi: {fa <= 0 <= fz}")
```

```
kuzey 2026-02: n=319 ortalama 20.324 aralik 19.491 - 21.193
kuzey 2026-03: n=239 ortalama 18.879 aralik 18.068 - 19.639
iki aralik 0.148 m3 boyunca kesisiyor
farkin kendi araligi: 1.446 m3 (0.281 - 2.612), sifir iceride mi: False
```

Kuzey bölgesinin iki dönemi yan yana kondu. İki aralık 0,148 m³ boyunca kesişiyor ve kesişmeye
bakan bir okuyucu "iki dönem arasında fark yok" sonucunu çıkarır. Bu sonuç yanlıştır ve
yanlışlığı bir yorum tercihi değil, hesapla gösterilebilecek bir şeydir.

Farkın kendi aralığı hesaplandığında 1,446 m³'lük gözlenen fark 0,281–2,612 m³ aralığına oturuyor
ve sıfır bu aralığın dışında kalıyor. Yani aynı veri, iki ayrı aralığa bakınca "belirsiz", farkın
aralığına bakınca "sıfırdan uzak" diyor. İkisinden doğru olanı ikincisidir, çünkü sorulan soru
farkın ne olduğudur ve fark ayrı bir sayıdır.

Nedeni kısaca şudur: iki ayrı aralık iki ayrı belirsizliği **tam boyuyla** yan yana koyar, oysa
farkın belirsizliği ikisinin toplamı kadar büyük değildir. Kesişmeme her zaman farkın sıfırdan uzak
olduğunu gösterir, ama kesişme hiçbir şey göstermez. Karar verilecekse bakılacak sayı tektir:
farkın aralığı ve sıfırın o aralıktaki yeri.

Uygulamadaki kural bundan çıkar. Bir raporda iki grubun aralığı yan yana basılıyorsa, karşılaştırma
yapılacak yer orası değildir; farkın aralığı ayrıca hesaplanıp ayrıca yazılır. İki aralıklı gösterim
her grubu kendi başına tanıtmak için yararlıdır, karşılaştırma için değil. Bu ayrım yazılmadığında
aynı çıktı iki farklı karar üretir ve hangisinin verildiği okuyucunun hangi satıra baktığına kalır.

#### Özet

- Güven aralığı formülle değil geri koyarak örneklemeyle üretildi: doğu bölgesinin 24,674 m³'lük
  ortalaması 1.000 çekilişte 23,894–25,431 m³ aralığına, yani 0,769 m³'lük hata payına oturdu.
- Aralık gözlemlerin değil özetin aralığıdır; 557 okumanın yalnız 37 tanesi, yüzde 6,64'ü, bu
  aralığın içindedir.
- Gözlem sayısı 35'ten 139'a, 139'dan 557'ye çıkınca genişlik 6,601'den 3,009'a, oradan 1,459 m³'e
  indi; hata payını yarılamanın bedeli dört katı gözlemdir.
- Yüzde 95 tek bir aralığa değil yordama aittir: 40 gözlemlik 120 örneklemin 113'ünde, yani yüzde
  94,2'sinde aralık kütle ortalamasını içerdi.
- Kuzeyin iki dönemi 0,148 m³ boyunca kesişen iki aralık verdi, ama farkın kendi aralığı
  0,281–2,612 m³ çıktı ve sıfırı dışarıda bıraktı; kesişme fark yok demek değildir.

#### Sonraki Adım

Farkın aralığı sıfırı dışarıda bıraktı ve bu, bir karara en yakın duran çıktıdır. Yine de tek
başına bir sınama değildir: sorulmayan soru, "hiçbir fark yokken bu büyüklükte bir farkın ne
sıklıkla ortaya çıkacağı"dır. Sonraki ders bu soruyu **yeniden karıştırma** ile cevaplar, sıfır
hipotezini, p değerini ve anlamlılık düzeyini karıştırma üzerinden tanımlar ve aynı iki grubu hem
eşleştirilmiş hem bağımsız sayarak sınar. p değeri iki kez basılır, etki büyüklüğü yanında durur ve
p değerinin ne olmadığı sayıyla gösterilir.

### Hipotez Testi Uygulaması

Source: https://academia.sh/tr/kurslar/kesifsel-analiz/hipotez-testi-uygulamasi

İki dönemde de okunan 1.101 abonede gözlenen fark 0,957 m³ ve bu tek fark iki ayrı p değeri veriyor: bağımsız sayımda 2.000 karıştırmanın 24'ü farkı aşıyor ve p 0,01249 çıkıyor, eşleştirilmiş sayımda 5'i aşıyor ve p 0,00300 oluyor. Varsayım denetimi eşleştirmenin gerçek olduğunu 0,213'lük korelasyonla gösteriyor; eşleştirme bozulduğunda p 0,01099'a geri dönüyor. Etki büyüklüğü 0,112 ve 0,089 olarak p'nin yanında duruyor. Aynı kümenin 275 çiftlik dörtte birinde fark 1,132 m³ ile daha büyük, p ise 0,10695 ile otuz beş kat büyük çıkıyor.

Önceki ders farkın kendi aralığını hesapladı ve sıfırın aralığın dışında kaldığını gördü. Bu bir
karara yakın duruyordu ama bir sınama değildi. Sınamanın sorduğu soru başkadır: hiçbir fark yokken,
gözlenen büyüklükte bir fark **kaç koşumda bir** ortaya çıkar.

Bu sorunun cevabı bu kursta tablodan okunmaz, koşumla sayılır. Keşifsel analiz konusunun ilk dersi
bölge etiketlerini rastgele yeniden dağıtıp doğu ile kuzey arasındaki farkın kaç koşumda bir
göründüğünü saymıştı; burada aynı yöntem bir sınama olarak adlandırılır ve asıl ölçü şudur:
**sınama seçimi bir varsayımdır ve varsayım değişince p değeri oynar.** Aynı iki grup, aynı gözlenen
fark, iki p değeri.

- **UI19. Sıfır hipotezi bir cümle değil bir işlemdir.** "İki grup arasında fark yok" varsayımı,
  etiketlerin gözlemler arasında değiştirilebilir olduğu anlamına gelir; **yeniden karıştırma
  sınaması** tam olarak bunu yapar ve farkı her karıştırmada yeniden hesaplar.
- **UI20. p değeri**, karıştırılmış kümelerin kaçının gözlenen fark kadar ya da ondan büyük bir
  fark ürettiğidir. Gözlenen koşum da sayıya katılır, bu yüzden pay ve payda birer artırılır.
- **UI21. Anlamlılık düzeyi** sınamadan **önce** yazılan bir eşiktir. Sonuç görüldükten sonra
  seçilen eşik, eşik değil bir sonuçtur.
- **UI22.** Sınama seçimi bir varsayımdır ve varsayım denetlenebilir. Eşleştirmenin gerçek olup
  olmadığı eşli okumaların korelasyonuyla ölçülür.
- **UI23.** Aynı gözlenen fark iki varsayımda iki p değeri verir. Fark değişmez, p değişir.
- **UI24. p değeri etkinin büyüklüğü değildir.** Etki büyüklüğü, farkın standart sapmaya bölünmüş
  hali, p'nin yanında ayrı bir sayı olarak yazılır.
- **UI25. p değeri sıfır hipotezinin olasılığı da değildir.** Ayrıca çözünürlüğü koşum sayısına
  bağlıdır: 2.000 karıştırmayla yazılabilecek en küçük p değeri 0,00050'dir.

#### Sıfır Hipotezi Bir İşlemdir

```python
# kume.py — MODELDIR: K03-K04'un kurgu olcum agi ayni tohumla yeniden uretilir.
# 3.199 satirlik uzun bicimli okuma tablosu, 1.329 abone, uc donem, bes bolge.
import math

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


def uretec(t):
    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


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

OKUMA = []
for a in _k + _e:
    r = uretec(TOHUM + 7000 + a["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(
            a["taban"] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100
        if a["abone_no"] not in GECERLI:
            r()
            continue
        OKUMA.append({"abone_no": a["abone_no"], "bolge": a["bolge"],
                      "donem": DONEM[d], "tuketim_m3": t})
        r()


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


KARISTIRMA = 2000
ikili = {}
for o in OKUMA:
    ikili.setdefault(o["abone_no"], {})[o["donem"]] = o["tuketim_m3"]
CIFT = [(v["2026-01"], v["2026-02"]) for v in ikili.values()
        if "2026-01" in v and "2026-02" in v]
ilk = [x for x, _ in CIFT]
son = [y for _, y in CIFT]
fark = [x - y for x, y in CIFT]
GOZLENEN = ortalama(fark)
print(f"iki donemde de okunan abone: {len(CIFT)}")
print(f"2026-01 ortalamasi {ortalama(ilk):.3f} m3, 2026-02 ortalamasi {ortalama(son):.3f} m3")
print(f"gozlenen fark {GOZLENEN:.3f} m3")


def karistir(v, sec):
    h = v[:]
    for i in range(len(h) - 1, 0, -1):
        j = int(sec() * (i + 1))
        h[i], h[j] = h[j], h[i]
    return h


sec = uretec(TOHUM + 401)
hepsi, n1 = ilk + son, len(ilk)
asan = 0
for _ in range(KARISTIRMA):
    h = karistir(hepsi, sec)
    if abs(ortalama(h[:n1]) - ortalama(h[n1:])) >= abs(GOZLENEN):
        asan += 1
p_bagimsiz = (asan + 1) / (KARISTIRMA + 1)
print(f"bagimsiz sayim: {KARISTIRMA} karistirmanin {asan} tanesi gozlenen farki asti, "
      f"p = {p_bagimsiz:.5f}")
```

```
iki donemde de okunan abone: 1101
2026-01 ortalamasi 20.638 m3, 2026-02 ortalamasi 19.681 m3
gozlenen fark 0.957 m3
bagimsiz sayim: 2000 karistirmanin 24 tanesi gozlenen farki asti, p = 0.01249
```

Soru bir rapor sorusudur: ilk dönemden ikinci döneme tüketim düştü mü. İki dönemde de okunabilmiş
1.101 abone var, ortalamalar 20,638 ve 19,681 m³ ve gözlenen fark 0,957 m³. Küme kurgudur ve
K03–K04'ün ölçüm ağından aynı tohumla yeniden üretilmiştir; 1.329 abonenin 1.101'inin iki dönemde
de okunabilmiş olması kümenin kendi eksikliğidir, bir seçim değil.

Sıfır hipotezi burada bir cümle olarak değil, bir işlem olarak kurulur. "Dönem etiketinin hiçbir
etkisi yok" demek, 2.202 okumanın hangisinin hangi döneme ait olduğunun rastgele olduğunu kabul
etmektir. Kod tam bunu yapar: bütün okumaları tek torbaya koyar, karıştırır, ilk 1.101'ini birinci
dönem sayar ve farkı yeniden hesaplar. Bu 2.000 kez tekrarlanır.

p değeri bu koşumdan bir **sayımdır**: karıştırmaların 24 tanesi, gözlenen 0,957 m³ kadar ya da
daha büyük bir fark üretti. Pay ve paydaya birer eklenir, çünkü gözlenen düzenlemenin kendisi de
olası düzenlemelerden biridir; p 0,01249 çıkar. Yüzde beşlik bir anlamlılık düzeyi sınamadan önce
yazılmışsa bu sonuç eşiğin altındadır.

Anlamlılık düzeyinin **önce** yazılması bu cümlenin taşıyıcı kısmıdır. Eşik sonuçtan sonra
seçildiğinde bir karar kuralı olmaktan çıkar ve sonucun kendisini tekrar eden bir etikete dönüşür;
o durumda sınama hiçbir şey elemiş olmaz. Eşiğin sayısı da bir gelenektir, bir ölçüm değildir: bu
kümede yüzde beş ile yüzde bir arasındaki seçim, aşağıdaki iki sayımın hangisine bakıldığından
daha fazla iş görür.

#### Eşleştirme Varsayımı

```python
# esli.py — ayni kume, baska bir varsayim: her satir bir abonenin iki okumasidir.
# Sifir hipotezi bu kez "her cift icinde farkin isareti rastgele" demektir.
sec = uretec(TOHUM + 403)
asan2 = 0
for _ in range(KARISTIRMA):
    t = sum(f if sec() < 0.5 else -f for f in fark) / len(fark)
    if abs(t) >= abs(GOZLENEN):
        asan2 += 1
p_esli = (asan2 + 1) / (KARISTIRMA + 1)


def sapma(v):
    m = ortalama(v)
    return math.sqrt(sum((x - m) ** 2 for x in v) / (len(v) - 1))


havuz = math.sqrt((sapma(ilk) ** 2 + sapma(son) ** 2) / 2)
ma, mb = ortalama(ilk), ortalama(son)
kov = sum((x - ma) * (y - mb) for x, y in CIFT) / (len(CIFT) - 1)
print(f"eslestirilmis sayim: {asan2} karistirma gozlenen farki asti, p = {p_esli:.5f}")
print(f"varsayim denetimi: esli okumalarin korelasyonu {kov / (sapma(ilk) * sapma(son)):.3f}")
print(f"fark ikisinde de {GOZLENEN:.3f} m3; etki buyuklugu "
      f"{GOZLENEN / havuz:.3f} (bagimsiz) ve {GOZLENEN / sapma(fark):.3f} (eslestirilmis)")
print(f"p orani {p_bagimsiz / p_esli:.2f} kat")
```

```
eslestirilmis sayim: 5 karistirma gozlenen farki asti, p = 0.00300
varsayim denetimi: esli okumalarin korelasyonu 0.213
fark ikisinde de 0.957 m3; etki buyuklugu 0.112 (bagimsiz) ve 0.089 (eslestirilmis)
p orani 4.17 kat
```

Aynı 2.202 okuma, ikinci bir varsayımla sayıldı. Bu kez her satır bir abonenin iki okumasıdır ve
sıfır hipotezi "her çift içinde farkın işareti rastgele" biçimini alır. Karıştırma da ona göre
değişir: etiketler gruplar arasında değil, her çiftin içinde yer değiştirir. Sonuç p 0,00300'dür.

Gözlenen fark iki sayımda da 0,957 m³'tür ve tek bir metreküp bile oynamamıştır. Oynayan tek sayı
p değeridir ve 4,17 kat küçülmüştür. Aradaki bütün fark, sınamayı seçerken alınan varsayımdan
gelir. İki sayım da yüzde beş eşiğinin altında kalır, ama yüzde bir eşiğinde kararlar ayrılır.

Varsayım denetimi ikinci satırdadır. Eşleştirmenin bir kazanç sağlaması için aynı abonenin iki
okumasının birbiriyle ilişkili olması gerekir; ölçülen korelasyon 0,213'tür. Bu, abonelerin
tüketim düzeyinin dönemler arasında kısmen korunduğu anlamına gelir ve eşleştirilmiş sayımın
neden daha küçük bir p verdiğini açıklar: abone ile abone arasındaki değişkenlik hesaptan düşer.

Etki büyüklüğü aynı satırda p ile yan yana durur: 0,112 ve 0,089. İkisi de farkın bir standart
sapmaya bölünmüş halidir ve ikisi de küçüktür. Ortalama tüketimin yüzde 4,6'sı kadar bir düşüşten
söz edilmektedir; p değerinin küçüklüğü bu düşüşü büyütmez.

#### Eşleştirme Yordamdan Gelmez

```python
# sahte.py — eslestirme bir yordam degil bir olgudur: ikinci donem okumalari
# baska abonelerle eslestirilirse fark ayni kalir, kazanc kaybolur.
sec = uretec(TOHUM + 404)
sahte = karistir(son, sec)
fs = [x - y for x, y in zip(ilk, sahte)]
sec = uretec(TOHUM + 405)
asan3 = 0
for _ in range(KARISTIRMA):
    t = sum(f if sec() < 0.5 else -f for f in fs) / len(fs)
    if abs(t) >= abs(ortalama(fs)):
        asan3 += 1
print(f"sahte eslestirme: ayni fark {ortalama(fs):.3f} m3, "
      f"p = {(asan3 + 1) / (KARISTIRMA + 1):.5f}")
print(f"farklarin standart sapmasi: gercek eslestirmede {sapma(fark):.3f}, "
      f"sahtede {sapma(fs):.3f} m3")
```

```
sahte eslestirme: ayni fark 0.957 m3, p = 0.01099
farklarin standart sapmasi: gercek eslestirmede 10.753, sahtede 12.275 m3
```

Eşleştirilmiş sınamanın küçük p değerini, sınamanın kendisinin ürettiği düşünülebilir. Bu koşum onu
sınar: ikinci dönem okumaları karıştırılıp başka abonelerle eşleştirilir, sonra tam olarak aynı
eşleştirilmiş sınama uygulanır.

Gözlenen fark değişmez, çünkü iki grubun ortalaması aynı kalmıştır: yine 0,957 m³. Ama p 0,01099'a
çıkar ve bağımsız sayımın verdiği 0,01249 ile aynı bölgeye döner. Nedeni son satırdadır: farkların
standart sapması 10,753'ten 12,275 m³'e yükselmiştir, yani gerçek eşleştirmenin düşürdüğü
değişkenlik geri gelmiştir.

Sonuç, sınama seçimi hakkındaki kuralı verir. Eşleştirilmiş sınama daha güçlü bir yöntem değildir;
**eşleştirme gerçekse** daha güçlüdür. Var olmayan bir eşleştirme uydurmak p değerini küçültmez,
yalnız hesabı yanlış yere taşır. Bu yüzden varsayım denetimi sınamanın bir ekiyle değil, önkoşulu
olarak yazılır. Denetimin kendisi de pahalı değildir: burada tek bir korelasyon sayısı ve tek bir
standart sapma karşılaştırması yetti, ikisi de sınamanın maliyetinin yanında hesaba katılmayacak
kadar küçüktür.

#### p Değerinin Ne Olmadığı

```python
# olcek.py — ayni etki, farkli gozlem sayisi. Alt kumeler ic ice secilir ve
# ayni eslestirilmis sinama her birine uygulanir.
sec = uretec(TOHUM + 406)
dizin = karistir(list(range(len(CIFT))), sec)
for bolen in (4, 2, 1):
    alt = [fark[i] for i in sorted(dizin[:len(CIFT) // bolen])]
    s2 = uretec(TOHUM + 403)
    a4 = 0
    for _ in range(KARISTIRMA):
        t = sum(f if s2() < 0.5 else -f for f in alt) / len(alt)
        if abs(t) >= abs(ortalama(alt)):
            a4 += 1
    print(f"n={len(alt):4d} fark {ortalama(alt):6.3f} m3 etki {ortalama(alt) / sapma(alt):.3f} "
          f"p = {(a4 + 1) / (KARISTIRMA + 1):.5f}")
print(f"{KARISTIRMA} karistirmayla yazilabilecek en kucuk p = {1 / (KARISTIRMA + 1):.5f}")
```

```
n= 275 fark  1.132 m3 etki 0.099 p = 0.10695
n= 550 fark  1.192 m3 etki 0.110 p = 0.01149
n=1101 fark  0.957 m3 etki 0.089 p = 0.00300
2000 karistirmayla yazilabilecek en kucuk p = 0.00050
```

Üç satır p değerinin ne olmadığını doğrudan gösteriyor. Dörtte birlik alt kümede gözlenen fark
1,132 m³'tür — tam kümedeki 0,957 m³'ten **büyük** — ve etki büyüklüğü de 0,099 ile 0,089'un
üstündedir. Buna rağmen p değeri 0,10695'tir, yani tam kümenin 0,00300'ünün otuz beş katı ve yüzde
beşlik eşiğin üstünde.

Aynı üç satır ters yönde de okunur: p küçüldükçe etki büyümemiştir. En küçük p'yi veren satır, en
küçük etkiyi veren satırdır. p değeri farkın büyüklüğünü değil, farkın gözlem sayısıyla birlikte
rastlantıdan ne kadar uzaklaştığını ölçer. Bu yüzden p tek başına raporlanmaz; yanında gözlem
sayısı ve etki büyüklüğü yazılır.

İkinci yanlış okuma da burada kapanır: p, sıfır hipotezinin doğru olma olasılığı değildir. Ölçtüğü
şey, sıfır hipotezi doğruyken bu kadar büyük bir farkın ne sıklıkla üretildiğidir — 0,00300 sayısı
"fark yok ihtimali binde üç" demek değil, "fark yokken bunun gibi bir sonuç 2.000 karıştırmanın
5'inde çıktı" demektir.

Son satır sayının kendi sınırını yazıyor: 2.000 karıştırmayla üretilebilecek en küçük p 0,00050'dir.
Hiçbir karıştırmanın gözlenen farkı aşamadığı bir sınamada yazılabilecek şey "p sıfırdır" değil,
"p 0,00050'den küçüktür"dür. Payın çözünürlüğünü koşum sayısı belirler.

#### Özet

- Sıfır hipotezi yeniden karıştırma sınamasında bir işlemdir: dönem etiketleri 2.000 kez rastgele
  dağıtılır, fark her seferinde yeniden hesaplanır ve gözlenen farkı aşan koşumlar sayılır.
- Aynı 1.101 çiftte gözlenen fark 0,957 m³'tür ve değişmez; p değeri bağımsız sayımda 0,01249,
  eşleştirilmiş sayımda 0,00300 çıkar, yani varsayım p'yi 4,17 kat oynatır.
- Eşleştirme varsayımı denetlenir: eşli okumaların korelasyonu 0,213'tür. Eşleştirme bozulduğunda
  farkların standart sapması 10,753'ten 12,275 m³'e çıkar ve p 0,01099 ile bağımsız sayıma döner.
- p değeri etki büyüklüğü değildir: 275 çiftlik alt kümede fark 1,132 m³ ve etki 0,099 ile daha
  büyükken p 0,10695'tir, tam kümenin otuz beş katı.
- p değeri sıfır hipotezinin olasılığı da değildir ve çözünürlüğü koşum sayısına bağlıdır; 2.000
  karıştırmayla yazılabilecek en küçük p 0,00050'dir.

#### Sonraki Adım

Bu derste tek bir soru soruldu ve tek bir p değeri yazıldı: iki dönem arasında fark var mı. Soru
seçildikten sonra sınamanın kendisi düzenli bir iştir ve varsayım denetimiyle birlikte savunulabilir
bir sonuç verir. Gerçek çözümlemede ise soru tek değildir. Aynı deney kümesinden hangi ölçütün
sayılacağı, hangi kırılımın açılacağı, hangi gözlem penceresinin alınacağı ve dengesiz atamanın ne
yapılacağı ayrı ayrı seçilir; her seçim yeni bir sınama demektir ve soruların sayısı payı büyütür.
Sonraki ders aynı deney kümesinden kaç farklı kararın çıktığını sayar ve kararın deneyden önce
yazılmasının bu payın ne kadarını kapattığını ölçer.

### A/B Testi Analizi

Source: https://academia.sh/tr/kurslar/kesifsel-analiz/ab-testi-analizi

Tasarımı bitmiş bir deneyin kümesi elde kaldığında çözümleyicinin önünde duran dört serbestlik derecesinin sayılması: ölçüt seçimi, kırılım, gözlem penceresi ve dengesiz atamanın ele alınışı 108 bileşim üretir. Deneyden önce yazılan tek karar 0,123 m³ fark, [-0,698, 0,952] oynama payı ve 0,786 p değeri verir; aynı kümeden gezilen 108 bileşimin 4'ü 0,05 eşiğinin altına iner, 9'u 0,10'un altına, 45'i artış 63'ü azalış yönü gösterir ve ortalama ölçütündeki fark -2,113 ile 1,119 m³ arasında gezinir. Gruplar arasındaki gerçek fark tam olarak sıfırdır. Kararın deneyden önce yazılması bileşim sayısını 108'den 1'e indirir.

Önceki ders tek bir sınama yaptı: iki grup, bir p değeri, yanında etki büyüklüğü. Verilen cevap
doğruydu ama tek bir soruya aitti. Tasarımı bitmiş bir deneyin kümesi elde kaldığında soru tek
değildir. Hangi ölçüt raporlanacak, kırılıma bakılacak mı, gözlem penceresi nerede kapanacak,
atama dengesiz kaldıysa ne yapılacak. Her seçim ayrı ayrı savunulabilir ve her seçim başka bir
sayı üretir.

Bu dersin sayısı **aynı deney kümesinden çıkan karar sayısıdır**. Deneyin tasarımı burada
kurulmaz: kaç abone gerektiği, deneyin niçin erken durdurulmadığı ve kaç karşılaştırmanın sınırı
nasıl sıkılaştırdığı Kullanıcı Deneyimi kursunun A/B ve Çok Değişkenli Test dersinde hesaplandı.
Bu ders tasarım bittikten sonra başlar: atama yapılmış, okumalar toplanmış, küme elde.

- **UI26.** Küme K03'ten devralınır ve **kurgudur**: 3.199 satırlık okuma tablosu, 1.329 abone,
  üç dönem, beş bölge. Tohum koda yazılıdır.
- **UI27.** Deney de **kurgudur**: dönem 1 taban okumadır, hatırlatma bildirimi dönem 1'den sonra
  gönderilmiştir, atama 70/30 dengesizdir. Atama okumalardan bağımsız çekilir ve hiçbir okumayı
  değiştirmez; **gruplar arasındaki gerçek fark tam olarak sıfırdır.**
- **UI28.** Sınama **yeniden karıştırmayla** (500 karıştırma), aralık **geri koyarak örneklemeyle**
  (1.000 çekim) üretilir. Dağılım tablosu, kritik değer ve hazır sınama işlevi kullanılmaz.
- **UI29.** "Anlamlı" eşiği 0,05'tir. Bu bir ölçüm değil bir karardır ve dersin sonunda payı
  yazılır.
- **UI30.** Dört serbestlik derecesi ve seçenek sayıları: ölçüt 2, kırılım 9, gözlem penceresi 3,
  dengesiz atamanın ele alınışı 2.

#### Deneyden Önce Yazılan Tek Karar

Deney kümesine giren abone, dönem 1 okuması bulunan abonedir. Birincil karar tek satırla yazılır:
ölçüt ortalama tüketim, kırılım yok, pencere dönem 2 ile 3, atama ham bırakılır.

```python
# ab_testi.py — MODELDIR. K03'un kurgu kumesi ayni tohumla uretilir, uzerine kurgu
# bir deney atamasi eklenir. Atama okumalardan bagimsiz cekilir ve hicbir okumayi
# degistirmez: gruplar arasindaki gercek fark tam olarak sifirdir.
import math

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


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

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


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


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

# Deney KURGUDUR: donem 1 taban okumadir, hatirlatma bildirimi donem 1'den sonra
# gonderilmistir ve atama 70/30 dengesizdir (uc aboneden ikisi B).
DENEY = []
for k in ABONE:
    d = OKUMA.get(k["abone_no"], {})
    if 1 not in d:
        continue
    r = uretec(TOHUM + 31000 + k["abone_no"])
    DENEY.append({"bolge": k["bolge"], "grup": "B" if r() < 0.70 else "A",
                  "taban_okuma": d[1], "d2": d.get(2), "d3": d.get(3)})

KARISTIRMA, ORNEKLEME = 500, 1000
rs = uretec(TOHUM + 55000)


def karistir(dizi):
    h = dizi[:]
    for i in range(len(h) - 1, 0, -1):
        j = int(rs() * (i + 1))
        h[i], h[j] = h[j], h[i]
    return h


def sinama(a, b):
    """Yeniden karistirma sinamasi: etiketler karisir, fark yeniden hesaplanir."""
    na, nb = len(a), len(b)
    goz = sum(b) / nb - sum(a) / na
    asan = 0
    for _ in range(KARISTIRMA):
        h = karistir(a + b)
        if abs(sum(h[na:]) / nb - sum(h[:na]) / na) >= abs(goz) - 1e-12:
            asan += 1
    return goz, asan / KARISTIRMA, na, nb


def aralik(a, b):
    """Geri koyarak ornekleme: fark 1.000 kez yeniden cekilen kumede hesaplanir."""
    na, nb, farklar = len(a), len(b), []
    for _ in range(ORNEKLEME):
        ya = sum(a[int(rs() * na)] for _ in range(na)) / na
        yb = sum(b[int(rs() * nb)] for _ in range(nb)) / nb
        farklar.append(yb - ya)
    farklar.sort()
    return farklar[24], farklar[974]


def deger(x, alanlar, olcut):
    d = [x[a] for a in alanlar if x[a] is not None]
    if not d:
        return None
    return sum(d) / len(d) if olcut == "ortalama" else (1.0 if max(d) >= 25 else 0.0)


def gruplar(alt, alanlar, olcut):
    va, vb = [], []
    for x in alt:
        v = deger(x, alanlar, olcut)
        if v is not None:
            (va if x["grup"] == "A" else vb).append(v)
    return va, vb


print(f"kurgu kume (tohum {TOHUM}): {len(ABONE)} abone, "
      f"{sum(len(v) for v in OKUMA.values())} okuma")
print(f"deney kumesi: {len(DENEY)} abone, "
      f"A {sum(1 for x in DENEY if x['grup'] == 'A')} / "
      f"B {sum(1 for x in DENEY if x['grup'] == 'B')}")

# Deneyden once yazilan tek karar: olcut ortalama, kirilim yok, pencere donem 2-3,
# atama ham birakilir.
va, vb = gruplar(DENEY, ("d2", "d3"), "ortalama")
goz, p, na, nb = sinama(va, vb)
alt, ust = aralik(va, vb)
print(f"\nbirincil karar  ortalama tuketim farki (B - A)")
print(f"  gozlenen fark : {goz:.3f} m3   ({na} + {nb} abone)")
print(f"  oynama payi   : [{alt:.3f}, {ust:.3f}] m3  (1.000 geri koyarak ornekleme)")
print(f"  p degeri      : {p:.3f}  ({KARISTIRMA} yeniden karistirma)")
```

```
kurgu kume (tohum 20260218): 1329 abone, 3199 okuma
deney kumesi: 1260 abone, A 402 / B 858

birincil karar  ortalama tuketim farki (B - A)
  gozlenen fark : 0.123 m3   (344 + 757 abone)
  oynama payi   : [-0.698, 0.952] m3  (1.000 geri koyarak ornekleme)
  p degeri      : 0.786  (500 yeniden karistirma)
```

Rapor edilecek satır budur: 0,123 m³'lük fark, yanında 1,650 m³ genişliğindeki oynama payı ve
0,786 p değeri. Aralık sıfırı içeriyor; karıştırma sınaması aynı büyüklükte bir farkı beş
koşumun dördünde üretiyor. Sayı 344 ile 757 abonenin ortalamasından geliyor ve grup boyları
eşit değil.

Bu satırın ilettiği tek bilgi, farkın oynama payının içinde kalmasıdır. Deneyin bittiği yer
burasıdır. Bundan sonrası çözümlemedir.

#### Dört Serbestlik Derecesi

Aynı küme üzerinde dört seçim vardır ve dördünün de savunulabilir birden fazla değeri bulunur.
**Ölçüt:** ortalama tüketim mi, üst tarife basamağına giren abone oranı mı. **Kırılım:** tüm küme,
beş bölgeden biri, ya da taban okumaya göre üç tarife basamağından biri. **Gözlem penceresi:**
iki dönem birden, yalnız dönem 2, yalnız dönem 3. **Denge:** dengesiz atama ham bırakılır ya da
B grubu A boyutuna kırpılır.

```python

# Dort serbestlik derecesi: olcut, kirilim, gozlem penceresi, dengesiz atamanin
# nasil ele alindigi. Bilesimlerin tamami gezilir ve kaci "anlamli" cikiyor sayilir.
OLCUT = ("ortalama", "ust basamak orani")
KIRILIM = ("tum kume", "kuzey", "guney", "dogu", "bati", "merkez",
           "10 alti", "10-25", "25 ustu")
PENCERE = {"donem 2-3": ("d2", "d3"), "yalniz donem 2": ("d2",),
           "yalniz donem 3": ("d3",)}
DENGE = ("ham", "kirpilmis")


def basamak(v):
    return "10 alti" if v < 10 else ("10-25" if v < 25 else "25 ustu")


def secilen(kir):
    if kir == "tum kume":
        return DENEY
    return [x for x in DENEY
            if x["bolge"] == kir or basamak(x["taban_okuma"]) == kir]


TARAMA = []
for olcut in OLCUT:
    for kir in KIRILIM:
        for pad, alanlar in PENCERE.items():
            for denge in DENGE:
                alt = [x for x in secilen(kir) if deger(x, alanlar, olcut) is not None]
                if denge == "kirpilmis":
                    a = [x for x in alt if x["grup"] == "A"]
                    alt = a + [x for x in alt if x["grup"] == "B"][:len(a)]
                va, vb = gruplar(alt, alanlar, olcut)
                if len(va) < 2 or len(vb) < 2:
                    continue
                TARAMA.append((olcut, kir, pad, denge) + sinama(va, vb))

anlamli = [s for s in TARAMA if s[5] <= 0.05]
poz = sum(1 for s in TARAMA if s[4] > 0)
ort = [s[4] for s in TARAMA if s[0] == "ortalama"]
print(f"gezilen bilesim : {len(TARAMA)}  "
      f"({len(OLCUT)} olcut x {len(KIRILIM)} kirilim x {len(PENCERE)} pencere "
      f"x {len(DENGE)} denge)")
print(f"p <= 0,05       : {len(anlamli)}")
print(f"p <= 0,10       : {sum(1 for s in TARAMA if s[5] <= 0.10)}")
print(f"yon             : {poz} bilesim artis, {len(TARAMA) - poz} bilesim azalis")
print(f"ortalama olcutunde fark araligi: {min(ort):.3f} ile {max(ort):.3f} m3")

print("\nolcut              kirilim   pencere          denge        fark       p    n(A)  n(B)")
for s in sorted(anlamli, key=lambda s: s[5]):
    print(f"{s[0]:<18} {s[1]:>8}   {s[2]:<15}  {s[3]:<10} {s[4]:>7.3f}  {s[5]:>6.3f}  "
          f"{s[6]:>5} {s[7]:>5}")
```

```
gezilen bilesim : 108  (2 olcut x 9 kirilim x 3 pencere x 2 denge)
p <= 0,05       : 4
p <= 0,10       : 9
yon             : 45 bilesim artis, 63 bilesim azalis
ortalama olcutunde fark araligi: -2.113 ile 1.119 m3

olcut              kirilim   pencere          denge        fark       p    n(A)  n(B)
ust basamak orani   25 ustu   yalniz donem 3   kirpilmis   -0.195   0.006     77    77
ust basamak orani   25 ustu   yalniz donem 3   ham         -0.160   0.014     77   157
ortalama               bati   yalniz donem 2   kirpilmis   -1.857   0.040     57    57
ust basamak orani    merkez   yalniz donem 3   kirpilmis   -0.189   0.040     53    53
```

Gerçek fark sıfırken 108 bileşimin 4'ü 0,05 eşiğinin altına, 9'u 0,10'un altına iniyor. Dördü de
çözümlemenin ürünüdür; kümede karşılığı olan hiçbir etki yoktur.

Tablonun asıl bilgisi eşik sayısı değil, iki sütunun dağılımıdır. Ortalama ölçütünde gözlenen fark
-2,113 ile 1,119 m³ arasında geziniyor; birincil kararın verdiği 0,123 m³ bu aralığın ortasında
duruyor. Bileşimlerin 45'i artış, 63'ü azalış yönü gösteriyor. Aynı kümeden "bildirim tüketimi
azalttı" ve "bildirim tüketimi artırdı" cümlelerinin ikisi de sayıyla desteklenebilir durumda.
Veri konuşmuyor; hangi bileşimin yazıldığı konuşuyor.

Anlamlı çıkan dört satırın ortak yanı üçüncü ve dördüncü sütunda görünüyor. Dördü de en dar
kırılımlardan geliyor: gözlem sayıları 53 ile 157 arasında, oysa birincil karar 1.101 abone
üzerinde çalışıyordu. Üçü en dar gözlem penceresinde, üçü kırpılmış dengede. Küçük kümede oynama
payı büyür, büyük payın içinden büyük bir gözlenen fark çekmek kolaylaşır ve eşik daha sık aşılır.
Kırpma da aynı yöne çalışır: 858 abonelik B grubunu 402'ye indirmek örneklemi küçültür.

#### Kararı Deneyden Önce Yazmak

Serbestliğin bedeli sayılabildiğine göre kapatılması da sayılabilir. Dört eksen sırayla deneyden
önce yazılır ve her adımda geriye kaç bileşim kaldığına bakılır.

```python

# Kararin deneyden once yazilmasi bilesim sayisini kacta kaca indiriyor.
YAZILI = (("olcut", 0, "ortalama"), ("pencere", 2, "donem 2-3"),
          ("kirilim", 1, "tum kume"), ("denge", 3, "ham"))
kalan = TARAMA
print("deneyden once yazilan       kalan bilesim   p <= 0,05   en kucuk p")
print(f"{'hicbiri':<27} {len(kalan):>13}   {sum(1 for s in kalan if s[5] <= 0.05):>9}"
      f"   {min(s[5] for s in kalan):>10.3f}")
yazilan = []
for ad, i, secim in YAZILI:
    yazilan.append(ad)
    kalan = [s for s in kalan if s[i] == secim]
    print(f"{'+ ' + ad:<27} {len(kalan):>13}   {sum(1 for s in kalan if s[5] <= 0.05):>9}"
          f"   {min(s[5] for s in kalan):>10.3f}")
print(f"\nkapanan bilesim: {len(TARAMA)} -> {len(kalan)}  ({len(TARAMA) - len(kalan)} secim "
      f"deneyden once elenir)")

en = min(TARAMA, key=lambda s: s[5])
bir = [s for s in TARAMA if s[:4] == ("ortalama", "tum kume", "donem 2-3", "ham")][0]
print(f"\nayni kumeden iki mesru cozumleme:")
print(f"  {bir[0]} / {bir[1]} / {bir[2]} / {bir[3]}: "
      f"fark {bir[4]:.3f}, p {bir[5]:.3f}, {bir[6]} + {bir[7]} abone")
print(f"  {en[0]} / {en[1]} / {en[2]} / {en[3]}: "
      f"fark {en[4]:.3f}, p {en[5]:.3f}, {en[6]} + {en[7]} abone")
print("gercek fark: 0,000 (atama okumalari degistirmedi)")
```

```
deneyden once yazilan       kalan bilesim   p <= 0,05   en kucuk p
hicbiri                               108           4        0.006
+ olcut                                54           1        0.040
+ pencere                              18           0        0.214
+ kirilim                               2           0        0.758
+ denge                                 1           0        0.772

kapanan bilesim: 108 -> 1  (107 secim deneyden once elenir)

ayni kumeden iki mesru cozumleme:
  ortalama / tum kume / donem 2-3 / ham: fark 0.123, p 0.772, 344 + 757 abone
  ust basamak orani / 25 ustu / yalniz donem 3 / kirpilmis: fark -0.195, p 0.006, 77 + 77 abone
gercek fark: 0,000 (atama okumalari degistirmedi)
```

Merdiven dört basamakta iniyor. Yalnız ölçütün yazılması 108 bileşimi 54'e, eşiği aşan bileşim
sayısını 4'ten 1'e indiriyor. Gözlem penceresi de yazıldığında geriye 18 bileşim kalıyor ve
eşiği aşan hiçbiri kalmıyor; en küçük p 0,006'dan 0,214'e çıkıyor. Dördü birden yazıldığında
bileşim sayısı 1'dir ve 107 seçim deneyden önce elenmiştir.

Kapanan şey bir yöntem kusuru değildir. Dört eksenin her değeri tek başına savunulabilir; sorun
değerin **sonuç görüldükten sonra** seçilebilmesidir. Deneyden önce yazılan karar bu sırayı
tersine çevirir ve seçimi sonuçtan bağımsız kılar.

Son blok payın kendi payını da gösteriyor. Birincil bileşimin p değeri ilk blokta 0,786, bu
blokta 0,772 çıktı. İki sayı aynı sınamanın iki koşumudur; aradaki fark 500 karıştırmanın kendi
oynama payıdır. Karıştırma sayısı artırılırsa bu fark daralır, sıfırlanmaz. Bir p değerinin
yanında kaç karıştırmayla üretildiği yazılmıyorsa, o p değerinin üçüncü basamağı okunmamalıdır.

Kursun kuralı burada bir maddeyle uzuyor: yanında **kaç bileşimin gezildiği** yazılmayan bir p
değeri, tek bir sınamanın p değeri değildir.

#### Özet

- Tasarımı bitmiş deneyin kümesinde dört serbestlik derecesi vardır: ölçüt (2), kırılım (9),
  gözlem penceresi (3), dengesiz atamanın ele alınışı (2). Bileşim sayısı 108'dir.
- Deneyden önce yazılan tek karar 0,123 m³ fark, [-0,698, 0,952] m³ oynama payı ve 0,786 p değeri
  verir; sayı 344 ile 757 abonenin ortalamasından gelir.
- Gruplar arasındaki gerçek fark sıfırken 108 bileşimin 4'ü 0,05'in, 9'u 0,10'un altına iner;
  45 bileşim artış, 63 bileşim azalış yönü gösterir ve ortalama ölçütündeki fark -2,113 ile
  1,119 m³ arasında gezinir.
- Eşiği aşan dört bileşim 53 ile 157 gözleme dayanır; küçük kırılımda oynama payı büyür ve eşik
  daha sık aşılır.
- Kararın deneyden önce yazılması bileşimi 108'den 1'e indirir; 107 seçim elenir ve en küçük p
  0,006'dan 0,772'ye çıkar.
- Aynı sınamanın iki koşumu 0,786 ile 0,772 verir; bu fark 500 karıştırmanın kendi payıdır.

#### Sonraki Adım

Bu ders bir farkın kaç bileşimde ölçüldüğünü saydı, ama saydığı şey hep iki grup arasındaki
farktı. Tüketimin bir bildirimle değil, sürekli bir değişkenle birlikte nasıl değiştiği hiç
sorulmadı. Sonraki ders ilişkiyi doğrudan modeller: en küçük kareler ders içinde yazılır, bir
katsayı hesaplanır ve katsayının yanına geri koyarak örneklemeyle payı basılır. Ardından kümeye
bir karıştırıcı değişken eklenir ve aynı katsayının işareti döner; açıklanan değişim oranının bu
dönmeyi haber vermediği yan yana gösterilir.

### Regresyon ile İlişki Modelleme

Source: https://academia.sh/tr/kurslar/kesifsel-analiz/regresyon-ile-iliski-modelleme

En küçük kareler ders içinde yazılır ve bir katsayının ne söylediği ile ne söylemediği ayrılır: sayaç yaşının tek değişkenli katsayısı -0,605 m³/yıl, oynama payı [-0,714, -0,503] ve açıklanan değişim oranı 0,098 çıkar. Karıştırıcı değişken olarak bölge taban düzeyi eklendiğinde aynı katsayı 1,825'e döner, payı [1,629, 2,003] olur ve iki aralık hiç kesişmez. Beş bölgenin her birinde bölge içi eğim pozitiftir (0,771 ile 2,416 arasında). Açıklanan değişim oranı 0,098'den 0,505'e çıkar ama işareti haber vermez; tümüyle rastgele bir sütun eklendiğinde 0,505363'ten 0,505377'ye yine yükselir. Artıkların bölge ortalaması tek değişkenli modelde -3,020 ile 2,481 arasında gezinir, karıştırıcı eklendiğinde -0,229 ile 0,295 arasına iner.

Önceki ders bir farkın kaç bileşimde ölçüldüğünü saydı, ama saydığı şey hep iki grup arasındaki
farktı. Tüketimin sürekli bir değişkenle birlikte nasıl değiştiği hiç sorulmadı. İki grup yerine
bir doğru sorulduğunda çıkan sayı bir fark değil, bir **katsayıdır**: değişken bir birim
arttığında tüketimin ortalama kaç birim değiştiği.

Bu dersin sayısı **katsayının oynama payıdır**. Yanında ikinci bir sayı durur ve dersin asıl
konusu odur: aynı katsayı, kümeye tek bir değişken eklendiğinde işaret değiştirir. Tahmin
doğruluğu ölçütleri burada hesaplanmaz; ortalama mutlak hata, yanlılık ve bant Süreç, Ekip ve
Teslimat kursunun Tahmin ve Planlama dersinde ölçüldü. Burada konu katsayının **yorumu ve
sınırıdır**.

- **UI31.** Küme K03'ten devralınır ve **kurgudur**. Abone düzeyine indirgenir: her abonenin
  değeri, dönemlerinin ortalamasıdır. 1.329 abonenin 1.260'ının en az bir okuması vardır.
- **UI32.** Sayaç yaşı alanı da **kurgudur** ve iki bileşeni birlikte taşır: bölgeye bağlı bir
  bileşen ile bölge içi tüketim sapmasına bağlı bir bileşen. Amaç iki yönü tek değişkende
  toplamaktır.
- **UI33.** En küçük kareler **ders içinde yazılır**: normal denklemler kurulur ve kısmi
  pivotlamalı elemeyle çözülür. Hazır çözücü kullanılmaz.
- **UI34.** Katsayının oynama payı **geri koyarak örneklemeyle** üretilir: abone listesi 1.000 kez
  yeniden çekilir ve her çekimde model yeniden kurulur.
- **UI35.** Karıştırıcı değişken **bölge taban düzeyidir**: bölgenin taban tüketimi hem sayaç
  yaşını hem tüketimi belirler.

#### Bir Katsayı ve Payı

En küçük kareler, artıkların karelerinin toplamını en küçük yapan katsayıları arar. Bu koşul
normal denklemleri verir ve denklem takımı elemeyle çözülür. Aşağıdaki blok kümeyi kurar,
çözücüyü yazar ve tek değişkenli modeli hesaplar.

```python
# regresyon.py — MODELDIR. K03'un kurgu kumesi ayni tohumla uretilir ve abone
# duzeyine indirgenir. Sayac yasi alani da KURGUDUR: bolgeye bagli bir bilesenle
# bolge ici tuketim sapmasina bagli bir bileseni birlikte tasir.
import math

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


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

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


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


ABONE, ELENEN = [], []
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])
    (ELENEN if r() < 0.046 else ABONE).append(
        {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2], "hane": hane,
         "memnuniyet": memnun})
GECERLI = {k["abone_no"] for k in ABONE}
OKUMA = {}
for k in ABONE + ELENEN:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(
            k["taban"] * math.exp((r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100
            + 0.5) / 100
        if k["abone_no"] in GECERLI:
            OKUMA.setdefault(k["abone_no"], []).append(t)
        r()

VERI = [dict(k, tuketim=sum(OKUMA[k["abone_no"]]) / len(OKUMA[k["abone_no"]]))
        for k in ABONE if k["abone_no"] in OKUMA]
BORT = {}
for x in VERI:
    BORT.setdefault(x["bolge"], []).append(x["tuketim"])
BORT = {b: sum(v) / len(v) for b, v in BORT.items()}
for x in VERI:
    r = uretec(TOHUM + 91000 + x["abone_no"])
    y = (14.0 - 0.75 * (x["taban"] - 20.5)
         + 0.15 * (x["tuketim"] - BORT[x["bolge"]]) + (r() + r() + r() - 1.5) * 2.4)
    x["yas"] = max(1, min(30, int(y + 0.5)))


def cozum(A, b):
    """Normal denklemleri kismi pivotlamali eleme ile cozer."""
    n = len(b)
    M = [A[i][:] + [b[i]] for i in range(n)]
    for i in range(n):
        p = max(range(i, n), key=lambda k: abs(M[k][i]))
        M[i], M[p] = M[p], M[i]
        for k in range(i + 1, n):
            f = M[k][i] / M[i][i]
            for j in range(i, n + 1):
                M[k][j] -= f * M[i][j]
    x = [0.0] * n
    for i in range(n - 1, -1, -1):
        x[i] = (M[i][n] - sum(M[i][j] * x[j] for j in range(i + 1, n))) / M[i][i]
    return x


def ekk(satirlar, alanlar):
    """En kucuk kareler: katsayilar ve aciklanan degisim orani."""
    p = len(alanlar) + 1
    A, b = [[0.0] * p for _ in range(p)], [0.0] * p
    for s in satirlar:
        v = [1.0] + [float(s[a]) for a in alanlar]
        for i in range(p):
            for j in range(p):
                A[i][j] += v[i] * v[j]
            b[i] += v[i] * s["tuketim"]
    kats = cozum(A, b)
    ort = sum(s["tuketim"] for s in satirlar) / len(satirlar)
    sst = sum((s["tuketim"] - ort) ** 2 for s in satirlar)
    sse = sum((s["tuketim"] - sum(k * x for k, x in
                                  zip(kats, [1.0] + [float(s[a]) for a in alanlar]))) ** 2
              for s in satirlar)
    return kats, 1 - sse / sst


ORNEKLEME = 1000
rs = uretec(TOHUM + 77000)


def katsayi_araligi(satirlar, alanlar, sira):
    """Geri koyarak ornekleme: abone listesi 1.000 kez yeniden cekilir."""
    n, cekilen = len(satirlar), []
    for _ in range(ORNEKLEME):
        ornek = [satirlar[int(rs() * n)] for _ in range(n)]
        cekilen.append(ekk(ornek, alanlar)[0][sira])
    cekilen.sort()
    return cekilen[24], cekilen[974]


print(f"kurgu kume (tohum {TOHUM}): {len(ABONE)} abone, "
      f"{sum(len(v) for v in OKUMA.values())} okuma")
print(f"en az bir okumasi olan: {len(VERI)} abone")
kats, r2 = ekk(VERI, ["yas"])
alt, ust = katsayi_araligi(VERI, ["yas"], 1)
print(f"\ntuketim = {kats[0]:.3f} + ({kats[1]:.3f}) x sayac_yasi")
print(f"  sayac yasi katsayisi : {kats[1]:.3f} m3/yil")
print(f"  oynama payi          : [{alt:.3f}, {ust:.3f}]  ({ORNEKLEME} geri koyarak ornekleme)")
print(f"  aciklanan degisim    : {r2:.4f}   ({len(VERI)} gozlem)")
```

```
kurgu kume (tohum 20260218): 1329 abone, 3199 okuma
en az bir okumasi olan: 1260 abone

tuketim = 28.352 + (-0.605) x sayac_yasi
  sayac yasi katsayisi : -0.605 m3/yil
  oynama payi          : [-0.714, -0.503]  (1000 geri koyarak ornekleme)
  aciklanan degisim    : 0.0984   (1260 gozlem)
```

Rapor edilecek satır şudur: sayaç yaşı bir yıl arttığında ortalama tüketim 0,605 m³ düşüyor,
oynama payı [-0,714, -0,503]. Aralık sıfırdan uzak ve dar; 1.260 gözleme dayanıyor. Bu sayı,
kursun kuralını sağlıyor gibi görünür.

Katsayının yanındaki üçüncü sayı, açıklanan değişim oranı, 0,098. Tüketimdeki değişimin yaklaşık
onda birini sayaç yaşı taşıyor. Bu düşük değer çoğu zaman "ilişki zayıf" diye okunur ve raporda
tek satırlık bir uyarıya döner. Bu okuma eksiktir. Açıklanan değişim oranı ilişkinin gücü
hakkında bir şey söyler; ilişkinin **yönü** hakkında hiçbir şey söylemez.

#### Karıştırıcı Değişken Katsayıyı Çevirir

Bölgenin taban tüketim düzeyi iki şeyi birden belirliyor: bölgede tüketim ne kadar yüksekse
sayaçlar o kadar yenidir ve tüketim de o kadar yüksektir. Bu tanım bir karıştırıcı değişkendir.
Modele girdiğinde katsayının ne olduğu ölçülebilir.

```python

# Karistirici degisken: bolge taban duzeyi hem sayac yasini hem tuketimi belirler.
for x in VERI:
    r = uretec(TOHUM + 99000 + x["abone_no"])
    x["rastgele"] = r() * 10

MODEL = [("yas", ["yas"]), ("yas + taban", ["yas", "taban"]),
         ("yas + taban + memnuniyet", ["yas", "taban", "memnuniyet"]),
         ("yas + taban + rastgele", ["yas", "taban", "rastgele"])]
print("model                       yas katsayisi   aciklanan degisim")
for ad, alanlar in MODEL:
    k, r2 = ekk(VERI, alanlar)
    print(f"{ad:<28} {k[1]:>13.3f}   {r2:>17.6f}")

alt2, ust2 = katsayi_araligi(VERI, ["yas", "taban"], 1)
k1, _ = ekk(VERI, ["yas"])
k2, _ = ekk(VERI, ["yas", "taban"])
print(f"\nkatsayi              gozlenen   oynama payi")
print(f"tek degiskenli       {k1[1]:>8.3f}   [{alt:.3f}, {ust:.3f}]")
print(f"karistirici eklenmis {k2[1]:>8.3f}   [{alt2:.3f}, {ust2:.3f}]")

print("\nbolge   n   ort. sayac yasi   ort. tuketim   bolge ici egim")
for b in sorted(BORT, key=lambda b: -BORT[b]):
    alt_b = [x for x in VERI if x["bolge"] == b]
    e = ekk(alt_b, ["yas"])[0][1]
    print(f"{b:<7} {len(alt_b):>3}   {sum(x['yas'] for x in alt_b)/len(alt_b):>14.2f}"
          f"   {BORT[b]:>12.3f}   {e:>14.3f}")
```

```
model                       yas katsayisi   aciklanan degisim
yas                                 -0.605            0.098357
yas + taban                          1.825            0.505363
yas + taban + memnuniyet             1.827            0.505764
yas + taban + rastgele               1.825            0.505377

katsayi              gozlenen   oynama payi
tek degiskenli         -0.605   [-0.714, -0.503]
karistirici eklenmis    1.825   [1.629, 2.003]

bolge   n   ort. sayac yasi   ort. tuketim   bolge ici egim
dogu    219             9.95         24.814            2.416
merkez  231            12.13         22.483            2.154
kuzey   363            13.60         20.351            1.777
guney   258            16.69         16.728            1.550
bati    189            18.84         13.935            0.771
```

Katsayı -0,605'ten 1,825'e döndü. İki oynama payı, [-0,714, -0,503] ile [1,629, 2,003], hiç
kesişmiyor. İki sayı da doğrudur ve ikisi de aynı kümeden çıkar; farklı olan tek şey hangi
değişkenlerin modelde bulunduğudur.

Üçüncü tablo mekanizmayı açıkta gösteriyor. Bölgeler arasında yön nettir: sayaçların ortalama
yaşı 9,95'ten 18,84'e çıkarken ortalama tüketim 24,814'ten 13,935'e düşüyor. Bölgelerin
**içinde** ise beş bölgenin beşinde de eğim pozitiftir; en düşüğü 0,771, en yükseği 2,416.
Tek değişkenli model bu iki yönü tek bir sayıda topluyor ve bölgeler arası yön ağır bastığı için
sonuç negatif çıkıyor. Karıştırıcı değişken modele girdiğinde bölgeler arası yön ayrılıyor ve
geriye bölge içi yön kalıyor.

İlk tablo, açıklanan değişim oranının ne söylemediğini iki ayrı şekilde veriyor. Birincisi: oran
0,098'den 0,505'e çıkarken katsayı işaret değiştirdi. Oranın yükselmesi, hangi işaretin doğru
olduğunu söylemiyor; yalnız artıkların küçüldüğünü söylüyor. İkincisi: modele tümüyle rastgele
üretilmiş bir sütun eklendiğinde oran 0,505363'ten 0,505377'ye **yükseliyor**. En küçük kareler
her yeni sütuna en kötü ihtimalle sıfır katsayı verebildiği için bu oran hiçbir zaman düşmez.
Değişken sayısı yazılmayan bir açıklanan değişim oranı karşılaştırılamaz.

Bir katsayı, "modeldeki öteki değişkenler sabitken" diye okunur ve bu okumanın tamamı modelin
içindekilere bağlıdır. Katsayının söylediği şey ilişkidir; nedensellik değildir ve modelde
bulunmayan bir değişkenin ne yaptığı hakkında hiçbir bilgi taşımaz.

#### Artıklar ve Payın Genişliği

Varsayım denetimi burada yapılır. Model doğru kurulmuşsa artıklar her kırılımda sıfır civarında
toplanmalı ve değişkenlikleri tahmin düzeyiyle birlikte oynamamalıdır.

```python

# Varsayim denetimi: artiklarin kirilimda ortalamasi ve tahmine gore degiskenligi.
def artiklar(satirlar, alanlar):
    kats = ekk(satirlar, alanlar)[0]
    cikti = []
    for s in satirlar:
        v = [1.0] + [float(s[a]) for a in alanlar]
        tahmin = sum(k * x for k, x in zip(kats, v))
        cikti.append((s, tahmin, s["tuketim"] - tahmin))
    return cikti


A1, A2 = artiklar(VERI, ["yas"]), artiklar(VERI, ["yas", "taban"])
print("bolge     n   artik ort. (yas)   artik ort. (yas + taban)")
for b in sorted(BORT, key=lambda b: -BORT[b]):
    d1 = [a for s, _, a in A1 if s["bolge"] == b]
    d2 = [a for s, _, a in A2 if s["bolge"] == b]
    print(f"{b:<7} {len(d1):>3}   {sum(d1)/len(d1):>16.3f}   {sum(d2)/len(d2):>24.3f}")


def sapma(d):
    o = sum(d) / len(d)
    return math.sqrt(sum((x - o) ** 2 for x in d) / len(d))


print("\ntahmin bandi      n   artik ortalamasi   artik degiskenligi")
sirali = sorted(A2, key=lambda t: t[1])
adim = len(sirali) // 4
for i in range(4):
    dilim = sirali[i * adim:(i + 1) * adim if i < 3 else len(sirali)]
    d = [a for _, _, a in dilim]
    print(f"{dilim[0][1]:>6.1f} - {dilim[-1][1]:>5.1f} {len(dilim):>5}   {sum(d)/len(d):>16.3f}"
          f"   {sapma(d):>18.3f}")

# Ayni katsayi, dortte bir gozlemle
r4 = uretec(TOHUM + 88000)
CEYREK = [x for x in VERI if r4() < 0.25]
a3, u3 = katsayi_araligi(CEYREK, ["yas", "taban"], 1)
k3 = ekk(CEYREK, ["yas", "taban"])[0][1]
print(f"\ngozlem sayisi   katsayi   oynama payi              genislik")
print(f"{len(VERI):>13}   {k2[1]:>7.3f}   [{alt2:.3f}, {ust2:.3f}]        {ust2 - alt2:>8.3f}")
print(f"{len(CEYREK):>13}   {k3:>7.3f}   [{a3:.3f}, {u3:.3f}]        {u3 - a3:>8.3f}")
```

```
bolge     n   artik ort. (yas)   artik ort. (yas + taban)
dogu    219              2.481                     -0.229
merkez  231              1.468                      0.295
kuzey   363              0.227                      0.031
guney   258             -1.526                     -0.118
bati    189             -3.020                      0.005

tahmin bandi      n   artik ortalamasi   artik degiskenligi
   8.7 -  16.5   315              0.293                3.891
  16.5 -  19.7   315             -0.168                3.988
  19.7 -  23.3   315             -0.346                4.852
  23.3 -  34.3   315              0.221                4.893

gozlem sayisi   katsayi   oynama payi              genislik
         1260     1.825   [1.629, 2.003]           0.374
          313     1.665   [1.341, 1.989]           0.648
```

İlk tablo tek değişkenli modelin kusurunu katsayıya bakmadan yakalıyor. Artıkların bölge
ortalaması -3,020 ile 2,481 arasında geziniyor: model doğu bölgesini sistemli olarak eksik,
batı bölgesini sistemli olarak fazla tahmin ediyor. Bir artık kümesinde kırılıma göre kalan bu
düzen, modelin dışarıda bıraktığı bir değişkenin imzasıdır. Karıştırıcı eklendiğinde aynı sayılar
-0,229 ile 0,295 arasına iniyor. Artık incelemesi, sonucu görmeden önce hangi modelin eksik
olduğunu söylüyor.

İkinci tablo bir varsayımın karşılanmadığını gösteriyor. Artıkların değişkenliği tahmin düzeyiyle
birlikte büyüyor: en düşük bantta 3,891, en yüksek bantta 4,893. Katsayı bu durumda hâlâ
hesaplanır, ama tek bir oynama payı bütün tahmin aralığı için geçerli değildir; yüksek tüketimli
abonelerde pay daha geniştir. Geri koyarak örnekleme bu düzensizliği kendiliğinden taşır, çünkü
kümeyi olduğu gibi yeniden çeker.

Üçüncü tablo payın neye bağlı olduğunu veriyor. Aynı model dörtte bir gözlemle kurulduğunda
katsayı 1,825'ten 1,665'e kayıyor ve oynama payının genişliği 0,374'ten 0,648'e çıkıyor. Gözlem
sayısı dörtte bire indi, genişlik yaklaşık iki katına çıktı. Küçük kırılımda hesaplanan bir
katsayının payı yazılmadan raporlanması, bu tablodaki iki satırı tek satır göstermektir.

#### Özet

- Sayaç yaşının tek değişkenli katsayısı -0,605 m³/yıl, oynama payı [-0,714, -0,503] ve açıklanan
  değişim oranı 0,098'dir; sayı 1.260 gözleme dayanır.
- Bölge taban düzeyi karıştırıcı değişken olarak eklendiğinde aynı katsayı 1,825 olur ve payı
  [1,629, 2,003] çıkar; iki aralık hiç kesişmez.
- Mekanizma kırılımda görünür: bölgeler arasında ortalama yaş yükselirken ortalama tüketim düşer,
  buna karşılık beş bölgenin beşinde de bölge içi eğim pozitiftir (0,771 ile 2,416 arasında).
- Açıklanan değişim oranı 0,098'den 0,505'e çıkarken katsayı işaret değiştirdi; oran yönü haber
  vermez ve tümüyle rastgele bir sütun eklendiğinde 0,505363'ten 0,505377'ye yine yükselir.
- Artıkların bölge ortalaması tek değişkenli modelde -3,020 ile 2,481 arasında gezinir, karıştırıcı
  eklendiğinde -0,229 ile 0,295 arasına iner; artık değişkenliği tahminle birlikte 3,891'den
  4,893'e büyür.
- Dörtte bir gözlemle aynı katsayının payı 0,374'ten 0,648 genişliğe çıkar.

#### Sonraki Adım

Bu ders bir katsayının kırılıma göre yön değiştirdiğini gösterdi, ama kırılım hep bölgeydi ve
zaman hiç işin içine girmedi. Aboneler ağa aynı anda katılmıyor ve aynı süre boyunca izlenmiyor.
Sonraki ders kümeyi giriş dönemine göre böler: elde tutma oranı hesaplanır, sonra giriş penceresi
ve gözlem penceresi değiştirilerek aynı kümeden kaç farklı oran çıktığı sayılır. Aynı yön
değiştirme burada bir kez daha görünür, bu kez katsayıda değil oranda: toplulaştırılmış oran bir
yönü, her kohortun oranı tersini gösterir.

### Kohort ve Huni Analizi

Source: https://academia.sh/tr/kurslar/kesifsel-analiz/kohort-ve-huni-analizi

Kohort tanımının aynı kümeden kaç ayrı elde tutma oranı çıkardığının sayılması: gözlenemeyen kohortu sıfır sayan kural 0,619, dışlayan kural 0,867 verir ve üç dönemlik pencerenin dışında 3.199 okumanın 843'ü kalır. Giriş penceresi dönem alındığında iki gözlenebilir kohort ve 0,009 oran açıklığı, beş hafta alındığında altı kohort ve 0,040 açıklık çıkar; en dar oynama payı 0,087 olduğu için açıklığın tamamı tek bir kohortun payının içine sığar. Huni yalnız toplulaştırma tersine dönmesi kadar geçer: toplulaştırılmış fark -0,237 iken gözlenebilir iki kohortun ikisinde de fark +0,083 ve +0,028'dir.

Önceki ders bir katsayının kırılıma göre yön değiştirdiğini gösterdi, ama kırılım hep bölgeydi ve
zaman hiç işin içine girmedi. Aboneler ağa aynı anda katılmıyor ve aynı süre boyunca izlenmiyor.
Bir aboneyi kayıt açıldıktan bir dönem sonra da okuyabiliyor olmak bir başarıdır ve bu başarının
oranına **elde tutma** denir.

Bu dersin sayısı **kohort tanımının oynattığı elde tutma oranıdır**. Kohort, giriş dönemine göre
kurulan kümedir ve tanımı iki karar içerir: giriş penceresi ne kadar geniştir ve gözlem penceresi
nerede kapanır. İki karar da savunulabilir, ikisi de aynı kümeden başka bir oran çıkarır. Dönüşüm
hunisinin adım hesabı burada tekrarlanmaz; adım dönüşümü, terk oranı ve kümülatif dönüşüm
Kullanıcı Deneyimi kursunun Dönüşüm Hunisi dersinde ölçüldü. Huni bu derse yalnız
**toplulaştırma tersine dönmesi** kadar girer.

- **UI36.** Küme K03'ten devralınır ve **kurgudur**: 3.199 okuma, 1.329 abone, üç dönem, beş bölge.
- **UI37.** Giriş haftası alanı da **kurgudur**: ölçüm ağı bölgelere aynı anda ulaşmamıştır, bu
  yüzden giriş dönemi dağılımı bölgeye bağlıdır.
- **UI38.** Okuma indisi bu derste **girişten sonraki dönemi** verir; takvim dönemi giriş dönemi
  ile indisin toplamından bir eksiktir ve takvim **üç dönemde kapanır**.
- **UI39.** Elde tutma, kohortun girişten $K$ dönem sonra hâlâ okuma üreten abonelerinin oranıdır.
  $K$ dönem sonrası takvimin dışına düşüyorsa oran **gözlenemez**.
- **UI40.** Gözlenemeyen aboneye iki kural uygulanabilir: **sıfır sayan** kural onu elde
  tutulmamış sayar, **dışlayan** kural onu paydadan çıkarır.
- **UI41.** Oynama payı **geri koyarak örneklemeyle** üretilir: kohort listesi 1.000 kez yeniden
  çekilir.
- **UI42.** Okuma yöntemi alanı da **kurgudur** ve iki ilişkiyi birlikte taşır: uzaktan okuma geç
  dönemlerde yaygınlaşmıştır ve kesintisi daha azdır.

#### Gözlem Penceresi Kohortu Keser

Takvim üç dönemde kapanıyor. Üçüncü dönemde ağa katılan bir abone için "bir dönem sonra hâlâ
okunabiliyor mu" sorusunun cevabı kümede yoktur. Bu abone elde tutulamamış değildir; **henüz
ölçülmemiştir**.

```python
# kohort.py — MODELDIR. K03'un kurgu kumesi ayni tohumla uretilir. Giris haftasi
# alani da KURGUDUR: olcum agi bolgelere ayni anda ulasmamistir, bu yuzden giris
# donemi dagilimi bolgeye baglidir. Okuma indisi girisden sonraki donemi verir;
# takvim donemi = giris donemi + indis - 1 ve takvim uc donemde kapanir.
import math

TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF
BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26),
         ("bati", 0.14, 14), ("merkez", 0.18, 23)]
GIRIS = {"dogu": [0.60, 0.28, 0.12], "merkez": [0.52, 0.30, 0.18],
         "kuzey": [0.40, 0.34, 0.26], "guney": [0.28, 0.36, 0.36],
         "bati": [0.16, 0.32, 0.52]}


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

KATILAN = []
for k in ABONE:
    if k["abone_no"] not in OKUMA:
        continue
    r = uretec(TOHUM + 61000 + k["abone_no"])
    e = ayrik(r(), GIRIS[k["bolge"]])
    hafta = e * 13 + 1 + int(r() * 13)
    KATILAN.append({"no": k["abone_no"], "bolge": k["bolge"], "hafta": hafta,
                    "kohort": e + 1, "blok": (hafta - 1) // 5 + 1,
                    "n": len(OKUMA[k["abone_no"]])})

PENCERE = 3


def gozlenebilir(x, K):
    """Kohortun K donem sonrasi uc donemlik takvimin icinde kaliyor mu."""
    return x["kohort"] + K <= PENCERE


def tutuldu(x, K):
    return x["n"] >= K + 1 and gozlenebilir(x, K)


def oran(alt, K, kural):
    pay = alt if kural == "sifir sayan" else [x for x in alt if gozlenebilir(x, K)]
    if not pay:
        return None, 0
    return sum(1 for x in pay if tutuldu(x, K)) / len(pay), len(pay)


print(f"kurgu kume (tohum {TOHUM}): {len(ABONE)} abone, "
      f"{sum(len(v) for v in OKUMA.values())} okuma")
print("giris kohortu (donem): " + ", ".join(
    f"{k}: {sum(1 for x in KATILAN if x['kohort'] == k)}" for k in (1, 2, 3))
    + f"   (en az bir okumasi olan {len(KATILAN)} abone)")
print(f"uc donemlik pencerenin disinda kalan okuma: "
      f"{sum(max(0, x['kohort'] + x['n'] - 1 - PENCERE) for x in KATILAN)}"
      f" / {sum(x['n'] for x in KATILAN)}")

for K in (1, 2):
    print(f"\nelde tutma (girisden {K} donem sonra)")
    print("kohort      n   gozlenebilir   sifir sayan   dislayan")
    for koh in (1, 2, 3):
        alt = [x for x in KATILAN if x["kohort"] == koh]
        o1, n1 = oran(alt, K, "sifir sayan")
        o2, n2 = oran(alt, K, "dislayan")
        print(f"{koh:>6} {len(alt):>6} {n2:>14}   {o1:>11.3f}   "
              + (f"{o2:>8.3f}" if o2 is not None else f"{'--':>8}"))
    o1, _ = oran(KATILAN, K, "sifir sayan")
    o2, n2 = oran(KATILAN, K, "dislayan")
    print(f"{'toplu':>6} {len(KATILAN):>6} {n2:>14}   {o1:>11.3f}   {o2:>8.3f}")
```

```
kurgu kume (tohum 20260218): 1329 abone, 3199 okuma
giris kohortu (donem): 1: 488, 2: 412, 3: 360   (en az bir okumasi olan 1260 abone)
uc donemlik pencerenin disinda kalan okuma: 843 / 3199

elde tutma (girisden 1 donem sonra)
kohort      n   gozlenebilir   sifir sayan   dislayan
     1    488            488         0.871      0.871
     2    412            412         0.862      0.862
     3    360              0         0.000         --
 toplu   1260            900         0.619      0.867

elde tutma (girisden 2 donem sonra)
kohort      n   gozlenebilir   sifir sayan   dislayan
     1    488            488         0.648      0.648
     2    412              0         0.000         --
     3    360              0         0.000         --
 toplu   1260            488         0.251      0.648
```

Rapora girecek sayı, bir dönemlik elde tutma için 0,619 mu 0,867 mi. İkisi de aynı kümeden ve
aynı tanımdan çıkıyor; ayrıldıkları tek yer, gözlenemeyen 360 abonenin ne sayıldığı. Sıfır sayan
kural onları elde tutulmamış kabul ediyor ve oranı 0,248 aşağı çekiyor. İki dönemlik elde tutmada
fark daha da büyük: 0,251 ile 0,648.

Gözlenemeyen aboneyi sıfır saymak bir ölçüm değil bir varsayımdır ve bu varsayım kümede
karşılanmıyor. Kohort 3'ün 360 abonesi için sonraki dönemin okuması **hiç toplanmamıştır**;
toplanmış olsaydı ilk iki kohortun 0,871 ve 0,862 oranlarına yakın bir sayı vermesi beklenir.

Üçüncü satır bu kesilmenin boyutunu veriyor: 3.199 okumanın 843'ü üç dönemlik takvimin dışına
düşüyor. Kohort tanımı kümeyi kesiyor ve kesilen parça küçük değil.

#### Giriş Penceresi Kohort Sayısını Değiştirir

Kohortun ikinci kararı giriş penceresinin genişliğidir. Dönem yerine beş haftalık bloklar
alınırsa aynı aboneler sekiz kohorta dağılır. Her kohortun oranının yanına payı da basılır.

```python

# Giris penceresi degisince ayni kumeden kac ayri oran cikiyor.
ORNEKLEME = 1000
rs = uretec(TOHUM + 44000)


def oran_araligi(alt, K):
    """Geri koyarak ornekleme: kohort listesi 1.000 kez yeniden cekilir."""
    n, cekilen = len(alt), []
    for _ in range(ORNEKLEME):
        cekilen.append(sum(1 for _ in range(n) if tutuldu(alt[int(rs() * n)], K)) / n)
    cekilen.sort()
    return cekilen[24], cekilen[974]


def tara(alan, ad):
    anahtarlar = sorted({x[alan] for x in KATILAN})
    print(f"\ngiris penceresi: {ad} -> {len(anahtarlar)} kohort   "
          "(dislayan kural, 1 donem)")
    print("kohort      n   elde tutma   oynama payi          genislik")
    genislikler, oranlar = [], []
    for a in anahtarlar:
        alt = [x for x in KATILAN if x[alan] == a and gozlenebilir(x, 1)]
        if len(alt) < 10:
            print(f"{a:>6} {len(alt):>6}   {'gozlenemez':>10}")
            continue
        o = sum(1 for x in alt if tutuldu(x, 1)) / len(alt)
        d, u = oran_araligi(alt, 1)
        genislikler.append(u - d)
        oranlar.append(o)
        print(f"{a:>6} {len(alt):>6}   {o:>10.3f}   [{d:.3f}, {u:.3f}]  {u - d:>10.3f}")
    print(f"  oran acikligi {max(oranlar) - min(oranlar):.3f}, "
          f"en dar pay {min(genislikler):.3f}, en genis pay {max(genislikler):.3f}")
    return oranlar


d3 = tara("kohort", "donem (13 hafta)")
d8 = tara("blok", "bes hafta")
print(f"\nayni kumeden cikan elde tutma orani sayisi: {len(d3)} ve {len(d8)}")
print(f"donem tanimiyla aralik {min(d3):.3f} - {max(d3):.3f}, "
      f"bes haftalik tanimla {min(d8):.3f} - {max(d8):.3f}")
```

```

giris penceresi: donem (13 hafta) -> 3 kohort   (dislayan kural, 1 donem)
kohort      n   elde tutma   oynama payi          genislik
     1    488        0.871   [0.840, 0.898]       0.057
     2    412        0.862   [0.828, 0.896]       0.068
     3      0   gozlenemez
  oran acikligi 0.009, en dar pay 0.057, en genis pay 0.068

giris penceresi: bes hafta -> 8 kohort   (dislayan kural, 1 donem)
kohort      n   elde tutma   oynama payi          genislik
     1    181        0.878   [0.829, 0.923]       0.094
     2    185        0.854   [0.805, 0.903]       0.097
     3    184        0.891   [0.848, 0.935]       0.087
     4    174        0.856   [0.805, 0.908]       0.103
     5    155        0.852   [0.800, 0.903]       0.103
     6     21        0.857   [0.667, 1.000]       0.333
     7      0   gozlenemez
     8      0   gozlenemez
  oran acikligi 0.040, en dar pay 0.087, en genis pay 0.333

ayni kumeden cikan elde tutma orani sayisi: 2 ve 6
donem tanimiyla aralik 0.862 - 0.871, bes haftalik tanimla 0.852 - 0.891
```

Giriş penceresi daraldığında raporlanabilir oran sayısı 2'den 6'ya çıkıyor ve oranlar arasındaki
açıklık 0,009'dan 0,040'a genişliyor. Bir kohort matrisine bakan kişi bu genişlemeyi bir örüntü
diye okuyabilir: üçüncü blok 0,891, beşinci blok 0,852, aradaki 4 puanlık düşüş bir eğilim gibi
görünür.

Payların sütunu bu okumayı kapatıyor. En dar oynama payı 0,087 genişliğinde; altı blok arasındaki
0,040'lık açıklığın tamamı **tek bir kohortun payının içine sığıyor**. Blokların ikişer ikişer
farkları da payların içinde kalıyor. İnce kohort tanımı yeni bilgi üretmedi, aynı bilgiyi daha çok
sayıya böldü ve her sayının payını büyüttü.

Altıncı blok bunun uç örneği. Yirmi bir gözlenebilir aboneye dayanan oran 0,857, payı ise
[0,667, 1,000]; genişliği 0,333, yani beş kohortun payının üç katından fazla. Yedinci ve sekizinci
bloklar tümüyle gözlem penceresinin dışında kalıyor ve hiç oran üretmiyor. Kohort tanımı
inceldikçe gözlenemeyen kohort sayısı da artıyor.

#### Toplulaştırılmış Oran ve Kohortların Oranı

Kohortun ne işe yaradığı, toplulaştırılmış bir oranın yanına konduğunda görünür. Kümede iki okuma
yöntemi var ve huninin iki adımı şudur: kohorta giriş, sonraki dönemde okuma.

```python

# Okuma yontemi alani da KURGUDUR ve iki iliskiyi birlikte tasir: uzaktan okuma
# gec donemlerde yayginlasmistir ve kesintisi daha azdir.
YONTEM_TABAN = {1: 0.28, 2: 0.55, 3: 0.80}
for x in KATILAN:
    r = uretec(TOHUM + 71000 + x["no"])
    p = YONTEM_TABAN[x["kohort"]] + (0.10 if x["n"] >= 2 else -0.10)
    x["yontem"] = "uzaktan" if r() < p else "yerinde"

YON = ("yerinde", "uzaktan")


def fark_araligi(a, b, K):
    na, nb, cekilen = len(a), len(b), []
    for _ in range(ORNEKLEME):
        oa = sum(1 for _ in range(na) if tutuldu(a[int(rs() * na)], K)) / na
        ob = sum(1 for _ in range(nb) if tutuldu(b[int(rs() * nb)], K)) / nb
        cekilen.append(ob - oa)
    cekilen.sort()
    return cekilen[24], cekilen[974]


print("huni: kohorta giris -> sonraki donemde okuma")
print("\nkohort   yerinde okuma      uzaktan okuma      fark     oynama payi")
for koh in (1, 2, 3):
    alt = [x for x in KATILAN if x["kohort"] == koh]
    a = [x for x in alt if x["yontem"] == "yerinde"]
    b = [x for x in alt if x["yontem"] == "uzaktan"]
    if not gozlenebilir(alt[0], 1):
        print(f"{koh:>6}   {'--':>5} ({len(a):>3})       {'--':>5} ({len(b):>3})"
              f"        --   gozlenemez")
        continue
    oa = sum(1 for x in a if tutuldu(x, 1)) / len(a)
    ob = sum(1 for x in b if tutuldu(x, 1)) / len(b)
    d, u = fark_araligi(a, b, 1)
    print(f"{koh:>6}   {oa:.3f} ({len(a):>3})       {ob:.3f} ({len(b):>3})"
          f"    {ob - oa:>+.3f}   [{d:+.3f}, {u:+.3f}]")
a = [x for x in KATILAN if x["yontem"] == "yerinde"]
b = [x for x in KATILAN if x["yontem"] == "uzaktan"]
oa = sum(1 for x in a if tutuldu(x, 1)) / len(a)
ob = sum(1 for x in b if tutuldu(x, 1)) / len(b)
d, u = fark_araligi(a, b, 1)
print(f"{'toplu':>6}   {oa:.3f} ({len(a):>3})       {ob:.3f} ({len(b):>3})"
      f"    {ob - oa:>+.3f}   [{d:+.3f}, {u:+.3f}]")

print("\nyontemin kohort bilesimi (satir yuzdesi)")
for y in YON:
    alt = [x for x in KATILAN if x["yontem"] == y]
    print(f"  {y:<8} " + "  ".join(
        f"kohort {k}: {sum(1 for x in alt if x['kohort'] == k) / len(alt):.3f}"
        for k in (1, 2, 3)))
```

```
huni: kohorta giris -> sonraki donemde okuma

kohort   yerinde okuma      uzaktan okuma      fark     oynama payi
     1   0.843 (325)       0.926 (163)    +0.083   [+0.028, +0.139]
     2   0.844 (154)       0.872 (258)    +0.028   [-0.041, +0.099]
     3      -- ( 56)          -- (304)        --   gozlenemez
 toplu   0.755 (535)       0.519 (725)    -0.237   [-0.284, -0.184]

yontemin kohort bilesimi (satir yuzdesi)
  yerinde  kohort 1: 0.607  kohort 2: 0.288  kohort 3: 0.105
  uzaktan  kohort 1: 0.225  kohort 2: 0.356  kohort 3: 0.419
```

Toplulaştırılmış satır tek bir cümle söylüyor: uzaktan okunan sayaçlarda elde tutma 0,237 puan
düşük ve payı [-0,284, -0,184], sıfırdan uzakta. Bu sayı ve bu pay, kursun kuralının istediği
biçimde yazılmıştır ve yanlıştır.

Kohort satırları tersini gösteriyor. Birinci kohortta uzaktan okuma 0,083 puan **önde** ve payı
[+0,028, +0,139], sıfırı içermiyor. İkinci kohortta 0,028 puan önde, payı sıfırı içeriyor.
Üçüncü kohort gözlenemiyor. Toplulaştırılmış oranın gösterdiği yönü **hiçbir kohort
göstermiyor**: ikisi tersini söylüyor, biri hiçbir şey söylemiyor.

Bu olguya **toplulaştırma tersine dönmesi** denir ve mekanizması son tabloda duruyor. Yerinde
okunan sayaçların yüzde 60,7'si birinci kohortta; uzaktan okunanların yüzde 41,9'u üçüncü
kohortta. Üçüncü kohort gözlem penceresi yüzünden sıfır sayılıyor, dolayısıyla uzaktan okumanın
toplulaştırılmış oranı ağırlıklı olarak **ölçülememiş** abonelerden geliyor. İki yöntemin farkı
değil, iki yöntemin kohort bileşimi ölçülmüştür.

Toplulaştırılmış bir oran, kohortlar arasında oran farkı **ve** bileşim farkı varsa hiçbir
kohortu tarif etmez. Bileşim yazılmadan raporlanan bir toplulaştırılmış oran, bir ölçüm değil bir
ortalama alma kararıdır.

#### Özet

- Gözlenemeyen kohorta uygulanan kural aynı kümeden iki oran çıkarır: bir dönemlik elde tutma
  sıfır sayan kuralla 0,619, dışlayan kuralla 0,867; iki dönemlikte 0,251 ile 0,648.
- Üç dönemlik gözlem penceresinin dışında 3.199 okumanın 843'ü kalır; kohort tanımı kümeyi keser.
- Giriş penceresi dönemden beş haftaya inince raporlanabilir oran sayısı 2'den 6'ya, oran açıklığı
  0,009'dan 0,040'a çıkar; en dar oynama payı 0,087 olduğu için açıklığın tamamı tek bir kohortun
  payının içine sığar.
- Yirmi bir aboneye dayanan altıncı blokta oran 0,857, payı [0,667, 1,000] ve genişliği 0,333;
  yedinci ve sekizinci bloklar tümüyle gözlem penceresinin dışındadır.
- Toplulaştırma tersine dönmesi: toplulaştırılmış fark -0,237 ve payı sıfırdan uzakken,
  gözlenebilir iki kohortta fark +0,083 ve +0,028'dir. Yerinde okunanların yüzde 60,7'si birinci,
  uzaktan okunanların yüzde 41,9'u üçüncü kohorttadır.

#### Sonraki Adım

Üç derste sayının yanına payı yazıldı ve payı büyüten üç kaynak sayıldı: bileşim sayısı, modelde
bulunmayan değişken, kohort tanımı. Üçünde de küme verilmiş kabul edildi. Kursun son dersi bu
kabulü kaldırır: küme zaten okunabilmiş sayaçlardan ve en az bir okuma üretmiş abonelerden
oluşuyor, yani ölçülen şey ağın kendisi değil ağın görünen kısmı. Aynı derste gürültüden kaç bulgu
üretilebildiği sayılır ve bu sayı beklenen değerle karşılaştırılır.

### Yanıltıcı Analizler

Source: https://academia.sh/tr/kurslar/kesifsel-analiz/yaniltici-analizler

Kümenin kendisinin bir seçim olduğunun ve gürültünün bulgu üretebildiğinin sayılması: ağdaki bütün sayaçların kütlesinde doğu ile kuzey arasındaki fark 4,659 m³, okunabilmiş sayaçların örnekleminde 4,463 m³, sıfır okumalar atılınca 4,655 m³ ve yalnız üç dönem kalan abonelerde 4,454 m³ çıkar; dört kararın açıklığı 0,206 m³'tür. 1.329 abonenin 69'u hiçbir tabloda görünmez. Yirmi kırılımlık on tarama tümüyle rastgele bir sonuç değişkeni üzerinde 200 sınama yapar ve 11 bulgu verir; beklenen 10,0'dır ve on taramanın 7'sinde en az bir bulgu çıkar. Kurs kapanışında on üç dersin gözlenen sayısı, oynama payı ve kararın değişip değişmediği tek tabloda toplanır.

Üç derste sayının yanına payı yazıldı ve payı büyüten üç kaynak sayıldı: bileşim sayısı, modelde
bulunmayan değişken, kohort tanımı. Üçünde de küme verilmiş kabul edildi. Bu ders o kabulü
kaldırır. Küme ağın kendisi değil, ağın **görünen kısmıdır**: okunabilmiş sayaçlardan ve en az
bir okuma üretmiş abonelerden oluşur.

Bu dersin sayısı iki tanedir. Birincisi **eleme kararlarının rapor edilen farkı ne kadar
oynattığı**, ikincisi **gürültüden üretilebilen bulgu sayısı**. İkisi de aynı şeye çıkar: bir
sayının payı yalnız örneklemden değil, o sayıya giden yolda kaç kez seçim yapıldığından da gelir.

- **UI43.** Küme K03'ten devralınır ve **kurgudur**. Bu derste elenen sayaçların okumaları da
  saklanır, böylece **kütle** ile **örneklem** yan yana konabilir.
- **UI44.** Kütle, ağdaki bütün sayaçların okumalarıdır; örneklem, kayda girebilmiş sayaçların
  okumalarıdır. Aradaki eleme kümenin üretiminde vardır ve **ölçülen değerden bağımsız çekilir**.
- **UI45.** İki eleme kararı daha sınanır: sıfır yazılmış okumaların atılması ve yalnız üç dönem
  boyunca kalan abonelerin sayılması.
- **UI46.** Gürültü taraması için sonuç değişkeni **tümüyle rastgele** çekilir; kırılımlar gerçek
  kümeden alınır. Hiçbir kırılımda gerçek bir etki yoktur.
- **UI47.** Yirmi kırılım, on tarama, 200 karıştırma, eşik 0,05. Eşik bir karardır ve beklenen
  bulgu sayısı bu eşikten hesaplanır.

#### Küme Kendisi Bir Seçimdir

Kursun çıpası doğu ile kuzey arasındaki farktır. Bu fark, hangi satırların sayıldığına göre
değişiyor.

```python
# yaniltici.py — MODELDIR. K03'un kurgu kumesi ayni tohumla uretilir, ama bu kez
# elenen sayaclarin okumalari da saklanir: kutle ile orneklem yan yana konur.
import math

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


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

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


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


ABONE, ELENEN = [], []
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])
    (ELENEN if r() < 0.046 else ABONE).append(
        {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2], "hane": hane,
         "memnuniyet": memnun})
GECERLI = {k["abone_no"] for k in ABONE}
KUTLE, ORNEKLEM = [], []
for k in ABONE + ELENEN:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(
            k["taban"] * math.exp((r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100
            + 0.5) / 100
        satir = {"abone_no": k["abone_no"], "bolge": k["bolge"], "donem": d + 1,
                 "tuketim_m3": t}
        KUTLE.append(satir)
        if k["abone_no"] in GECERLI:
            ORNEKLEM.append(satir)
        r()

AB = {}
for s in ORNEKLEM:
    AB.setdefault(s["abone_no"], []).append(s["tuketim_m3"])


def ozet(satirlar, ad):
    t, c = {}, {}
    for s in satirlar:
        t[s["bolge"]] = t.get(s["bolge"], 0.0) + s["tuketim_m3"]
        c[s["bolge"]] = c.get(s["bolge"], 0) + 1
    d, k = t["dogu"] / c["dogu"], t["kuzey"] / c["kuzey"]
    print(f"{ad:<34} {len(satirlar):>6} {d:>8.3f} {k:>8.3f} {d - k:>8.3f}")
    return d - k


print(f"{'kume':<34} {'satir':>6} {'dogu':>8} {'kuzey':>8} {'fark':>8}")
farklar = [ozet(KUTLE, "kutle (agdaki butun sayaclar)"),
           ozet(ORNEKLEM, "orneklem (okunabilmis sayaclar)"),
           ozet([s for s in ORNEKLEM if s["tuketim_m3"] > 0], "sifir okumalar atilmis"),
           ozet([s for s in ORNEKLEM if len(AB[s["abone_no"]]) == 3],
                "yalniz uc donem kalan aboneler")]
print(f"\ndort kararin urettigi fark acikligi: {max(farklar) - min(farklar):.3f} m3")
print(f"elenen abone: {len(ELENEN)}, elenen okuma: {len(KUTLE) - len(ORNEKLEM)}")
print(f"hic okuma uretmeyen abone: {len(ABONE) - len(AB)} / {len(ABONE)}")
print(f"sifir okuma: {sum(1 for s in ORNEKLEM if s['tuketim_m3'] == 0)} / {len(ORNEKLEM)}")

print("\nokuma sayisi   abone   abone ortalamasi   ilk donem ortalamasi")
for n in (1, 2, 3):
    alt = [v for v in AB.values() if len(v) == n]
    print(f"{n:>12} {len(alt):>7} {sum(sum(v)/len(v) for v in alt)/len(alt):>18.3f}"
          f" {sum(v[0] for v in alt)/len(alt):>22.3f}")
hepsi = [sum(v) / len(v) for v in AB.values()]
print(f"{'hepsi':>12} {len(hepsi):>7} {sum(hepsi)/len(hepsi):>18.3f}")
```

```
kume                                satir     dogu    kuzey     fark
kutle (agdaki butun sayaclar)        3364   24.784   20.125    4.659
orneklem (okunabilmis sayaclar)      3199   24.674   20.210    4.463
sifir okumalar atilmis               3080   25.593   20.938    4.655
yalniz uc donem kalan aboneler       2514   24.604   20.150    4.454

dort kararin urettigi fark acikligi: 0.206 m3
elenen abone: 71, elenen okuma: 165
hic okuma uretmeyen abone: 69 / 1329
sifir okuma: 119 / 3199

okuma sayisi   abone   abone ortalamasi   ilk donem ortalamasi
           1     159             20.858                 20.858
           2     263             19.776                 19.818
           3     838             19.627                 20.895
       hepsi    1260             19.813
```

İlk tablo **seçim yanlılığının** iki yüzünü ayırıyor. Kütle ile örneklem arasındaki fark
4,659'dan 4,463 m³'e iniyor: 165 okuma ve 71 abone eksik. Ama bu eleme kümenin üretiminde
tüketimden bağımsız çekilmiştir, dolayısıyla aradaki 0,196 m³ bir yanlılık değil, örneklemin
kendi payıdır. Elemenin yanlılık üretip üretmediğini belirleyen şey elemenin büyüklüğü değil,
**ölçülen değerle ilişkili olup olmadığıdır**.

Üçüncü satır ilişkili bir eleme gösteriyor. Sıfır yazılmış 119 okuma "geçersiz okuma" sayılıp
atıldığında doğu ortalaması 24,674'ten 25,593 m³'e çıkıyor. Karar savunulabilir — sıfır bir
tüketim değil, bir okunamama kaydı olabilir — ama sıfırlar rastgele dağılmadığı için sonucu bir
yöne itiyor. Dört kararın açıklığı 0,206 m³ ve bu, kursun çıpa farkının yaklaşık yirmide biridir.

İkinci tablo **ayakta kalan yanlılığını** veriyor. Üç dönem boyunca kalan 838 abonenin ortalaması
19,627 m³, kümenin tamamının ortalaması 19,813 m³. Fark küçük ve kaynağı son sütunda: üç dönem
kalan abonelerin **ilk dönem** ortalaması 20,895 m³ ile tek dönemliklerin 20,858 m³'üne neredeyse
eşit. Yani ayakta kalanlar baştan farklı aboneler değil; farkı yaratan şey, uzun kalanların
sonraki dönem okumalarının da ortalamaya girmesi.

Tablonun dışında kalan sayı en önemlisi: 1.329 abonenin **69'u hiç okuma üretmemiştir** ve bu
derste kurulan hiçbir abone tablosunda görünmez. Abone başına hesaplanan her özet 1.260 aboneye
aittir. Ayakta kalan yanlılığının en sessiz biçimi, paydanın kendisinin görünmez olmasıdır.

#### Gürültü Bulgu Üretir

İkinci sayı çözümleme serbestliğinin sınırıdır. Sonuç değişkeni tümüyle rastgele çekilir,
kırılımlar gerçek kümeden alınır ve her kırılım için yeniden karıştırma sınaması yapılır.
Bulunacak hiçbir şey yoktur.

```python

# Gurultuden bulgu uretme: sonuc degiskeni tumuyle rastgele cekilir, kirilimlar
# gercek kumeden alinir. Hicbir kirilimda gercek bir etki yoktur.
KAYIT = {k["abone_no"]: k for k in ABONE if k["abone_no"] in AB}
VERI = [{"bolge": k["bolge"], "hane": k["hane"], "memnuniyet": k["memnuniyet"],
         "basamak": ("10 alti" if AB[n][0] < 10 else
                     ("10-25" if AB[n][0] < 25 else "25 ustu")),
         "sifir": min(AB[n]) == 0.0, "tuketim": sum(AB[n]) / len(AB[n])}
        for n, k in KAYIT.items()]
N = len(VERI)
KIRILIM = []
for alan in ("bolge", "hane", "memnuniyet", "basamak"):
    for a in sorted({x[alan] for x in VERI}, key=str):
        KIRILIM.append((f"{alan}={a}", [i for i, x in enumerate(VERI) if x[alan] == a]))
KIRILIM.append(("sifir okumali", [i for i, x in enumerate(VERI) if x["sifir"]]))

KARISTIRMA, ESIK, TARAMA = 200, 0.05, 10
rs = uretec(TOHUM + 33000)
PERM = []
for _ in range(KARISTIRMA):
    h = list(range(N))
    for i in range(N - 1, 0, -1):
        j = int(rs() * (i + 1))
        h[i], h[j] = h[j], h[i]
    PERM.append(h)


def tara(deger):
    """Her kirilim icin: kirilim ici ile disi arasindaki farkin karistirma sinamasi."""
    toplam, bulgu = sum(deger), []
    for ad, idx in KIRILIM:
        m = len(idx)
        ic = sum(map(deger.__getitem__, idx))
        goz = ic / m - (toplam - ic) / (N - m)
        asan = 0
        for h in PERM:
            p = sum(deger[h[i]] for i in idx)
            if abs(p / m - (toplam - p) / (N - m)) >= abs(goz) - 1e-12:
                asan += 1
        if asan / KARISTIRMA <= ESIK:
            bulgu.append((ad, asan / KARISTIRMA))
    return bulgu


rg = uretec(TOHUM + 22000)
print(f"{N} abone, {len(KIRILIM)} kirilim, {KARISTIRMA} karistirma, esik {ESIK}")
print("gurultu taramasi (sonuc degiskeni rastgele, gercek etki yok)")
toplam, en_az_bir, en_cok = 0, 0, 0
for t in range(TARAMA):
    b = tara([rg() for _ in range(N)])
    toplam += len(b)
    en_az_bir += 1 if b else 0
    en_cok = max(en_cok, len(b))
    print(f"  tarama {t + 1:>2}: {len(b)} bulgu")
    if b:
        print("      " + ", ".join(f"{ad} p={p:.3f}" for ad, p in b))
sinama = TARAMA * len(KIRILIM)
print(f"\ntoplam sinama {sinama}, gozlenen bulgu {toplam}, beklenen {sinama * ESIK:.1f}")
print(f"en az bir bulgu cikan tarama {en_az_bir}/{TARAMA}, "
      f"beklenen {TARAMA * (1 - (1 - ESIK) ** len(KIRILIM)):.1f}")
print(f"tek taramada cikan en cok bulgu: {en_cok}")
print(f"ayni tarama gercek tuketim uzerinde: {len(tara([x['tuketim'] for x in VERI]))} bulgu")
```

```
1260 abone, 20 kirilim, 200 karistirma, esik 0.05
gurultu taramasi (sonuc degiskeni rastgele, gercek etki yok)
  tarama  1: 1 bulgu
      bolge=dogu p=0.050
  tarama  2: 0 bulgu
  tarama  3: 1 bulgu
      sifir okumali p=0.040
  tarama  4: 1 bulgu
      bolge=kuzey p=0.050
  tarama  5: 5 bulgu
      bolge=kuzey p=0.030, hane=1 p=0.010, hane=6 p=0.010, basamak=10-25 p=0.000, basamak=25 ustu p=0.010
  tarama  6: 0 bulgu
  tarama  7: 1 bulgu
      basamak=25 ustu p=0.015
  tarama  8: 0 bulgu
  tarama  9: 1 bulgu
      memnuniyet=4 p=0.000
  tarama 10: 1 bulgu
      bolge=dogu p=0.035

toplam sinama 200, gozlenen bulgu 11, beklenen 10.0
en az bir bulgu cikan tarama 7/10, beklenen 6.4
tek taramada cikan en cok bulgu: 5
ayni tarama gercek tuketim uzerinde: 8 bulgu
```

İki yüz sınama 11 bulgu verdi; eşik 0,05 olduğu için beklenen sayı 10,0. Gözlenen ile beklenen
neredeyse aynı, çünkü bulgu sayısı kümeden değil eşikten ve sınama sayısından geliyor. En az bir
bulgu çıkan tarama sayısı 7, beklenen 6,4. Yirmi kırılımlık bir taramanın hiçbir şey bulmama
olasılığı, hiçbir etki yokken bile üçte birden küçüktür.

Beşinci tarama tek başına okunmaya değer: aynı rastgele sütun beş ayrı kırılımda eşiği aşıyor ve
birinin p değeri 0,000. Bu beş satır bir rapora "bölge, hane büyüklüğü ve tarife basamağı
kırılımlarında anlamlı fark bulundu" diye girebilir. Beşinin de arkasında hiçbir şey yoktur.

Son satır ayrımı imkânsız kılan şeyi veriyor. Aynı tarama gerçek tüketim üzerinde 8 bulgu
buluyor, gürültü üzerinde tarama başına ortalama 1,1. Toplu bakıldığında gerçek yapı ayırt
edilebilir; ama **tek bir bulguya** bakan kişi onun hangi kümeden geldiğini göremez. Ayrımı yapan
tek şey, kaç kırılımın denendiğinin yazılmış olmasıdır. Denenmiş kırılım sayısı yazılmayan bir
bulgu, gürültü taramasının bir satırından ayırt edilemez.

Bu, keşif konusunun bıraktığı borcu ödemenin de yeridir. Keşifsel analiz beş kırılım alanında
232 hücre gezmiş, bunların 33'ünün 30 satırdan az olduğunu saymıştı; sınanacak soru o 232
hücrenin arasından seçildi. Yukarıdaki tarama 20 kırılımda 200 sınamayla 11 bulgu üretiyorsa,
232 hücrelik bir keşif taramasının aynı eşikte üreteceği beklenen bulgu sayısı 11,6'dır — ve
keşif aşamasında bu bulguların hiçbiri bir sınama olarak sayılmadı. Borç şudur: keşifte gezilen
hücre sayısı rapora yazılmadığında, sonradan yapılan tek bir sınama kendi payını olduğundan dar
gösterir. Ödemesi bir hesap değil bir cümledir: kaç kırılım gezildiği yazılır.

Seçim yanlılığı ile p değeri avcılığı burada birleşiyor. Birincisi kümeye hangi satırların
girdiğini seçmektir, ikincisi kümeden hangi sorunun sorulduğunu. İkisi de sonucu görüldükten
sonra yapılabilir ve ikisi de yazılmadıkça görünmez.

#### Özet

- Aynı çıpa farkı dört kararla dört değer alır: kütlede 4,659, örneklemde 4,463, sıfır okumalar
  atılınca 4,655 ve yalnız üç dönem kalan abonelerde 4,454 m³; açıklık 0,206 m³'tür.
- Eleme büyüklüğü değil, elemenin ölçülen değerle ilişkisi yanlılık üretir: tüketimden bağımsız
  çekilen 71 abonelik eleme farkı 0,196 m³ oynatır, sıfır okumaların atılması doğu ortalamasını
  24,674'ten 25,593 m³'e taşır.
- Ayakta kalan yanlılığı iki yerdedir: üç dönem kalan 838 abonenin ortalaması 19,627 m³ ile
  kümenin 19,813 m³'üne göre düşüktür ve 1.329 abonenin 69'u hiçbir abone tablosunda görünmez.
- Gürültü üzerinde 20 kırılımlık 10 tarama 200 sınama yapar ve 11 bulgu verir; eşik 0,05
  olduğundan beklenen 10,0'dır ve on taramanın 7'sinde en az bir bulgu çıkar.
- Tek bir tarama beş bulgu üretebilir ve bulguların hiçbirinin arkasında bir etki yoktur; denenmiş
  kırılım sayısı yazılmayan bir bulgu gürültü taramasının satırından ayırt edilemez.

#### Kurs Kapanışı

On üç dersin hesabı tek tabloda duruyor ve her sayı kendi dersinden okundu.

| Ders | Gözlenen sayı | Oynama payı | Karar değişir mi |
|---|---|---|---|
| Keşif 01 keşifsel analizin amacı | doğu - kuzey 4,463 m³ | 2.000 koşumda aşılmadı | hayır |
| Keşif 02 tek değişkenli inceleme | doğu ortalaması 24,674 m³ | çit dışı eleme 25,154 m³ | evet, fark 4,622 |
| Keşif 03 iki değişkenli inceleme | katsayı +0,600 | tek nokta çıkınca -0,057 | evet, ilişki kalmaz |
| Keşif 04 çok değişkenli inceleme | 15 çiftin 5'i eşiği aşar | eşik 0,0354, 2.000 koşum | evet, bağımsız bulgu 1 |
| Keşif 05 veri görsel denetimi | küme ortalaması 19,693 m³ | sıfırlar sayılmazsa 20,454 | evet, yüzde 3,9 açıklık |
| Uygulama 01 betimsel özet seçimi | ortalama 24,674 m³ | pay genişliği 1,552 m³ | hayır, 142 okumada evet |
| Uygulama 02 dağılım karşılaştırması | ortanca 19,66 m³ | çentik 0,920 ↔ 3,146 m³ | evet, iki tepe gizlenir |
| Uygulama 03 güven aralığı yorumu | doğu ortalaması 24,674 m³ | 23,894–25,431 m³ | evet, kesişme yanıltır |
| Uygulama 04 hipotez sınaması | fark 0,957 m³ | p 0,01249 ↔ 0,00300 | hayır, dörtte birde evet |
| Uygulama 05 A/B testi analizi | fark 0,123 m³ | [-0,698, 0,952] m³ | evet, 108 bileşimin 4'ü |
| Uygulama 06 regresyon | katsayı -0,605 m³/yıl | [-0,714, -0,503] | evet, katsayı 1,825 |
| Uygulama 07 kohort ve huni | elde tutma 0,619 | kural değişince 0,867 | evet, yön ters döner |
| Uygulama 08 yanıltıcı analizler | 11 bulgu / 200 sınama | beklenen 10,0 bulgu | evet, hiçbiri gerçek değil |

Üçüncü sütun kursun kuralıdır: **yanında oynama payı yazılmayan bir fark, bulgu değil bir
gözlemdir; payı yazılmayan sayı ölçülmemiş sayılır.** Dördüncü sütun payın ne işe yaradığını
söylüyor. **On üç dersin onunda karar değişiyor** — sayı aynı kaldığı halde, savunulabilir ikinci
bir kararla rapora giren cümle başkalaşıyor. Üçünde değişmiyor ve bu üç satır kursun asıl
çıktısıdır: payı yazılmış bir sayı, kararın **değişmediğini** de gösterebilir. Pay bir uyarı
işareti değil, kararın dayanağıdır.

On üç derste her sayının yanına payı yazıldı. Ama bütün bu sayılar analistin ekranında, çıktı
bloğu olarak kaldı. Kararı verecek kişi ne payı gördü ne de sayıyı; bulgunun **görülebilir ve
aktarılabilir** hale gelmesi hiç ele alınmadı. Payın kendisinin bir gösterimde nasıl duracağı da
sorulmadı: bir aralık nasıl çizilir, iki aralığın kesişmesi bir okuyucuya nasıl gösterilir, kaç
kırılımın denendiği bir raporun neresinde yazar. Sonraki kurs, Görselleştirme, Raporlama ve
Ölçekli Analiz, bu soruları ele alır.

