Ders 10 / 15
Doğası Gereği Yorumlanabilir Modeller
Açıklamayı sonradan üretmek yerine modeli baştan okunabilir kurmanın bedelinin ölçülmesi: iki kurallık, dört koşullu bir sıralı liste sınamada 0,7897 veriyor, otuz üç sütunlu en iyi ailenin 0,8056'sına 0,0159 yani dört abone kalıyor. Listeyi üç ve dört kurala uzatmak yaklaştırmıyor, 0,7857'ye geri düşürüyor. On üç alt gruba bakıldı, okunan on ikisinin altısında en iyi aileye 0,02 içinde yaklaşılamıyor; en uzağı merkez bölgesidir, 0,7414 yerine 0,6552 ve fark 0,0862. Üç alt grupta kural listesi en iyi aileyi geçiyor.
İçindekiler
Dört derste açıklama hep modelin dışından üretildi: kurulmuş bir modelin kararı sonradan okundu, bozuldu, taklit edildi ve ortalandı. Her seferinde açıklama bir yaklaşımdı ve sadakati ayrıca ölçülmek zorunda kaldı.
Başka bir yol vardır: modeli baştan okunabilir kurmak. Kararı birkaç kuralın sırayla uygulanmasıyla veren bir model açıklamayı ayrıca üretmez — modelin kendisi açıklamadır ve sadakati tanım gereği tamdır. Bu dersin sorusu o yolun bedelidir. M27/K03’ün Doğrusal Modeller konusu bedeli bir kez ölçmüştü: on iki katsayılı model ile otuz üç sütunlu en iyi aile arasında 0,0040, yani tek abone. O sayı burada tekrarlanmaz, girdi alınır — çünkü kural listesi on iki katsayıdan çok daha okunabilirdir ve bedelin okunabilirlikle nasıl büyüdüğü asıl sorudur.
- YO25. Kurulum önceki derslerinkidir: aynı kurgu abone tablosu, tohum 20260218, bölme 756/252/252, sınama kümesinde taban çizgisi 0,7579. Alt gruplar ve 25 kayıtlık okuma eşiği sürer; bakılan alt grup sayısı 13’tür.
- YO26. Karşılaştırma çizgileri M27/K03’ten gelir ve aynı tohumla yeniden hesaplanır: on iki sütunlu doğrusal model 0,8016, en iyi aile (otuz üç sütunlu, karesel cezalı) 0,8056. Karar ağacı ailesinin sayısı aynı kurstan 0,7857’dir.
- YO27. Kural listesi sıralı bir modeldir: ilk uyan kural kararı verir, hiçbiri uymazsa son etiket verilir. Her kural en fazla iki koşul taşır ve iki koşul aynı sütundan olamaz.
- YO28. Liste açgözlü kurulur: her adımda, kalan kayıtların varsayılan etiketine göre en çok doğru kazandıran kural eklenir ve kapsadığı kayıtlar çıkarılır. En az kapsam 12 kayıttır ve koşul eşikleri eğitim kümesinin ondalıklarından alınır.
- YO29. “En iyi aileye yaklaşmak”, sınama doğruluğu farkının 0,02’yi geçmemesidir; 0,02 bu sınama kümesinde beş abonedir.
Üç Karşılaştırma Çizgisi
Kurulum önceki derslerinkidir; üstüne M27/K03’ün en iyi ailesi aynı tohumla yeniden kurulur.
# yorum.py — MODELDIR. M27/K01–K07'nin KURGU abone tablosu ayni tohumla uretilir; # on iki sutunluk oznitelik kumesi ve bolme kurs boyunca sabittir. import itertools import math import statistics 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, 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, v = uretec(TOHUM + 7000 + k["no"]), [] for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])): v.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() if not v: 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 = {"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]} x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3) for b in BOLGE: x["b_" + b[0]] = int(k["bolge"][0] == b[0]) VERI.append(x) 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] K = karistir(VERI, TOHUM + 90000) EGT, DOG, SIN = K[:756], K[756:1008], K[1008:] ALAN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma", "kisi_basi", "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"] TABAN = sum(x["supheli"] == 0 for x in SIN) / len(SIN) def sikistir(z): if z >= 0: return 1.0 / (1.0 + math.exp(-z)) if z < 700 else 1.0 e = math.exp(z) if z > -700 else 0.0 return e / (1.0 + e) def olcek(egt, alan): return ({a: statistics.fmean(x[a] for x in egt) for a in alan}, {a: max(1e-9, statistics.pstdev([x[a] for x in egt])) for a in alan}) def egit(egt, alan, o, s, adim=0.3, tur=300, ceza=0.0): # MODELDIR: lojistik baglanim X = [[1.0] + [(x[a] - o[a]) / s[a] for a in alan] for x in egt] Y = [x["supheli"] for x in egt] w = [0.0] * len(X[0]) for _ in range(tur): g = [0.0] * len(w) for i in range(len(X)): h = sikistir(sum(w[j] * X[i][j] for j in range(len(w)))) - Y[i] for j in range(len(w)): g[j] += h * X[i][j] for j in range(len(w)): w[j] -= adim * (g[j] / len(X) + (ceza * w[j] if j else 0.0)) return w def puan(w, alan, o, s, x): return sikistir(w[0] + sum(w[j + 1] * (x[a] - o[a]) / s[a] for j, a in enumerate(alan))) def karar(w, alan, o, s, x): return int(puan(w, alan, o, s, x) > 0.5) O, S = olcek(EGT, ALAN) W = egit(EGT, ALAN, O, S) print(f"egitim {len(EGT)}, dogrulama {len(DOG)}, sinama {len(SIN)}") def basamak(x): return ("tarife 10" if x["ort_tuketim"] <= 10 else "tarife 25" if x["ort_tuketim"] <= 25 else "tarife 40") def hane_grup(x): return "hane 1-2" if x["hane"] <= 2 else ("hane 3-4" if x["hane"] <= 4 else "hane 5+") def okuma_grup(x): return "okuma az" if x["donem"] <= 2 else "okuma tam" def esitse(f, deger): return lambda x: f(x) == deger ALTGRUP = ([("bolge " + b[0], esitse(lambda x: x["bolge"], b[0])) for b in BOLGE] + [(t, esitse(basamak, t)) for t in ("tarife 10", "tarife 25", "tarife 40")] + [(h, esitse(hane_grup, h)) for h in ("hane 1-2", "hane 3-4", "hane 5+")] + [(o, esitse(okuma_grup, o)) for o in ("okuma az", "okuma tam")]) ENAZ = 25 BOY = {ad: sum(1 for x in SIN if f(x)) for ad, f in ALTGRUP} print(f"alt grup sayisi {len(ALTGRUP)}, esik {ENAZ} kayit, esigin altinda " f"{[a for a in BOY if BOY[a] < ENAZ]}") CARPIM = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "kisi_basi"] def genislet(x): d = dict(x) for a, b in itertools.combinations(CARPIM, 2): d[a + "*" + b] = x[a] * x[b] for a in CARPIM: d[a + "^2"] = x[a] * x[a] return d GENIS = (ALAN + [a + "*" + b for a, b in itertools.combinations(CARPIM, 2)] + [a + "^2" for a in CARPIM]) GE, GS = [genislet(x) for x in EGT], [genislet(x) for x in SIN] OG, SG = olcek(GE, GENIS) WG = egit(GE, GENIS, OG, SG, ceza=0.05) # M27/K03'un en iyi ailesi EN_IYI = sum(karar(WG, GENIS, OG, SG, x) == x["supheli"] for x in GS) / len(GS) DM = sum(karar(W, ALAN, O, S, x) == x["supheli"] for x in SIN) / len(SIN) print(f"taban cizgisi {TABAN:.4f}, on iki sutunlu dogrusal model {DM:.4f}, " f"en iyi aile ({len(GENIS)} sutun) {EN_IYI:.4f}")
egitim 756, dogrulama 252, sinama 252 alt grup sayisi 13, esik 25 kayit, esigin altinda ['tarife 10'] taban cizgisi 0.7579, on iki sutunlu dogrusal model 0.8016, en iyi aile (33 sutun) 0.8056
Kural Listesi Uzadıkça
Liste açgözlü kurulur ve uzunluk birden altıya süpürülür.
KURAL_SUTUN = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma", "bolge"] def uyar(k, x): a, yon, e = k return x[a] == e if yon == "=" else (x[a] < e if yon == "<" else x[a] >= e) def kosullar(kume): for a in KURAL_SUTUN: d = sorted({x[a] for x in kume}) if a == "bolge": for v in d: yield (a, "=", v) else: for v in (d if len(d) < 10 else [d[int(i * len(d) / 10)] for i in range(1, 10)]): yield (a, "<", v) yield (a, ">=", v) def kazanc(g, v0, enaz): # varsayilana gore kazanilan dogru sayisi if len(g) < enaz: return None poz = sum(x["supheli"] for x in g) etiket = int(poz * 2 > len(g)) return ((poz if etiket else len(g) - poz) - (poz if v0 else len(g) - poz), etiket) def kural_listesi(egt, uzunluk, enaz=12, tohum=8): # MODELDIR: sirali kural listesi kalan, liste = list(egt), [] for _ in range(uzunluk): v0 = int(sum(x["supheli"] for x in kalan) * 2 > len(kalan)) aday = [] for k1 in kosullar(kalan): g1 = [x for x in kalan if uyar(k1, x)] z = kazanc(g1, v0, enaz) if z: p = sum(x["supheli"] for x in g1) / len(g1) aday.append((p if v0 == 0 else 1 - p, z[0], k1, g1, z[1])) if not aday: break aday.sort(key=lambda t: -t[0]) en = max(((t[1], [t[2]], t[4]) for t in aday[:tohum]), key=lambda t: t[0]) for _, _, k1, g1, _ in aday[:tohum]: for k2 in kosullar(g1): if k2[0] == k1[0]: continue z = kazanc([x for x in g1 if uyar(k2, x)], v0, enaz) if z and z[0] > en[0]: en = (z[0], [k1, k2], z[1]) if en[0] <= 0: break liste.append((en[1], en[2])) kalan = [x for x in kalan if not all(uyar(k, x) for k in en[1])] if not kalan: break p = sum(x["supheli"] for x in kalan) return liste, (int(p * 2 > len(kalan)) if kalan else 0) def kural_tahmin(liste, son, x): for kosul, etiket in liste: if all(uyar(k, x) for k in kosul): return etiket return son def yaz(kosul): return " ve ".join(f"{a} {y} {e}" for a, y, e in kosul) YAKIN = 0.02 # sinama kumesinde bes abone print(f"{'kural':>6}{'kosul':>7}{'sinama':>9}{'en iyi aileye fark':>20}") SWEEP = [] for n in range(1, 7): liste, son = kural_listesi(EGT, n) d = sum(kural_tahmin(liste, son, x) == x["supheli"] for x in SIN) / len(SIN) k = sum(len(c) for c, e in liste) SWEEP.append((d, -len(liste), liste, son, k)) print(f"{len(liste):>6}{k:>7}{d:>9.4f}{EN_IYI - d:>+20.4f}") SECIM = max(SWEEP, key=lambda t: (t[0], t[1])) print(f"\nen iyi aileye en cok yaklasan liste {-SECIM[1]} kural, {SECIM[4]} kosul, " f"sinama {SECIM[0]:.4f}, fark {EN_IYI - SECIM[0]:+.4f} " f"({round((EN_IYI - SECIM[0]) * len(SIN))} abone)") for kosul, etiket in SECIM[2]: print(f" eger {yaz(kosul)} ise {etiket}") print(f" yoksa {SECIM[3]}")
kural kosul sinama en iyi aileye fark
1 2 0.7857 +0.0198
2 4 0.7897 +0.0159
3 6 0.7857 +0.0198
4 8 0.7857 +0.0198
4 8 0.7857 +0.0198
4 8 0.7857 +0.0198
en iyi aileye en cok yaklasan liste 2 kural, 4 kosul, sinama 0.7897, fark +0.0159 (4 abone)
eger bolge = dogu ve oynaklik >= 11.86 ise 1
eger sifir_okuma >= 1 ve oynaklik >= 20.06 ise 1
yoksa 0
Tek kural iki koşulla 0,7857 veriyor; bu, M27/K03’te budanmış karar ağacı ailesinin sayısıdır. İkinci kural sayıyı 0,7897’ye çıkarıyor ve en iyi aileye 0,0159, yani dört abone kalıyor. Üçüncü ve dördüncü kurallar yaklaştırmıyor, 0,7857’ye geri düşürüyor; beşinci adımda açgözlü yordam kazanç bulamayıp duruyor. Uzunluk ile doğruluk arasında tek yönlü bir ilişki yok.
Bedelin büyüklüğü asıl okunacak yerdedir. M27/K03 on iki katsayı için farkı 0,0040, yani tek abone ölçmüştü; dört koşula inildiğinde aynı fark dört aboneye çıkıyor. Okunabilirlik sürekli bir eksendir ve bedeli o eksende büyür; hangi noktanın seçileceği bir ölçüm değil bir karardır, ama karar ancak iki ucun sayısı yazıldığında verilebilir.
Listenin kendisi üç satırda okunuyor ve her satır bir cümledir. Bu modelin açıklamasının sadakati tanım gereği 1’dir, çünkü açıklama modelin kendisidir; üçüncü dersin 41 boş açıklaması burada oluşmaz.
Hangi Alt Grupta Yaklaşılamıyor
Bütünde ölçülen 0,0159 tek başına okunmaz. Aynı iki model on üç alt grupta yan yana konur.
LISTE, SON = SECIM[2], SECIM[3] print(f"{'alt grup':<14}{'kayit':>6}{'kural listesi':>15}{'en iyi aile':>13}" f"{'fark':>9}") UZAK, OKUNAN = [], 0 for ad, f in ALTGRUP: g = [x for x in SIN if f(x)] kl = sum(kural_tahmin(LISTE, SON, x) == x["supheli"] for x in g) / len(g) ei = sum(karar(WG, GENIS, OG, SG, genislet(x)) == x["supheli"] for x in g) / len(g) if BOY[ad] >= ENAZ: OKUNAN += 1 if ei - kl > YAKIN: UZAK.append((ad, kl, ei)) print(f"{ad:<14}{len(g):>6}{kl:>15.4f}{ei:>13.4f}{ei - kl:>+9.4f}") UZAK.sort(key=lambda t: t[1] - t[2]) print(f"\nokunan alt grup {OKUNAN}/{len(ALTGRUP)}; en iyi aileye {YAKIN} icinde " f"yaklasamayan alt grup {len(UZAK)}, en uzagi {UZAK[0][0]} " f"({UZAK[0][1]:.4f} yerine {UZAK[0][2]:.4f}, fark {UZAK[0][2] - UZAK[0][1]:+.4f})")
alt grup kayit kural listesi en iyi aile fark bolge kuzey 68 0.8088 0.7794 -0.0294 bolge guney 58 0.8621 0.8448 -0.0172 bolge dogu 36 0.6667 0.7222 +0.0556 bolge bati 32 1.0000 1.0000 +0.0000 bolge merkez 58 0.6552 0.7414 +0.0862 tarife 10 12 0.6667 0.6667 +0.0000 tarife 25 193 0.8290 0.8342 +0.0052 tarife 40 47 0.6596 0.7234 +0.0638 hane 1-2 73 0.7945 0.8356 +0.0411 hane 3-4 143 0.8042 0.7972 -0.0070 hane 5+ 36 0.7222 0.7778 +0.0556 okuma az 85 0.7529 0.7765 +0.0235 okuma tam 167 0.8084 0.8204 +0.0120 okunan alt grup 12/13; en iyi aileye 0.02 icinde yaklasamayan alt grup 6, en uzagi bolge merkez (0.6552 yerine 0.7414, fark +0.0862)
Bütünde dört abone olan fark alt gruplarda dağılıyor. On üç alt gruba bakıldı, eşiği geçen 12’si okundu ve bunların altısında en iyi aileye 0,02 içinde yaklaşılamıyor. En uzağı merkez bölgesidir: 0,6552’ye karşı 0,7414, fark 0,0862 — bütündeki farkın beş katından fazlası. En üst tarife basamağında fark 0,0638, doğu bölgesinde ve büyük hanelerde 0,0556.
Nedeni listenin kendisinden okunuyor. İki kuralın biri doğu bölgesine, öbürü sıfır okumasına bağlı; merkez bölgesinin şüpheli aboneleri ikisine de girmiyor ve hepsi son satırın varsayılan etiketini alıyor. Kısalık bütün için ödenir, faturası bazı alt gruplara çıkar.
Ters yön de aynı tabloda duruyor. Üç alt grupta kural listesi en iyi aileyi geçiyor: kuzeyde 0,0294, güneyde 0,0172, orta hane büyüklüğünde 0,0070. Bütündeki tek sayı, hangi modelin kimin için daha iyi olduğunu söylemiyor.
Özet
- İki kurallık, dört koşullu sıralı liste sınamada 0,7897 veriyor; en iyi ailenin 0,8056’sına 0,0159, yani dört abone kalıyor.
- Listeyi uzatmak yaklaştırmıyor: üç ve dört kural 0,7857’ye düşürüyor ve liste dördüncü kuraldan sonra doyuyor. Tek kural 0,7857 ile karar ağacı ailesinin sayısını veriyor.
- Okunabilirliğin bedeli o eksende büyüyor: M27/K03’te on iki katsayı için bir abone, burada dört koşul için dört abone.
- Kural listesinin sadakati tanım gereği 1’dir; üçüncü dersin 41 boş açıklaması burada oluşmaz.
- On üç alt gruba bakıldı, 12’si okundu: altısında en iyi aileye 0,02 içinde yaklaşılamıyor, en uzağı merkez bölgesinde 0,0862; üç alt grupta ise kural listesi en iyi aileyi geçiyor.
Sonraki Adım
On derste bir sayının ne olduğu, kimin için olduğu ve neye dayandığı ölçüldü: bölmenin şişirdiği pay, bedel yapısının oynattığı işletme noktası, tabanın seçimi, farkın payı, dağılım kayması, açıklamanın kapattığı soru sayısı, iki önem sıralamasının ayrışması, açıklamanın sadakati, ortalamanın gizlediği etkileşim ve kural listesinin bedeli. Hepsinde ölçülen şey doğruluk ya da okunabilirlikti.
Hiçbiri bir zarar ölçüsü değildi. Merkez bölgesindeki 0,0862’lik fark, oradaki abonelerin şüpheli işaretini daha sık yanlış aldığı anlamına gelir; kimin ne kadar yanlış işaret aldığı ve o işaretin ona ne yaptığı on derste hiç sorulmadı. Sonraki konu bu soruyla açılır: yanlışlık kümenin neresinden geliyor, adil olmanın kaç ayrı tanımı var ve bu tanımlar aynı anda sağlanabiliyor mu, ve modelin öğrendiği şey tek tek kayıtlar hakkında ne sızdırıyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.