İçeriğe geç
academia.sh

Ders 01 / 15

Doğrulama Stratejileri

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

İçindekiler

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

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

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

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

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

# MODELDIR. M26'nin KURGU olcum agi ayni tohumla uretilir, okumalar abone duzeyinde
# ozetlenir ve uzerine KURGU bir kacak/ariza suphesi etiketi eklenir.
import math

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


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

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


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


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

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


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


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


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


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


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


def dogruluk(d, s):
    return sum(tahmin(d, x) == x["supheli"] for x in s) / len(s)


def taban(egt, s):
    c = int(sum(x["supheli"] for x in egt) * 2 > len(egt))
    return sum(x["supheli"] == c for x in s) / len(s)


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


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


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


print(f"abone {len(VERI)} -- 756/252/252 -- alt grup {len(ADLAR)} (dort eksen)\n"
      f"{'alt grup':<14} {'n':>4} {'taban':>7} {'agac':>7} {'fark':>8}")
satir("BUTUN", SIN)
olcum = {g: satir(" ".join(g), [x for x in SIN if g in gruplar(x)]) for g in ADLAR}
ol = [v[2] for v in olcum.values() if v[0] >= 25]
alti = [" ".join(g) for g, v in olcum.items() if v[2] < v[1]]
print(f"\naciklik ({len(ol)} alt grup): en iyi {max(ol):.4f}, en kotu {min(ol):.4f}, "
      f"aciklik {max(ol) - min(ol):.4f}\ntabanin altinda kalan: {len(alti)}/"
      f"{len(ADLAR)} -- " + ", ".join(alti))
abone 1260 -- 756/252/252 -- alt grup 13 (dort eksen)
alt grup          n   taban    agac     fark
BUTUN           252  0.7579  0.7778  +0.0198
bolge bati       32  1.0000  0.9688  -0.0312
bolge dogu       36  0.4722  0.6111  +0.1389
bolge guney      58  0.8276  0.8793  +0.0517
bolge kuzey      68  0.8235  0.7794  -0.0441
bolge merkez     58  0.6552  0.6724  +0.0172
hane 1-2         73  0.7534  0.7945  +0.0411
hane 3-4        143  0.7692  0.7762  +0.0070
hane 5+          36  0.7222  0.7500  +0.0278
okuma az         85  0.7882  0.7412  -0.0471
okuma tam       167  0.7425  0.7964  +0.0539
tarife 10        12  0.6667  0.5833  -0.0833   n<25, acikliga girmez
tarife 25       193  0.8394  0.8290  -0.0104
tarife 40        47  0.4468  0.6170  +0.1702

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

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

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

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

Aynı Abone İki Kümede

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Özet

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

Sonraki Adım

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

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat