---
title: 'Keşifsel Analizin Amacı'
source: 'https://academia.sh/tr/kurslar/kesifsel-analiz/kesifsel-analizin-amaci'
course: 'İstatistiksel Analiz ve Keşifsel Veri Analizi'
language: tr
updated: '2026-08-17T18:08:47+00:00'
license: 'CC BY-SA 4.0'
---

# Keşifsel Analizin Amacı

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.
