Ders 16 / 20
Olasılık Kalibrasyonu
Söylenen olasılık ile gerçekleşen oran arasındaki farkın ölçülmesi: doğrusal modelin kalibrasyon hatası 0,0242, sıralaması ona tıpatıp eşit olan keskinleştirilmiş skorunki 0,1512'dir ve iki modelin eğri altındaki alanı da 0,8058'dir. Derinlik 8 ağacın eğitim kümesindeki kalibrasyon hatası tanım gereği 0,0000, sınama kümesinde 0,1435'tir; eğitimden öğrenilen düzeltme eşlemesi birim eşlemeye yakınsar ve hiçbir şey düzeltmez. Doğrulama kümesinden öğrenilen tek değişkenli eşleme keskinleştirilmiş skorun hatasını 0,1512'den 0,0463'e indirir ve eğri altındaki alanı 0,8058'de bırakır.
İçindekiler
Önceki dersin tamamı sıralamaya dayanıyordu. Eşik süpürüldü, iki eğri basıldı, işletme noktası bedel hesabıyla seçildi; hiçbir adımda modelin söylediği sayının kendisinin bir karşılığı olması gerekmedi. Skorlar kesin artan bir dönüşümden geçirilse sıralama, eğriler ve seçilen abone kümesi değişmeden kalırdı.
Ama model bir abone için 0,80 dediğinde bu sayı bir şey iddia eder: 0,80 denen abonelerin yaklaşık yüzde sekseni şüpheli çıkmalıdır. Bu iddia sıralamadan bağımsızdır ve ayrı ölçülür. Kalibrasyon, söylenen olasılık ile gerçekleşen oran arasındaki farktır.
- MD23. Kalibrasyon sıralamadan bağımsız bir ölçüdür; iki model aynı sıralamayı verip ayrı kalibrasyon hataları üretebilir.
- MD24. Olasılıklar beş eşit genişlikte aralığa bölünür. Aralık sayısı bir seçimdir: sayı büyüdükçe her aralıktaki abone sayısı düşer ve gerçekleşen oran oynar.
- MD25. Kalibrasyon hatası, her aralıkta söylenen olasılıkların toplamı ile gerçekleşen şüpheli sayısının mutlak farkı toplanıp gözlem sayısına bölünerek hesaplanır.
- MD26. Keskinleştirilmiş skor kesin artan bir dönüşümdür; sıralamayı ve dolayısıyla eğri altındaki alanı tam olarak korur.
- MD27. Düzeltme eşlemesi modelin skorundan başka hiçbir öznitelik görmez; tek girdisi skor, iki parametresi eğim ve kaydırmadır. Eğim pozitif kaldığı sürece sıralama değişmez.
- MD28. Eşleme doğrulama kümesinden öğrenilir; öbür iki küme karşılaştırma için basılır.
- MD29. Ağacın yaprak olasılığı o yaprağa düşen eğitim satırlarındaki şüpheli oranıdır; bu yüzden ağacın eğitim kümesindeki kalibrasyon hatası tanım gereği sıfırdır.
- MD30. Taban çizgisi burada da bir sayı verir: her aboneye eğitim kümesindeki şüpheli oranını söyleyen yordam kalibrasyonda ölçülür ve eğri altındaki alanı 0,5000’dir.
Söylenen ile Gerçekleşen
Kalibrasyon ölçmek için olasılıklar aralıklara bölünür, her aralıkta modelin söylediği ortalama olasılık ile o aralıktaki abonelerin gerçekleşen şüpheli oranı yan yana yazılır. Bu tabloya güvenilirlik eğrisi denir ve çizilmesi gerekmez, sayı olarak okunur.
# degerlendirme.py — MODELDIR. Kurgu abone tablosu ayni tohumla yeniden uretilir. import math TOHUM, ADAY, 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 = [], {} for i in range(ADAY): 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() VERI = [] for k in ABONE: v = OKUMA.get(k["no"]) 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)} 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"] def safsizlik(s): p = sum(x["supheli"] for x in s) / len(s) return 2 * p * (1 - p) def agac(s, derinlik, alan, enaz=2): # MODELDIR: karar agaci n = len(s) p = sum(x["supheli"] for x in s) / n en = None if derinlik and n >= 2 * enaz and 0.0 < p < 1.0: for a in alan: 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)) / n if en is None or k > en[0]: en = (k, a, v, sol, sag) if en is None or en[0] <= 1e-9: return {"p": p} return {"alan": en[1], "esik": en[2], "sol": agac(en[3], derinlik - 1, alan, enaz), "sag": agac(en[4], derinlik - 1, alan, enaz)} def olasilik(d, x): while "p" not in d: d = d["sol"] if x[d["alan"]] < d["esik"] else d["sag"] return d["p"] def dogrusal(egt, alan, w, tur=300, adim=0.5): # MODELDIR: egim temelli dogrusal model o = {a: sum(x[a] for x in egt) / len(egt) for a in alan} s = {a: (sum((x[a] - o[a]) ** 2 for x in egt) / len(egt)) ** 0.5 or 1.0 for a in alan} f = lambda x: [(x[a] - o[a]) / s[a] for a in alan] k, b = [0.0] * len(alan), 0.0 X = [f(x) for x in egt] y = [x["supheli"] for x in egt] a = [(w if x["supheli"] else 1.0) for x in egt] n = sum(a) for _ in range(tur): gk, gb = [0.0] * len(alan), 0.0 for i, xi in enumerate(X): z = b + sum(k[j] * xi[j] for j in range(len(k))) e = (1 / (1 + math.exp(-max(-30.0, min(30.0, z)))) - y[i]) * a[i] gb += e for j in range(len(k)): gk[j] += e * xi[j] b -= adim * gb / n for j in range(len(k)): k[j] -= adim * gk[j] / n def skor(x): v = f(x) z = b + sum(k[j] * v[j] for j in range(len(k))) return 1 / (1 + math.exp(-max(-30.0, min(30.0, z)))) return skor S = dogrusal(EGT, ALAN, 1.0) # MODELDIR: olasilik ureten egim temelli dogrusal model ARALIK = 5 def guvenilirlik(skor, veri, n=ARALIK): # her aralikta sayim, soylenen, gerceklesen kova = [[0, 0.0, 0] for _ in range(n)] for x in veri: p = skor(x) k = kova[min(n - 1, int(p * n))] k[0], k[1], k[2] = k[0] + 1, k[1] + p, k[2] + x["supheli"] return kova def kal_hata(skor, veri, n=ARALIK): # aralik agirlikli ortalama mutlak fark return sum(abs(k[1] - k[2]) for k in guvenilirlik(skor, veri, n)) / len(veri) def guvenilirlik_bas(ad, skor, veri): print(f"{ad} (kalibrasyon hatasi {kal_hata(skor, veri):.4f})") for i, k in enumerate(guvenilirlik(skor, veri)): if k[0]: print(f" {i / ARALIK:.1f}-{(i + 1) / ARALIK:.1f} abone {k[0]:>3} " f"soylenen {k[1] / k[0]:.4f} gerceklesen {k[2] / k[0]:.4f} " f"fark {k[1] / k[0] - k[2] / k[0]:+.4f}") guvenilirlik_bas("dogrusal model, sinama kumesi", S, SIN)
dogrusal model, sinama kumesi (kalibrasyon hatasi 0.0242) 0.0-0.2 abone 152 soylenen 0.0891 gerceklesen 0.1053 fark -0.0161 0.2-0.4 abone 53 soylenen 0.2837 gerceklesen 0.3019 fark -0.0182 0.4-0.6 abone 23 soylenen 0.4918 gerceklesen 0.4783 fark +0.0136 0.6-0.8 abone 16 soylenen 0.7079 gerceklesen 0.6250 fark +0.0829 0.8-1.0 abone 8 soylenen 0.8698 gerceklesen 1.0000 fark -0.1302
İlk üç aralıkta fark 0,02 düzeyinin altında ve kalibrasyon hatası 0,0242. Son iki aralık daha oynak, çünkü orada toplam 24 abone var: 0,6-0,8 aralığında model 0,7079 söylerken 0,6250 gerçekleşiyor, 0,8-1,0 aralığında 0,8698 söylerken sekiz abonenin sekizi de şüpheli çıkıyor. Sekiz aboneden hesaplanan bir oranın 0,13 sapması ölçünün kendi oynaklığıdır; aralık sayısı büyüdükçe bu oynaklık büyür, küçüldükçe tablo körleşir.
Sıralaması İyi, Kalibrasyonu Kötü
Skorlar kesin artan bir dönüşümden geçirilirse hiçbir abonenin sırası değişmez. Sıralamaya dayanan her ölçü sabit kalır; kalibrasyon kalmaz.
def alan_roc(skor, veri): # esitlikleri ortalayan sira toplami p = sorted(((skor(x), x["supheli"]) for x in veri)) P = sum(y for _, y in p) t, i = 0.0, 0 while i < len(p): j = i while j < len(p) and p[j][0] == p[i][0]: j += 1 t += (i + j + 1) / 2.0 * sum(y for _, y in p[i:j]) i = j return (t - P * (P + 1) / 2) / (P * (len(p) - P)) def keskin(p, g=3.0): # kesin artan, siralamayi degistirmeyen donusum return p ** g / (p ** g + (1 - p) ** g) K = lambda x: keskin(S(x)) # MODELDIR: keskinlestirilmis skor T8 = agac(EGT, 8, ALAN) # MODELDIR: derinlik 8 karar agaci TABAN = sum(x["supheli"] for x in EGT) / len(EGT) print(f"{'model':<20}{'ROC':>8}{'kal.hata':>10}{'ort skor':>10}{'supheli orani':>15}") for ad, s in (("dogrusal", S), ("keskinlestirilmis", K), ("agac d8", lambda x: olasilik(T8, x)), ("taban (egitim orani)", lambda x: TABAN)): print(f"{ad:<20}{alan_roc(s, SIN):>8.4f}{kal_hata(s, SIN):>10.4f}" f"{sum(s(x) for x in SIN) / len(SIN):>10.4f}" f"{sum(x['supheli'] for x in SIN) / len(SIN):>15.4f}") print() guvenilirlik_bas("keskinlestirilmis skor, sinama kumesi", K, SIN)
model ROC kal.hata ort skor supheli orani dogrusal 0.8058 0.0242 0.2309 0.2421 keskinlestirilmis 0.8058 0.1512 0.1504 0.2421 agac d8 0.7391 0.1435 0.2586 0.2421 taban (egitim orani) 0.5000 0.0198 0.2222 0.2421 keskinlestirilmis skor, sinama kumesi (kalibrasyon hatasi 0.1512) 0.0-0.2 abone 204 soylenen 0.0199 gerceklesen 0.1569 fark -0.1369 0.2-0.4 abone 10 soylenen 0.3033 gerceklesen 0.3000 fark +0.0033 0.4-0.6 abone 7 soylenen 0.4756 gerceklesen 0.8571 fark -0.3816 0.6-0.8 abone 8 soylenen 0.7001 gerceklesen 0.3750 fark +0.3251 0.8-1.0 abone 23 soylenen 0.9509 gerceklesen 0.7391 fark +0.2117
İlk tablonun ilk iki satırı iddianın kanıtı: iki modelin eğri altındaki alanı aynı, 0,8058, çünkü ikisi 252 aboneyi tıpatıp aynı sırada diziyor. Kalibrasyon hatası ise 0,0242’den 0,1512’ye, altı katından fazlasına çıkıyor.
Üçüncü satır ayrı bir uyarı taşıyor. Derinlik 8 ağacının ortalama skoru 0,2586, sınama kümesindeki gerçek şüpheli oranı 0,2421 — aradaki fark yalnız 0,0165. Toplamda doğru görünen bir model aralık düzeyinde 0,1435 hata veriyor. Ortalamanın tutması kalibrasyon değildir; birbirini götüren aşırı ve eksik güvenleri gizler.
Dördüncü satır kalibrasyonun tek başına neyi ölçmediğini söylüyor. Her aboneye eğitim kümesinin şüpheli oranını, 0,2222’yi söyleyen taban çizgisinin kalibrasyon hatası 0,0198 ile tablodaki en küçük sayıdır; eğri altındaki alanı ise 0,5000, yani sıralaması rastgeleyle aynıdır. Hiçbir şey öğrenmemiş bir yordam kalibrasyonda birinci olabilir. İki ölçü ayrı sorulara yanıt verir ve ikisinin de yazılması gerekir.
İkinci tablo keskinleştirilmiş skorun nerede bozulduğunu gösteriyor. En kalabalık aralıkta model 0,0199 söylüyor, gerçekleşen 0,1569 — yedi katından fazla. Üst uçta ise 0,9509 söyleyip 0,7391 gerçekleştiriyor. Model bir yandan aşırı çekingen, bir yandan aşırı güvenli; iki hata ortalamada bir ölçüde birbirini götürür, aralık düzeyinde ikisi de durur.
Düzeltme: Tek Değişkenli Bir Eşleme
Bozulma sıralamada değil, skorun sayı değerinde. Düzeltmenin de sıralamaya dokunmaması gerekir: skoru girdi alan, kesin artan, iki parametreli bir eşleme yeter.
def logit(p, e=1e-6): p = min(1 - e, max(e, p)) return math.log(p / (1 - p)) def esleme(skor, veri, tur=600, adim=0.5): # MODELDIR: tek degiskenli duzeltme eslemesi z = [logit(skor(x)) for x in veri] y = [x["supheli"] for x in veri] a, b = 1.0, 0.0 for _ in range(tur): ga = gb = 0.0 for i, zi in enumerate(z): e = 1 / (1 + math.exp(-max(-30.0, min(30.0, a * zi + b)))) - y[i] ga, gb = ga + e * zi, gb + e a, b = a - adim * ga / len(z), b - adim * gb / len(z) return lambda x: 1 / (1 + math.exp(-max(-30.0, min(30.0, a * logit(skor(x)) + b)))), a, b print(f"{'eslemenin ogrenildigi kume':<28}{'a':>8}{'b':>9}{'ROC':>8}{'kal.hata':>10}") print(f"{'duzeltme yok':<28}{'-':>8}{'-':>9}{alan_roc(K, SIN):>8.4f}" f"{kal_hata(K, SIN):>10.4f}") for ad, kume in (("egitim", EGT), ("dogrulama", DOG), ("sinama", SIN)): d, a, b = esleme(K, kume) print(f"{ad:<28}{a:>8.4f}{b:>9.4f}{alan_roc(d, SIN):>8.4f}{kal_hata(d, SIN):>10.4f}") A8 = lambda x: olasilik(T8, x) d8, a8, b8 = esleme(A8, EGT) print(f"\nagac d8 kalibrasyon hatasi: egitim {kal_hata(A8, EGT):.4f}, " f"dogrulama {kal_hata(A8, DOG):.4f}, sinama {kal_hata(A8, SIN):.4f}") print(f"egitimden ogrenilen esleme a {a8:.4f} b {b8:.4f}, sinamada kal.hata " f"{kal_hata(d8, SIN):.4f}")
eslemenin ogrenildigi kume a b ROC kal.hata duzeltme yok - - 0.8058 0.1512 egitim 0.3340 0.0015 0.8058 0.0244 dogrulama 0.3013 -0.3695 0.8058 0.0463 sinama 0.3038 -0.0043 0.8058 0.0208 agac d8 kalibrasyon hatasi: egitim 0.0000, dogrulama 0.1624, sinama 0.1435 egitimden ogrenilen esleme a 1.0002 b 0.0001, sinamada kal.hata 0.1435
Eşlemenin eğimi üç kümede de 0,30 dolayında: keskinleştirme skorları ne kadar uçlara ittiyse, eşleme o kadarını geri alıyor. Eğri altındaki alan dört satırda da 0,8058 — eğim pozitif olduğu sürece sıralama değişmez ve düzeltme hiçbir aboneyi yerinden oynatmaz. Kalibrasyon hatası ise 0,1512’den doğrulama kümesiyle 0,0463’e iniyor, yani üçte birine.
Sınama kümesinden öğrenilen eşleme 0,0208 veriyor; bu sayı bir başarım değil, düzeltmenin ölçüldüğü kümeden öğrenilmiş olmasının sonucudur ve 0,0463 ile arasındaki 0,0255 fark bir kestirim değil bir iyimserliktir.
Eğitim satırı bu kümede iyi çıkıyor, 0,0244; doğrusal model eğitim kümesine sıkı uymadığı için oradaki olasılıkları da aşırı güvenli değil. Kuralın gerekçesi son iki satırda. Derinlik 8 ağacının eğitim kümesindeki kalibrasyon hatası 0,0000, sınama kümesinde 0,1435 — ağacın yaprak olasılığı o yaprağın eğitim oranıdır, dolayısıyla eğitim kümesinde söylenen ile gerçekleşen tanım gereği eşittir. Eğitimden öğrenilen eşleme eğimi 1,0002, kaydırması 0,0001 buluyor ve sınamadaki hatayı 0,1435’ten 0,1435’e taşıyor: düzeltilecek bir şey görmemiştir, çünkü baktığı kümede düzeltilecek bir şey yoktur.
Özet
- Kalibrasyon, söylenen olasılık ile gerçekleşen oran arasındaki farktır ve olasılıklar aralıklara bölünerek ölçülür; doğrusal modelin sınama kümesindeki kalibrasyon hatası 0,0242’dir.
- Kesin artan bir dönüşüm sıralamayı korur: keskinleştirilmiş skorun eğri altındaki alanı da 0,8058’dir, kalibrasyon hatası ise 0,1512, altı katından fazla.
- Ortalama skorun gerçek orana yakın olması yetmez: derinlik 8 ağacının ortalaması 0,2586, gerçek oran 0,2421, aralık düzeyindeki hatası 0,1435. Sabit 0,2222 söyleyen taban çizgisi ise kalibrasyonda 0,0198 ile en iyi, eğri altındaki alanda 0,5000 ile en kötüdür.
- Doğrulamadan öğrenilen tek değişkenli eşleme kalibrasyon hatasını 0,1512’den 0,0463’e indirir ve eğri altındaki alanı 0,8058’de bırakır; eğim pozitif olduğu için hiçbir sıra değişmez.
- Ağacın eğitim kümesindeki kalibrasyon hatası tanım gereği 0,0000’dır; oradan öğrenilen eşleme birim eşlemeye yakınsar ve sınamadaki 0,1435 hatayı olduğu gibi bırakır.
Sonraki Adım
Dört derste ölçütün her biri sınıflandırma içindi ve hepsi tek bir işlemden çıktı: sayma. Karışıklık matrisi dört sayım, kesinlik ile duyarlılık iki oran, eğriler eşik başına birer sayım çifti, kalibrasyon aralık başına bir sayım karşılaştırmasıydı. Hedef bir sınıf olduğu için doğru ile yanlış ayrık iki kutuydu. Aynı kurgu kümede hedef dönem 3 ortalama tüketimi olduğunda sayılacak bir kutu kalmaz: model 22,40 der, gerçek 26,15’tir ve bu tahmin ne doğru ne yanlıştır. Sonraki ders ölçüyü uzaklığa çevirir ve taban çizgisini eğitim ortalaması olarak yeniden kurar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.