İçeriğe geç
academia.sh

Ders 03 / 12

Kategorik Kodlama

Bir kategorik alanın sayıya çevrilmesinde üç kodlamanın sütun sayısı ve katkı olarak ölçülmesi: bölgenin bir-sıcak kodlanması sınama doğruluğunu 0,7302'den 0,7778'e çıkarır, 240 kodluk okuma rotası alanı bir-sıcak kodlandığında 231 ek sütuna karşılık +0,0119, sıralı kodlandığında tek sütunla aynı +0,0119 verir. Hedef temelli kodlama eğitim doğruluğunu 0,9114'e şişirirken sınamada 0,7421'e düşürür; kat içinde hesaplandığında eğitimdeki şişme 0,0595 geri çekilir ve sınama 0,7540'a döner.

İçindekiler

Önceki ders bölge bilgisini hazır beş ikili sütun olarak kullandı ve o sütunların nereden geldiğini sormadı. Bölge bir metin alanıdır. Modelin girdisi sayıdır. Aradaki çeviri bir karardır ve kararın en az iki bedeli vardır: kaç sütun ürettiği ve ayrılmış kümedeki sayıyı ne kadar oynattığı.

Bu ders üç kodlamayı aynı tabloda karşılaştırır. Bir-sıcak kodlama her kategori için ayrı bir ikili sütun açar. Sıralı kodlama kategorilere birer tamsayı verir ve tek sütunla yetinir. Hedef temelli kodlama her kategoriyi, o kategorinin eğitim kümesindeki şüpheli oranıyla değiştirir; tek sütun üretir ama etiketi kodlamanın içine sokar. Ölçüm iki kategorik alan üzerinde yapılır: beş kategorili bölge ve kardinalitesi iki yüz kırk olan okuma rotası kodu.

  • HA17. Okuma rotası kodu ham kaydın bir alanıdır ve kurgudur: her abone bir okuma rotasına bağlıdır, rotalar bölgeye ve ağın genişleme dalgasına göre açılmıştır. M26 bu alanı kullanmamıştı.
  • HA18. Rota kodu etiketle doğrudan üretilmez. Taşıdığı bilgi bölgeden ve ağa katılma dalgasından gelir; ikincisi öznitelik sütunlarında yoktur.
  • HA19. Ölçüm kümesi, bölme ve taban çizgisi önceki derslerdekiyle aynıdır: 756/252/252 ve sınama kümesinde 0,7579.
  • HA20. Model sabittir: derinlik 6 karar ağacı. Ölçekleme uygulanmaz, çünkü önceki derste ağaçtaki katkısının tam olarak sıfır olduğu gösterildi.
  • HA21. Kodlama eğitilmiş bir nesnedir. Öğrenilen şey bir-sıcak kodlamada kategori listesi, sıralı kodlamada kategori–tamsayı eşlemesi, hedef temelli kodlamada kategori–oran tablosudur. Üçü de yalnız eğitim kümesinden çıkarılır.
  • HA22. Görülmemiş kategori, ayrılmış kümede çıkıp eğitim kümesinde bulunmayan koddur. Her kodlama ona bir yanıt vermek zorundadır ve verdiği yanıt kodlamanın parçasıdır.
  • HA23. Hedef temelli kodlamanın kat içinde hesaplanması şudur: eğitim kümesi beş kata bölünür ve her satırın kodlama değeri, o satırın bulunmadığı dört kattan hesaplanır. Böylece hiçbir satırın kendi etiketi kendi kodlama değerine girmez.
  • HA24. Çapraz doğrulamanın kendisi bu derste kurulmuyor; kat yalnız kodlamanın hesaplandığı bölme olarak kullanılıyor.
  • HA25. Sınama kümesi 252 abonedir, bir abone 0,0040 eder.

Üç Kodlama, İki Sayı

Kurulum tabloyu yeniden üretir ve rota alanını ekler.

# kodlama.py — MODELDIR. Kurgu abone tablosu ayni tohumla uretilir; ham kayittan
# gelen KURGU okuma rotasi kodu kategorik sutun olarak eklenir.
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, rr = [], uretec(TOHUM + 41000)
for k in ABONE:
    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 = {"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]}
    dalga = min(7, int((k["no"] - 10001) / 1399 * 8))       # aga katilma dalgasi
    x["rota"] = "R%03d" % ([b[0] for b in BOLGE].index(k["bolge"][0]) * 48
                           + dalga * 6 + int(rr() * 6) + 1)
    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, SIN = K[:756], K[1008:]
TABAN = sum(x["supheli"] == 0 for x in SIN) / len(SIN)
SAY = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma"]
EK = {x["rota"] for x in EGT}
BOY = {}
for x in EGT:
    BOY[x["rota"]] = BOY.get(x["rota"], 0) + 1
print(f"rota kodu: tabloda {len({x['rota'] for x in VERI})}, egitimde {len(EK)}, "
      f"en kalabalik rota {max(BOY.values())} abone, ortalama "
      f"{sum(BOY.values()) / len(BOY):.1f}")
print(f"sinamada gorulmemis rota kodu {len({x['rota'] for x in SIN} - EK)}, "
      f"bu kodlardaki abone {sum(1 for x in SIN if x['rota'] not in EK)}")
print(f"bolge {len({x['bolge'] for x in EGT})} kategori, taban cizgisi {TABAN:.4f}")
rota kodu: tabloda 240, egitimde 231, en kalabalik rota 9 abone, ortalama 3.3
sinamada gorulmemis rota kodu 6, bu kodlardaki abone 10
bolge 5 kategori, taban cizgisi 0.7579

Rota başına ortalama 3,3 abone düşüyor ve en kalabalık rota dokuz abone. Bu sayı dersin ikinci yarısında belirleyici olacak. Şimdi dört kodlama sırayla uygulanır.

def gini(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, alan, enaz=2):        # MODELDIR: karar agaci, derinlik 6
    p = sum(x["supheli"] for x in s) / len(s)
    en = None
    if derinlik and len(s) >= 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 = gini(s) - (len(sol) * gini(sol) + len(sag) * gini(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, alan, enaz),
            "sag": agac(en[4], derinlik - 1, alan, enaz)}


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 bir_sicak(sutun, egt, sin):             # OGRENME: egitimdeki kategori listesi
    kat = sorted({x[sutun] for x in egt})
    ac = (lambda s: [dict(x, **{sutun + "_" + k: int(x[sutun] == k) for k in kat})
                     for x in s])
    return [sutun + "_" + k for k in kat], ac(egt), ac(sin)


def sirali(sutun, egt, sin, sira=None):     # OGRENME: kategori -> tamsayi eslemesi
    kat = sira or {k: i for i, k in enumerate(sorted({x[sutun] for x in egt}))}
    ac = lambda s: [dict(x, rota_s=kat.get(x[sutun], -1)) for x in s]
    return ["rota_s"], ac(egt), ac(sin)


def oran(satirlar):
    m = {}
    for x in satirlar:
        m.setdefault(x["rota"], []).append(x["supheli"])
    return {k: sum(v) / len(v) for k, v in m.items()}


def hedef(egt, sin):                        # OGRENME: kategori basina supheli orani
    g, t = sum(x["supheli"] for x in egt) / len(egt), oran(egt)
    ac = lambda s: [dict(x, rota_h=t.get(x["rota"], g)) for x in s]
    return ["rota_h"], ac(egt), ac(sin)


def hedef_kat_icinde(egt, sin, kat=5):      # her satir kendi katinin disindan
    g, t = sum(x["supheli"] for x in egt) / len(egt), oran(egt)
    tablo = [oran([y for j, y in enumerate(egt) if j % kat != i]) for i in range(kat)]
    e = [dict(x, rota_h=tablo[i % kat].get(x["rota"], g)) for i, x in enumerate(egt)]
    return ["rota_h"], e, [dict(x, rota_h=t.get(x["rota"], g)) for x in sin]


SONUC = {}


def olc(ad, alan, e, s):
    m = agac(e, 6, alan)
    de = sum(tahmin(m, x) == x["supheli"] for x in e) / len(e)
    ds = sum(tahmin(m, x) == x["supheli"] for x in s) / len(s)
    SONUC[ad] = (len(alan), de, ds)
    print(f"{ad:<28} {len(alan):>6} {de:>8.4f} {ds:>8.4f}")


print(f"{'kodlama':<28} {'sutun':>6} {'egitim':>8} {'sinama':>8}")
olc("kategorik sutun yok", SAY, EGT, SIN)
ab, eb, sb = bir_sicak("bolge", EGT, SIN)
olc("bolge bir-sicak", SAY + ab, eb, sb)
for ad, fn in (("+ rota bir-sicak", lambda: bir_sicak("rota", eb, sb)),
               ("+ rota sirali", lambda: sirali("rota", eb, sb)),
               ("+ rota hedef temelli", lambda: hedef(eb, sb)),
               ("+ rota hedef, kat icinde", lambda: hedef_kat_icinde(eb, sb))):
    a, e, s = fn()
    olc(ad, SAY + ab + a, e, s)
kodlama                       sutun   egitim   sinama
kategorik sutun yok               6   0.8492   0.7302
bolge bir-sicak                  11   0.8466   0.7778
+ rota bir-sicak                242   0.8452   0.7897
+ rota sirali                    12   0.8651   0.7897
+ rota hedef temelli             12   0.9114   0.7421
+ rota hedef, kat icinde         12   0.8519   0.7540

İlk iki satır kodlamanın kendisinin ne ettiğini söylüyor. Kategorik alanlar hiç kullanılmadığında model 0,7302 okuyor ve taban çizgisinin 0,0277 altında kalıyor. Beş kategorili bölge alanı beş ikili sütuna açıldığında sayı 0,7778’e çıkıyor: on iki abone. Bu, kursun şimdiye kadarki en büyük tek katkısıdır ve kararın kendisi görünmezdir, çünkü bölgenin sayıya çevrilmesi genellikle tartışılmadan yapılır.

Aynı Katkı, İki Yüz Otuz Bir Sütun Farkı

Rota alanının üç kodlaması aynı tabloda yan yana durunca ödenen bedel görünür oluyor.

t = SONUC["bolge bir-sicak"]
print(f"{'kodlama':<28} {'ek sutun':>9} {'egitim katki':>13} {'sinama katki':>13}")
for ad in ("+ rota bir-sicak", "+ rota sirali", "+ rota hedef temelli",
           "+ rota hedef, kat icinde"):
    v = SONUC[ad]
    print(f"{ad:<28} {v[0] - t[0]:>9} {v[1] - t[1]:>+13.4f} {v[2] - t[2]:>+13.4f}")

kod = sorted(EK)
kr = uretec(TOHUM + 43000)
kk = list(range(len(kod)))
for i in range(len(kk) - 1, 0, -1):
    j = int(kr() * (i + 1))
    kk[i], kk[j] = kk[j], kk[i]
a, e, s = sirali("rota", eb, sb, {k: kk[i] for i, k in enumerate(kod)})
m = agac(e, 6, SAY + ab + a)
print(f"\nsirali kodlama, kod sirasi karistirilinca: sinama "
      f"{sum(tahmin(m, x) == x['supheli'] for x in s) / len(s):.4f}")

g = sum(x["supheli"] for x in EGT) / len(EGT)
_, _, sh = hedef(eb, sb)
yeni = [x for x in sh if x["rota"] not in EK]
print(f"gorulmemis rotadaki {len(yeni)} abone: bir-sicak kodlamada 231 sutunun hepsi 0, "
      f"sirali kodlamada -1, hedef temelli kodlamada {g:.4f}")
print(f"kat icinde hesaplanan kodlamanin egitimdeki sismesi "
      f"{SONUC['+ rota hedef temelli'][1] - SONUC['+ rota hedef, kat icinde'][1]:+.4f}, "
      f"sinamada geri alinan "
      f"{SONUC['+ rota hedef, kat icinde'][2] - SONUC['+ rota hedef temelli'][2]:+.4f}")
kodlama                       ek sutun  egitim katki  sinama katki
+ rota bir-sicak                   231       -0.0013       +0.0119
+ rota sirali                        1       +0.0185       +0.0119
+ rota hedef temelli                 1       +0.0648       -0.0357
+ rota hedef, kat icinde             1       +0.0053       -0.0238

sirali kodlama, kod sirasi karistirilinca: sinama 0.7778
gorulmemis rotadaki 10 abone: bir-sicak kodlamada 231 sutunun hepsi 0, sirali kodlamada -1, hedef temelli kodlamada 0.2222
kat icinde hesaplanan kodlamanin egitimdeki sismesi +0.0595, sinamada geri alinan +0.0119

İlk iki satır aynı katkıyı iki farklı fiyata veriyor: bir-sıcak kodlama 231 ek sütun karşılığında 0,0119, sıralı kodlama tek sütun karşılığında yine 0,0119. Üç abonelik bu fark tek başına okunmazdı; okunan şey fiyat farkıdır. Bir-sıcak kodlamanın maliyeti kardinaliteyle birlikte doğrusal büyür ve 756 satırlık bir eğitim kümesinde 231 sütun, her sütuna ortalama üç satır düşmesi demektir.

Sıralı kodlamanın bu tabloda işe yaramasının bir sebebi var ve karıştırma sınaması onu ortaya koyuyor. Kod numaraları rastgele verilmemiş; önce bölgeye, sonra ağa katılma dalgasına göre sıralanmışlar, dolayısıyla “rota numarası küçüktür” demek bir şeyler söylüyor. Eşleme karıştırıldığında sınama sayısı 0,7778’e, yani rota alanı hiç kullanılmamış gibi bir yere düşüyor. Sıralı kodlamanın katkısı kategorilerden değil, kodun kendi sırasından gelir; sıra uydurma olduğunda katkı sıfırdır.

Üçüncü satır dersin asıl sayısıdır. Hedef temelli kodlama eğitim kümesinde 0,0648 kazandırıyor ve sınama kümesinde 0,0357 kaybettiriyor. İki sayının ters işareti tesadüf değil, aynı olayın iki yüzüdür. Rota başına ortalama 3,3 abone düşüyor; üç abonelik bir rotanın şüpheli oranı, o üç satırın etiketlerinin ortalamasıdır ve her satırın kendi etiketi o ortalamanın üçte biridir. Ağaç bu sütunu okuduğunda satırın etiketinin bir kopyasını okumuş olur. Eğitim kümesinde 0,9114 çıkması öğrenmenin değil, kendini okumanın sonucudur.

Kat içinde hesaplama bunu düzeltir. Her satırın kodlama değeri, o satırın bulunmadığı dört kattan çıkarıldığında eğitimdeki şişmenin 0,0595’i kayboluyor ve sınama sayısı 0,0119 geri geliyor. Yine de kalan katkı −0,0238’dir: sızıntı geri çekildikten sonra bile hedef temelli kodlama bu alanda tabanın altında kalıyor. Ölçülen sonuç şudur — sızıntıyı gidermek adımı iyi yapmaz, yalnız adımın gerçek katkısını görünür kılar.

Son satır kodlamanın sessiz yüzüdür. Sınama kümesinde on abone, eğitim kümesinde hiç görülmemiş altı rotaya bağlı. Bir-sıcak kodlama onlara 231 sıfırdan oluşan bir satır veriyor, sıralı kodlama eğitim aralığının dışında bir −1 veriyor, hedef temelli kodlama eğitim kümesinin genel oranını, 0,2222’yi veriyor. Üçü de bir karardır ve üçü de kodlamanın parçasıdır; hiçbiri kendiliğinden doğru değildir.

Özet

  • Kategorik alanlar hiç kullanılmadığında model 0,7302 ile taban çizgisinin altında kalıyor; beş kategorili bölge alanı bir-sıcak kodlandığında 0,7778’e çıkıyor, katkı +0,0476.
  • Kardinalitesi 240 olan rota alanı bir-sıcak kodlandığında 231 ek sütuna karşılık +0,0119, sıralı kodlandığında tek sütuna karşılık yine +0,0119 veriyor; aynı katkının iki farklı fiyatı vardır.
  • Sıralı kodlamanın katkısı kodun kendi sırasından gelir: kategori–tamsayı eşlemesi karıştırıldığında sınama sayısı 0,7778’e, yani alan hiç kullanılmamış düzeye düşüyor.
  • Hedef temelli kodlama eğitimde +0,0648, sınamada −0,0357 veriyor; rota başına 3,3 abone düştüğü için her satırın kendi etiketi kendi kodlama değerinin içindedir.
  • Kat içinde hesaplama eğitimdeki şişmenin 0,0595’ini siliyor ve sınamada 0,0119 geri getiriyor, ama kalan katkı −0,0238’dir; sızıntıyı gidermek adımı iyi yapmaz, gerçek katkısını gösterir.

Sonraki Adım

Bu derste memnuniyet sütunu her abone için dolu kabul edildi. Ham kayıtta öyle değil: memnuniyet bir anket yanıtıdır ve anketi yanıtlamayan abone vardır. Şimdiye kadarki bütün derslerde o boşluk sessizce eğitim kümesinin ortancasıyla dolduruldu ve doldurmanın kendisi hiç ölçülmedi. Sonraki ders boşluğu geri koyar ve üç seçeneği yan yana basar: ortanca ile doldurmak, doldurup yanına bir eksiklik göstergesi eklemek ve eksik satırı eğitim kümesinden atmak. Eksikliğin abonenin kendisi hakkında bilgi taşıdığı durumda göstergenin katkısı ölçülür ve satır atmanın ayrılmış kümede niçin uygulanamayacağı sayıyla gösterilir.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat