Ders 02 / 11
Öğrenme Türleri
Aynı kaçak şüphesi problemi dört kurulumda kurulur ve her kurulumun istediği etiket sayısı sayılır: denetimli 883 etiketle ayrılmış kümede 0,8594, denetimsiz 6 etiketle 0,8117, yarı denetimli 60 etiketle 0,8090, pekiştirmeli 120 ziyaretle 0,8090. Taban çizgisi 0,7533'tür. Etiket bütçesi 883'ten 30'a inerken ayrılmış küme sayısı 0,8594'ten 0,7745'e düşer, eğitim sayısı ise 0,8709'dan 0,9400'e çıkar. İki kümeli bölme tabanın tam üstüne oturur, altı kümeli bölme 0,0584 kazandırır. Ziyaret politikası 120 ziyarette 73 kaçak bulur, aynı bütçe rastgele harcansa 25 bulunur.
İçindekiler
Önceki ders tek bir kurulum kullandı: 883 abonenin etiketi biliniyordu ve yordam hepsini gördü. Etiket orada bedava üretildi. Sahada bir etiket bir kapı ziyareti demektir; ziyaret sayılıdır. Kurulumu belirleyen şey budur — hangi bilgi, ne kadarıyla, ne karşılığında elde ediliyor.
Bu ders aynı problemi dört kurulumda kurar ve her kurulumun kaç etiket istediğini sayar. Ölçü ve ayrılmış küme dördünde de aynı kalır ki sayılar yan yana okunabilsin.
- MK8. Denetimli öğrenme (supervised learning): her örneğin etiketi bilinir. Yordam öznitelikten etikete giden eşlemeyi doğrudan arar.
- MK9. Denetimsiz öğrenme (unsupervised learning): etiket yoktur. Çıktı bir karar değil bir yapıdır; yapıyı karara çevirmek ayrı bir iştir ve etiket ister.
- MK10. Yarı denetimli öğrenme (semi-supervised learning): az sayıda etiketli örnek, çok sayıda etiketsiz örnekle birlikte kullanılır. Etiketsiz satırların katkısı ölçülebilir bir sayıdır.
- MK11. Pekiştirmeli öğrenme (reinforcement learning): etiket önceden verilmez, eylemin karşılığında gelir. Yordam kimi ziyaret edeceğini seçer, yalnız ziyaret ettiğinin etiketini görür ve bir sonraki seçimi buna göre yapar.
- MK12. Etiket bir bütçedir. Bu derste kurulumların karşılaştırma birimi doğruluk değil, doğruluk başına harcanan etikettir.
- MK13. Pekiştirmeli kurulumun asıl ölçüsü doğruluk değil getiridir: harcanan bütçede bulunan kaçak sayısı. Doğruluk yine basılır, ama kurulumu tarif eden sayı getiridir.
Kurgu Kümenin Yeniden Kurulması
# kurulum.py — 01. dersin kurgu kumesi ayni tohumla yeniden kurulur: okuma # tablosu, abone ozeti, kurgu etiket, egitim / ayrilmis ayrimi ve agac ogrenici. import math TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26), ("bati", 0.14, 14), ("merkez", 0.18, 23)] OZNITELIK = ["ortalama", "kisi_basi", "dusus", "sifir_okuma", "okuma_sayisi", "memnuniyet", "hane_kisi", "en_yuksek", "en_dusuk"] 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 _ab, _el, _seri = [], [], {} for i in range(HAM): r = uretec(TOHUM + i) b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])] k = {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2], "hane_kisi": ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05]), "memnuniyet": ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17]) + 1} (_el if r() < 0.046 else _ab).append(k) _gecerli = {a["abone_no"] for a in _ab} for k in _ab + _el: r = uretec(TOHUM + 7000 + k["abone_no"]) for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])): t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp( (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100 if k["abone_no"] in _gecerli: _seri.setdefault(k["abone_no"], []).append(t) r() ABONE = [] for k in _ab: t = _seri.get(k["abone_no"]) if not t: continue ort = sum(t) / len(t) a = {"abone_no": k["abone_no"], "bolge": k["bolge"], "seri": t, "hane_kisi": k["hane_kisi"], "memnuniyet": k["memnuniyet"], "okuma_sayisi": len(t), "ortalama": ort, "en_yuksek": max(t), "en_dusuk": min(t), "sifir_okuma": sum(1 for v in t if v == 0), "kisi_basi": ort / max(1, k["hane_kisi"]), "dusus": (t[0] - t[-1]) / t[0] if len(t) > 1 and t[0] > 0 else 0.0} r = uretec(TOHUM + 31000 + a["abone_no"]) a["suphe"] = 1 if (1.30 * a["sifir_okuma"] + 1.25 * (a["dusus"] > 0.45) + 1.05 * (a["kisi_basi"] > 12.0) + 0.65 * (a["okuma_sayisi"] < 3) + 0.45 * (a["memnuniyet"] <= 2) - 1.55 + (r() + r() - 1.0) * 1.1) > 0 else 0 ABONE.append(a) r = uretec(TOHUM + 90001) EGITIM, AYRILMIS = [], [] for a in ABONE: (EGITIM if r() < 0.70 else AYRILMIS).append(a) poz = lambda k: sum(a["suphe"] for a in k) dogruluk = lambda f, k: sum(1 for a in k if f(a) == a["suphe"]) / len(k) _saf = lambda k: 2 * (poz(k) / len(k)) * (1 - poz(k) / len(k)) if k else 0.0 def ogren(k, derinlik=3, en_az=40): """01. dersin acgozlu karar agaci: bolme olcutu ve durma kurali orada.""" en, secim = _saf(k) * len(k), None if derinlik and len(k) >= en_az: for oz in OZNITELIK: for e in sorted({a[oz] for a in k})[1:]: sol = [a for a in k if a[oz] < e] sag = [a for a in k if a[oz] >= e] m = _saf(sol) * len(sol) + _saf(sag) * len(sag) if m < en - 1e-9: en, secim = m, (oz, e, sol, sag) if secim is None: return 1 if 2 * poz(k) > len(k) else 0 s, g = ogren(secim[2], derinlik - 1, en_az), ogren(secim[3], derinlik - 1, en_az) return s if s == g else (secim[0], secim[1], s, g) def uygula(d, a): while isinstance(d, tuple): d = d[2] if a[d[0]] < d[1] else d[3] return d print(f"kurgu kume (tohum {TOHUM}): {len(ABONE)} abone, {len(EGITIM)} egitim, " f"{len(AYRILMIS)} ayrilmis, {poz(ABONE)} supheli")
kurgu kume (tohum 20260218): 1260 abone, 883 egitim, 377 ayrilmis, 327 supheli
Denetimli: Etiket Bütçesi Küçüldükçe
Denetimli kurulumda değişen tek şey kaç etiket verildiğidir. Küçük bütçelerde tek çekim yanıltıcı olur, bu yüzden her bütçe için beş ayrı altküme çekilir ve sayılar ortalanır.
# denetimli.py — etiket sayisi bir butcedir: ayni yordam artan etiketle kurulur. # Her butce icin bes ayri rastgele altkume cekilir ve iki sayi ortalanir. import statistics from collections import Counter BUTCE, CEKIM = [30, 60, 150, 400, 883], 5 en_sik = Counter(a["suphe"] for a in EGITIM).most_common(1)[0][0] TABAN_E, TABAN_A = dogruluk(lambda a: en_sik, EGITIM), dogruluk(lambda a: en_sik, AYRILMIS) E = [20, 10, 12, 12] y = lambda h: str(h[0]).ljust(E[0]) + "".join(str(v).rjust(E[i + 1]) for i, v in enumerate(h[1:])) print(y(["etiket", "egitimde", "ayrilmista", "tabana gore"])) print(y(["taban (0 etiket)", f"{TABAN_E:.4f}", f"{TABAN_A:.4f}", "0.0000"])) for n in BUTCE: ic, dis = [], [] for j in range(CEKIM): r = uretec(TOHUM + 4100 + j) alt = sorted(EGITIM, key=lambda a: r())[:n] d = ogren(alt, 3, max(12, n // 20)) ic.append(dogruluk(lambda a: uygula(d, a), alt)) dis.append(dogruluk(lambda a: uygula(d, a), AYRILMIS)) o = statistics.fmean(dis) print(y([n, f"{statistics.fmean(ic):.4f}", f"{o:.4f}", f"{o - TABAN_A:+.4f}"]))
etiket egitimde ayrilmista tabana gore taban (0 etiket) 0.7350 0.7533 0.0000 30 0.9400 0.7745 +0.0212 60 0.9267 0.7841 +0.0308 150 0.8947 0.7873 +0.0340 400 0.8725 0.8419 +0.0886 883 0.8709 0.8594 +0.1061
Tabanın üstündeki fark bütçeyle birlikte eriyor: 883 etikette 0,1061, 400’de 0,0886, 30’da 0,0212. Otuz etiketle kurulan bir model tabanı geçiyor, ama geçtiği pay 883 etiketlinin beşte biri kadar.
İki sütun ters yönde hareket ediyor. Etiket azaldıkça ayrılmış küme sayısı düşerken eğitim sayısı yükseliyor: 30 etikette 0,9400, 883 etikette 0,8709. Otuz satırlık bir kümede ağaç neredeyse her satırı doğru sınıflandırabilir; ayrılmış kümede aynı ağaç 0,7745’te kalır. Bu ters hareket Genelleme konusunun konusudur; burada yalnız kayda geçirilir.
Denetimsiz: Etiketsiz Yapı ve Adlandırma Bedeli
Denetimsiz kurulumda etiket sütunu hiç okunmaz. Yordam yalnız öznitelik uzayına bakar ve birbirine yakın aboneleri kümelere ayırır. Ölçekler farklı olduğu için her öznitelik ortalaması çıkarılıp kendi değişkenliğine bölünür; yoksa metreküp cinsinden bir sütun küçük ölçekli sütunları ezer.
Bu kurulumun çıktısı bir karar değildir. “Bu abone dördüncü kümede” cümlesi saha ekibine bir şey söylemez; kümenin adı gerekir. Adlandırma etiket ister: her kümeden bir abone ziyaret edilir, kümenin adı o abonenin etiketi olur, maliyet K etikettir.
# denetimsiz.py — etiket hic kullanilmadan kume yapisi cikarilir. Cikti bir # karar degil bir yapidir; karara cevirmek icin her kumeden bir abone ziyaret # edilir ve kumenin adi o abonenin etiketi olur: maliyet K etiket. ORT = {o: statistics.fmean(a[o] for a in EGITIM) for o in OZNITELIK} SAP = {o: statistics.pstdev(a[o] for a in EGITIM) or 1.0 for o in OZNITELIK} r = uretec(TOHUM + 4100) KARISIK = sorted(EGITIM, key=lambda a: r()) vek = lambda a: [(a[o] - ORT[o]) / SAP[o] for o in OZNITELIK] uzak = lambda v, m: sum((x - y) ** 2 for x, y in zip(v, m)) def kumele(K): """K merkez rastgele secilir, yirmi turda uyeliklerin ortalamasina cekilir.""" r = uretec(TOHUM + 4202) mk = [vek(KARISIK[int(r() * len(KARISIK))]) for _ in range(K)] for _ in range(20): gr = [[] for _ in range(K)] for a in EGITIM: v = vek(a) gr[min(range(K), key=lambda i: uzak(v, mk[i]))].append(v) for i in range(K): if gr[i]: mk[i] = [sum(c) / len(c) for c in zip(*gr[i])] return lambda a: min(range(K), key=lambda i: uzak(vek(a), mk[i])) print(y(["kume sayisi", "etiket", "egitimde", "ayrilmista"])) KUME = {} for K in (2, 6): hangi, isim = kumele(K), {} for a in KARISIK: isim.setdefault(hangi(a), a["suphe"]) f = lambda a, h=hangi, i=isim: i[h(a)] KUME[K] = (hangi, f, isim) print(y([K, K, f"{dogruluk(f, EGITIM):.4f}", f"{dogruluk(f, AYRILMIS):.4f}"])) hangi6 = KUME[6][0] print("K=6 kume boylari", sorted(Counter(hangi6(a) for a in EGITIM).values(), reverse=True), "supheli adlandirilan kumenin boyu", sum(1 for a in EGITIM if KUME[6][2][hangi6(a)] == 1))
kume sayisi etiket egitimde ayrilmista 2 2 0.7350 0.7533 6 6 0.7780 0.8117 K=6 kume boylari [268, 157, 147, 131, 102, 78] supheli adlandirilan kumenin boyu 78
İki kümeli bölme tabanın tam üstüne oturuyor: 0,7533, farkı sıfır. İki küme de temiz diye adlandırılmış, yani yordam herkese “temiz” diyen taban çizgisiyle aynı kararı vermiştir. Kümeleme şüpheye göre bölmez; en büyük değişkenliğe göre böler ve bu kümede en büyük değişkenlik tüketim büyüklüğündedir, kaçakta değil.
Altı kümeli bölmede tablo değişiyor: 0,8117, tabanın 0,0584 üstünde. 78 abonelik en küçük küme şüpheli diye adlandırılmış ve altı etiketten biri bunu belirlemeye yetmiştir. Küme sayısı bir karardır ve etkisi 0,0584’tür — kümelemenin değil, kaç küme denmesinin ürettiği bir fark.
Yarı Denetimli: Etiketsiz Satırların Katkısı
Yarı denetimli kurulumda 60 abonenin etiketi bilinir, 823’ünki bilinmez. Etiketsiz satırlar atılmaz: kümeleme yapısına göre her birine bir atanmış etiket (pseudo-label) verilir ve ağaç 60 gerçek etiketle 823 atanmış etiketin toplamı üzerinde kurulur.
# yari.py — 60 etiket + 823 etiketsiz satir: etiketsiz satirlar kume yapisindan # atanmis etiket alir, agac 60 gercek ve 823 atanmis etiketle kurulur. ETIKETLI, ETIKETSIZ = KARISIK[:60], KARISIK[60:] isim60 = {} for i in range(6): alt = [x["suphe"] for x in ETIKETLI if hangi6(x) == i] isim60[i] = 1 if alt and 2 * sum(alt) > len(alt) else 0 ATANMIS = [{**a, "suphe": isim60[hangi6(a)]} for a in ETIKETSIZ] d60, dyari = ogren(ETIKETLI, 3, 12), ogren(ETIKETLI + ATANMIS, 3, 40) f60, fyari = lambda a: uygula(d60, a), lambda a: uygula(dyari, a) uyan = sum(1 for p, a in zip(ATANMIS, ETIKETSIZ) if p["suphe"] == a["suphe"]) print(f"atanmis etiket {len(ATANMIS)}, gercek etiketle uyusan {uyan}, " f"oran {uyan / len(ATANMIS):.4f}") print(y(["kurulum", "etiket", "egitimde", "ayrilmista"])) for ad, f in [("yalniz 60 etiket", f60), ("60 + 823 etiketsiz", fyari)]: print(y([ad, 60, f"{dogruluk(f, EGITIM):.4f}", f"{dogruluk(f, AYRILMIS):.4f}"]))
atanmis etiket 823, gercek etiketle uyusan 633, oran 0.7691 kurulum etiket egitimde ayrilmista yalniz 60 etiket 60 0.7792 0.7905 60 + 823 etiketsiz 60 0.7780 0.8090
Aynı 60 etiket, iki kurulum, iki sayı. Etiketsiz 823 satır eklendiğinde ayrılmış küme sayısı 0,7905’ten 0,8090’a çıkıyor: 0,0185. Atanmış etiketlerin yalnız yüzde 76,91’i gerçek etiketle uyuşmaktadır, yani üçte birine yakını yanlıştır ve buna rağmen katkı artıdır. Etiketsiz satırların taşıdığı şey etiket değil, yoğunluk bilgisidir: hangi öznitelik bileşimlerinin sık, hangilerinin seyrek olduğu.
Pekiştirmeli: Etiketi Eylemle Kazanmak
Dördüncü kurulumda etiket sütunu kapalıdır. Yordam bir abone seçer, o abone ziyaret edilir ve yalnız o abonenin etiketi açılır. Bütçe altı turda yirmişer ziyarettir. İlk tur rastgeledir, sonraki turlarda seçim o ana kadar görülen etiketlerle kurulan beş ağacın oyuna göre yapılır.
# pekistirmeli.py — etiket ancak ziyaret edilince goruluyor. Alti turda yirmiser # ziyaret; her tur, o ana kadar gorulenlerle kurulan bes agacin oyuna gore secilir. TUR, ADIM = 6, 20 r = uretec(TOHUM + 4404) HAVUZ = sorted(EGITIM, key=lambda a: r()) ziyaret, gorulen = [], set() print(y(["tur", "ziyaret", "bulunan", "toplam"])) for t in range(TUR): if not ziyaret: sec = HAVUZ[:ADIM] else: top = [ogren([ziyaret[int(r() * len(ziyaret))] for _ in ziyaret], 3, 10) for _ in range(5)] sec = sorted((a for a in HAVUZ if a["abone_no"] not in gorulen), key=lambda a: (-sum(uygula(d, a) for d in top), a["abone_no"]))[:ADIM] gorulen.update(a["abone_no"] for a in sec) ziyaret += sec print(y([t + 1, ADIM, poz(sec), poz(ziyaret)])) dpek, dtam = ogren(ziyaret, 3, 20), ogren(EGITIM) print(f"\n{len(ziyaret)} ziyarette bulunan kacak {poz(ziyaret)}; " f"ayni butce rastgele harcansa {poz(HAVUZ[:TUR * ADIM])}") print(y(["kurulum", "etiket", "egitimde", "ayrilmista"])) SON = [("denetimli", 883, lambda a: uygula(dtam, a)), ("denetimsiz", 6, KUME[6][1]), ("yari denetimli", 60, fyari), ("pekistirmeli", TUR * ADIM, lambda a: uygula(dpek, a))] for ad, n, f in SON: print(y([ad, n, f"{dogruluk(f, EGITIM):.4f}", f"{dogruluk(f, AYRILMIS):.4f}"]))
tur ziyaret bulunan toplam 1 20 4 4 2 20 11 15 3 20 8 23 4 20 11 34 5 20 19 53 6 20 20 73 120 ziyarette bulunan kacak 73; ayni butce rastgele harcansa 25 kurulum etiket egitimde ayrilmista denetimli 883 0.8709 0.8594 denetimsiz 6 0.7780 0.8117 yari denetimli 60 0.7780 0.8090 pekistirmeli 120 0.7973 0.8090
Getiri sütunu turdan tura yükseliyor: 4, 11, 8, 11, 19, 20. Altıncı turda seçilen yirmi abonenin yirmisi de kaçaktır. Toplamda 120 ziyarette 73 kaçak bulunmuştur; aynı bütçe rastgele harcansaydı 25 bulunurdu. Taban çizgisi burada en sık sınıf değil rastgele ziyarettir, çünkü ölçülen şey sınıflandırma doğruluğu değil bütçenin getirisidir ve rastgele ziyaret öğrenmeyen yordamın bu ölçüdeki karşılığıdır. Fark 48 kaçaktır.
Son tablo dört kurulumu yan yana koyuyor. Doğruluk sütununda üç kurulum çok yakın duruyor — 0,8117, 0,8090, 0,8090 — ama etiket sütunları 6, 60 ve 120’dir. Aynı sayıyı yirmi kat farklı bütçeyle üretmek aynı şey değildir. Pekiştirmeli kurulumun 120 etiketinin 73’ü sahada bulunmuş kaçak olarak geri dönmüştür; onun sayısı getiri satırında okunur.
Özet
- Dört kurulum aynı problemi çözer ve dördü de aynı ayrılmış kümede ölçülür: denetimli 883 etiketle 0,8594, denetimsiz 6 etiketle 0,8117, yarı denetimli 60 etiketle 0,8090, pekiştirmeli 120 ziyaretle 0,8090; taban çizgisi 0,7533’tür.
- Etiket bütçesi küçüldükçe tabanın üstündeki fark eriyor: 883 etikette 0,1061, 400’de 0,0886, 30’da 0,0212. Aynı düşüşte eğitim sayısı ters yönde, 0,8709’dan 0,9400’e çıkıyor.
- Denetimsiz kurulumun çıktısı karar değil yapıdır; yapıyı karara çevirmek küme başına bir ziyaret ister. İki kümeli bölme tabanın tam üstüne oturur, altı kümeli bölme 0,0584 kazandırır.
- Yarı denetimli kurulumda etiketsiz 823 satır, aynı 60 etiketle kurulan modeli 0,7905’ten 0,8090’a taşır; atanmış etiketlerin yalnız yüzde 76,91’i doğrudur.
- Pekiştirmeli kurulumun ölçüsü getiridir: 120 ziyarette 73 kaçak, rastgele ziyaretle 25; fark 48 kaçaktır ve bu sayı doğruluk sütununda görünmez.
Sonraki Adım
Dört kurulumun üçü etikete para ödedi, dördüncüsü etiketi ziyaretle kazandı. Hiçbiri şunu sormadı: etiket veriden türetilebilir mi. Okuma tablosunda kimsenin etiketlemediği bir yapı vardır — her abonenin dönemler boyunca izlediği yol. Bir dönemin okumasından sonrakini kestirmek etiket istemez, çünkü cevap zaten tablodadır. Sonraki ders bu kurulumu kurar: etiketsiz bir vekil görevle bir gösterim öğrenilir, o gösterim asıl göreve öznitelik olarak verilir ve vekil görevin asıl görevde taban çizgisi üzerine kaç puan kattığı ölçülür.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.