---
title: 'A/B Testi Analizi'
source: 'https://academia.sh/tr/kurslar/kesifsel-analiz/ab-testi-analizi'
course: 'İstatistiksel Analiz ve Keşifsel Veri Analizi'
language: tr
updated: '2026-08-17T18:08:46+00:00'
license: 'CC BY-SA 4.0'
---

# A/B 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.
