Ders 08 / 15
Yerel Açıklama Yöntemleri
Tek bir tahmini açıklayan iki yöntemin aynı abonelere sorulması ve açıklamanın sadakatinin ölçülmesi: yerel vekil model komşuluktaki kararların ortalama 0,9417'sini doğru veriyor, ama 252 abonenin 41'inde komşuluk tek etiket taşıdığı için açıklama boş çıkıyor. Vekil modelle katkı payı dağıtımı 211 dolu açıklamanın 145'inde ayrı sütun gösteriyor. Sadakat batı bölgesinde 0,9664 ile en yüksek, orada boş açıklama oranı 0,4688; en düşük sadakat 0,9027 ile en üst tarife basamağındadır ve açıklık 0,0637'dir.
İçindekiler
Önceki dersin iki sıralaması da modelin bütününe aitti. Kurgudaki abone şüpheli işaretini aldığında modelin genel olarak neye dayandığını değil, kendi kararının neye dayandığını sorar. Güney bölgesinde küresel sıralamanın ilk sırasının değişmesi, bütünün cevabının tek bir abone için doğru olmayabileceğini göstermişti.
Yerel açıklama bu soruya iki ayrı yapıyla cevap verir. Birincisi, asıl modelin bir örneğin çevresindeki davranışını taklit eden küçük bir model kurar; ikincisi, çıktıyı öznitelikler arasında paylaştırır. İkisi de bir sütun adı üretir; bu ders o iki adın ne kadar sık aynı olduğunu ve açıklamanın asıl modeli gerçekten anlatıp anlatmadığını sayar.
- YO14. Kurulum önceki iki dersinkidir: aynı kurgu abone tablosu, tohum 20260218, bölme 756/252/252, taban çizgisi 0,7579, doğrusal model sınamada 0,8016. Bakılan alt grup sayısı 13, okuma eşiği 25 kayıt.
- YO15. Yerel vekil model, açıklanan abonenin çevresinde üretilmiş 40 komşuya oturtulan tek bölmeli küçük bir modeldir. Komşular sayısal sütunların bir standart sapmalık aralığında oynatılmasıyla, iki değerli sütunun ve bölgenin 0,2 olasılıkla değişmesiyle üretilir; etiketleri gerçek etiket değil asıl modelin kararıdır.
- YO16. Açıklamanın sadakati, vekil modelin komşuluktaki kararların kaçını doğru verdiğidir. Komşuluğun tamamı tek etiket taşıyorsa vekil model sabittir: sadakati 1 olur, açıklaması boştur.
- YO17. Katkı payı dağıtımı, taban kayıttan başlayıp abonenin sütunlarını rastgele bir sırayla tek tek yerine koyar, her adımda puandaki değişimi kaydeder ve 24 sıra üzerinden ortalar. Taban kayıt eğitim kümesinin ortalamasıdır, bölgesi beş göstergenin eğitim ortalamasıdır.
- YO18. Tek özniteliği bozma, katkı payının tek sıralı biçimidir: yalnız bir sütun taban değerine çekilir. İki yöntem karşılaştırılırken her birinin verdiği ilk sütun karşılaştırılır.
İki Yöntem, Aynı Abone
Kurulum önceki derslerinkiyle aynıdır.
# yorum.py — MODELDIR. M27/K01–K07'nin KURGU abone tablosu ayni tohumla uretilir; # on iki sutunluk oznitelik kumesi ve bolme kurs boyunca sabittir. 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): # 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) 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) DOGRULUK = sum(karar(W, ALAN, O, S, x) == x["supheli"] for x in SIN) / len(SIN) print(f"egitim {len(EGT)}, dogrulama {len(DOG)}, sinama {len(SIN)}, taban " f"cizgisi {TABAN:.4f}, dogrusal modelin sinama dogrulugu {DOGRULUK:.4f}") 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]}")
egitim 756, dogrulama 252, sinama 252, taban cizgisi 0.7579, dogrusal modelin sinama dogrulugu 0.8016 alt grup sayisi 13, esik 25 kayit, esigin altinda ['tarife 10']
İki yöntem art arda kurulur ve her abone için birer sütun adı üretir.
YEREL = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma", "bolge"] TABAN_K = {a: statistics.fmean(x[a] for x in EGT) for a in ("ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma")} TABAN_K["bolge"] = None # taban kayitta bolge tek bir bolge degil, ortalama B_ORT = {"b_" + b[0]: statistics.fmean(x["b_" + b[0]] for x in EGT) for b in BOLGE} def duzelt(d): # turetilmis sutunlari yeniden hesaplar d["kisi_basi"] = round(d["ort_tuketim"] / max(1, d["hane"]), 3) if d["bolge"] is None: d.update(B_ORT) else: for b in BOLGE: d["b_" + b[0]] = int(d["bolge"] == b[0]) return d TABAN_KAYIT = duzelt(dict(SIN[0], **TABAN_K)) def komsuluk(x, sayi=40, tohum=TOHUM + 600000): r, c = uretec(tohum + int(x["ort_tuketim"] * 100) + x["hane"]), [] for _ in range(sayi): d = dict(x) for a in ("ort_tuketim", "oynaklik", "memnuniyet", "donem"): d[a] = x[a] + (2 * r() - 1) * S[a] d["hane"] = max(1, round(x["hane"] + (2 * r() - 1) * S["hane"])) if r() < 0.2: d["sifir_okuma"] = 1 - x["sifir_okuma"] if r() < 0.2: d["bolge"] = BOLGE[int(r() * 5)][0] c.append(duzelt(d)) return c def vekil(x): # MODELDIR: tek bolmeli karar agaci, yerel vekil c = komsuluk(x) y = [karar(W, ALAN, O, S, k) for k in c] if len(set(y)) == 1: return None, 1.0 # komsulugun tamami tek etiket: aciklama bos en = (0.0, None) for a in YEREL: d = sorted({k[a] for k in c}) aday = d[1:] if a in ("sifir_okuma", "bolge") else \ [d[int(i * len(d) / 8)] for i in range(1, 8)] for v in aday: sol = {i for i in range(len(c)) if (c[i][a] != v if a == "bolge" else c[i][a] < v)} if not sol or len(sol) == len(c): continue ps = sum(y[i] for i in sol) * 2 > len(sol) pg = sum(y[i] for i in range(len(c)) if i not in sol) * 2 > len(c) - len(sol) u = sum((ps if i in sol else pg) == y[i] for i in range(len(c))) / len(c) if u > en[0]: en = (u, a) return en[1], en[0] def katki(x, tur=24, tohum=TOHUM + 700000): r = uretec(tohum + int(x["ort_tuketim"] * 100) + x["hane"]) pay = {a: 0.0 for a in YEREL} for _ in range(tur): sira = list(YEREL) for i in range(len(sira) - 1, 0, -1): j = int(r() * (i + 1)) sira[i], sira[j] = sira[j], sira[i] d, onceki = dict(TABAN_KAYIT), puan(W, ALAN, O, S, TABAN_KAYIT) for a in sira: d[a] = x[a] yeni = puan(W, ALAN, O, S, duzelt(d)) pay[a] += yeni - onceki onceki = yeni return {a: pay[a] / tur for a in YEREL} def tek_bozma(x): # tek ozniteligi bozma: bir sutun tabana cekilir p0 = puan(W, ALAN, O, S, x) return {a: p0 - puan(W, ALAN, O, S, duzelt(dict(x, **{a: TABAN_K[a]}))) for a in YEREL} SADAKAT, VSUT, KSUT, TSUT = [], [], [], [] for x in SIN: a, u = vekil(x) p, t = katki(x), tek_bozma(x) SADAKAT.append(u) VSUT.append(a) KSUT.append(max(YEREL, key=lambda k: abs(p[k]))) TSUT.append(max(YEREL, key=lambda k: abs(t[k]))) DOLU = [i for i in range(len(SIN)) if VSUT[i]] AYRI = [i for i in DOLU if VSUT[i] != KSUT[i]] print(f"ortalama sadakat {sum(SADAKAT) / len(SADAKAT):.4f}; komsulugunda tek " f"etiket bulunan, yani bos aciklama alan abone {len(SIN) - len(DOLU)}") print(f"dolu aciklama {len(DOLU)}, bunlarda ortalama sadakat " f"{sum(SADAKAT[i] for i in DOLU) / len(DOLU):.4f}") print(f"vekil model ile katki payinin ayni sutunu vermedigi abone " f"{len(AYRI)}/{len(DOLU)} ({len(AYRI) / len(DOLU):.4f})") print(f"katki payi ile tek bozmanin ayristigi abone " f"{sum(1 for i in range(len(SIN)) if KSUT[i] != TSUT[i])}/{len(SIN)}") i = min(AYRI, key=lambda i: abs(puan(W, ALAN, O, S, SIN[i]) - 0.5)) x, p = SIN[i], katki(SIN[i]) print(f"\nornek abone: bolge {x['bolge']}, ortalama tuketim {x['ort_tuketim']}, " f"sifir okuma {x['sifir_okuma']}, puan {puan(W, ALAN, O, S, x):.4f}") print(f" vekil modelin bolme sutunu {VSUT[i]}, sadakat {SADAKAT[i]:.4f}") print(" katki paylari " + ", ".join(f"{a} {p[a]:+.4f}" for a in sorted(YEREL, key=lambda a: -abs(p[a]))[:3]))
ortalama sadakat 0.9417; komsulugunda tek etiket bulunan, yani bos aciklama alan abone 41 dolu aciklama 211, bunlarda ortalama sadakat 0.9303 vekil model ile katki payinin ayni sutunu vermedigi abone 145/211 (0.6872) katki payi ile tek bozmanin ayristigi abone 27/252 ornek abone: bolge dogu, ortalama tuketim 24.67, sifir okuma 0, puan 0.4885 vekil modelin bolme sutunu ort_tuketim, sadakat 0.7750 katki paylari bolge +0.1631, ort_tuketim +0.1335, oynaklik +0.0428
Örnek abone iki açıklama alıyor ve ikisi başka şey söylüyor. Vekil model, o abonenin çevresinde kararı ayıran şeyin ortalama tüketim olduğunu söylüyor ve komşuluktaki kararların 0,7750’sini doğru veriyor. Katkı payı dağıtımı, aboneyi taban kayıttan bu puana taşıyan en büyük payın bölge olduğunu söylüyor: doğu bölgesinde olmak puana 0,1631 katmış. İkisi de doğrudur ve iki ayrı soruya cevap verir: birincisi “buradan çıkış hangi sütundan olur”, ikincisi “buraya hangi sütun getirdi”. 211 dolu açıklamanın 145’inde aynı sütunu vermiyorlar. Katkı payının tek sıralı biçimi olan tek özniteliği bozma ise 27 abonede ondan ayrışıyor: bir sütunun kattığı şey ondan önce hangi sütunların yerine konduğuna bağlıdır.
Sadakat Tek Başına Okunmaz
Ortalama sadakat 0,9417 ile yüksek görünüyor. Bu sayının içinde komşuluğu tek etiket taşıyan 41 abone var: vekil model sabittir, sadakati tanım gereği 1’dir ve söylediği hiçbir şey yoktur. Boş açıklamalar dışarıda bırakıldığında sadakat 0,9303’e iniyor.
print(f"{'alt grup':<14}{'kayit':>6}{'sadakat':>9}{'bos aciklama':>14}{'ayrisma':>9}") OKUNAN = [] for ad, f in ALTGRUP: g = [i for i, x in enumerate(SIN) if f(x)] sd = sum(SADAKAT[i] for i in g) / len(g) bos = sum(1 for i in g if VSUT[i] is None) / len(g) d = [i for i in g if VSUT[i]] ay = sum(1 for i in d if VSUT[i] != KSUT[i]) / len(d) if BOY[ad] >= ENAZ: OKUNAN.append((ad, sd, ay)) print(f"{ad:<14}{len(g):>6}{sd:>9.4f}{bos:>14.4f}{ay:>9.4f}") eni, enk = max(OKUNAN, key=lambda t: t[1]), min(OKUNAN, key=lambda t: t[1]) ea = max(OKUNAN, key=lambda t: t[2]) print(f"\nokunan alt grup {len(OKUNAN)}/{len(ALTGRUP)}") print(f"sadakat en yuksek {eni[0]} {eni[1]:.4f}, en dusuk {enk[0]} {enk[1]:.4f}, " f"aciklik {eni[1] - enk[1]:.4f}") print(f"ayrisma en yuksek {ea[0]} {ea[2]:.4f}, en dusuk " f"{min(OKUNAN, key=lambda t: t[2])[0]} {min(t[2] for t in OKUNAN):.4f}")
alt grup kayit sadakat bos aciklama ayrisma bolge kuzey 68 0.9401 0.0441 0.7231 bolge guney 58 0.9586 0.2414 0.7273 bolge dogu 36 0.9028 0.1389 0.7097 bolge bati 32 0.9664 0.4688 0.4118 bolge merkez 58 0.9371 0.0690 0.6852 tarife 10 12 0.9688 0.5833 1.0000 tarife 25 193 0.9495 0.1503 0.7012 tarife 40 47 0.9027 0.1064 0.5952 hane 1-2 73 0.9538 0.2603 0.6852 hane 3-4 143 0.9320 0.1329 0.7097 hane 5+ 36 0.9556 0.0833 0.6061 okuma az 85 0.9456 0.2353 0.8154 okuma tam 167 0.9397 0.1257 0.6301 okunan alt grup 12/13 sadakat en yuksek bolge bati 0.9664, en dusuk tarife 40 0.9027, aciklik 0.0637 ayrisma en yuksek okuma az 0.8154, en dusuk bolge bati 0.4118
On üç alt gruba bakıldı, 12’si okundu. Sadakatin en yüksek olduğu alt grup batı bölgesidir, 0,9664; aynı satırda boş açıklama oranı 0,4688, yani otuz iki abonenin on beşi hiçbir şey söylemeyen bir açıklama alıyor. Sadakati yalnız başına raporlayan biri batıyı en iyi açıklanan grup diye yazar; iki sütun yan yana konduğunda o cümle tersine döner. Sadakat, açıklamanın bir şey söylediğini varsayar; söylemediğinde de yüksek çıkar.
En düşük sadakat 0,9027 ile en üst tarife basamağındadır ve açıklık 0,0637’dir. Yüksek tüketimli aboneler karar sınırının yakınında yoğunlaştığı için komşulukları iki etiket taşır ve tek bir bölme yetmez; aynı grup açıklamaların en dolu olduğu gruptur. İki yöntemin ayrışması ise alt gruplarda 0,4118 ile 0,8154 arasında değişiyor.
Özet
- Yerel vekil model komşuluktaki kararların ortalama 0,9417’sini doğru veriyor; boş açıklamalar dışarıda bırakıldığında 0,9303’e iniyor.
- 252 abonenin 41’inde komşuluk tek etiket taşıyor: vekil model sabittir, sadakati 1’dir ve açıklaması boştur. Sadakat bu yüzden tek başına okunmaz.
- Vekil model ile katkı payı dağıtımı 211 dolu açıklamanın 145’inde ayrı sütun gösteriyor; ikisi “buradan çıkış hangi sütundan olur” ve “buraya hangi sütun getirdi” sorularına cevap verir.
- On üç alt gruba bakıldı, 12’si okundu: sadakat 0,9027 ile 0,9664 arasında, açıklık 0,0637; en yüksek sadakatli grupta boş açıklama oranı 0,4688’dir.
Sonraki Adım
Bu derste açıklamalar tek tek abonelere aitti. Bir sütunun modele bütün olarak ne yaptığını görmenin başka bir yolu vardır: sütunun değeri bir uçtan öbür uca gezdirilirken öbür sütunlar kümenin kendi değerlerinde bırakılır ve ortalama puanın nasıl değiştiğine bakılır. Bu kısmi bağımlılıktır ve genellikle eğri olarak çizilir. Burada çizilmez, sayı basılır; sayı basıldığında ortalamanın ne gizlediği görünür olur. Sonraki ders bütünde düz görünen bir kısmi bağımlılığın iki alt grupta ters yönde eğimli olabildiğini kaç sütunda gerçekleştiğiyle sayar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.