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.