İçeriğe geç
academia.sh

Ders 10 / 12

Boyut Azaltmanın Öznitelik Rolü

On üç ham özniteliğin yerine bileşen temelli bir temsil konduğunda ayrılmış küme sayısının ve yorumlanabilirliğin ne olduğunun ölçülmesi: ham sütunlar sınamada 0,8254 verirken iki bileşen 0,8175, üç bileşen 0,8056, beş bileşen 0,7778, sekiz bileşen 0,7460 veriyor ve hiçbir bileşen sayısında ham temsile yetişilemiyor. En büyük bileşen payını taşıyan bileşen tek başına 0,7381 ile tabanın altında kalırken payı 0,093 olan beşinci bileşen 0,7659 veriyor. Ham temsilde bölmelerin 0,35'i ortalama tüketimden okunurken bileşen temsilinde aynı pay adı olmayan bir karışıma düşüyor.

İçindekiler

Önceki ders sütun sayısını azaltmanın bir yolunu ölçtü: sütunları teker teker tutmak ya da atmak. Gömülü yöntem yirmi beş adaydan on dördünü tuttu ve ayrılmış kümede 0,8254 verdi; iki dersin elle ölçerek kurduğu on üç sütunluk küme de aynı sayıyı verdi. Tutulan sütunların hepsinin bir adı var ve ne anlama geldikleri biliniyor.

Sütun sayısını azaltmanın ikinci yolu sütunları atmak yerine karıştırmaktır. On üç sütun, her biri on üçünün ağırlıklı toplamı olan birkaç yeni sütuna dönüştürülebilir; bunlara bileşen denir ve bileşenler kümedeki değişkenliği en çok taşıyan yönlerden başlayarak sıralanır. M26/K05’in keşifsel analiz kursu bileşen payını orada ölçmüştü ve kuram burada tekrarlanmaz. Bu dersin sorduğu tek soru şudur: bileşenler bir öznitelik olarak ne yapıyor — kaç bileşende ham özniteliklerin ayrılmış küme sayısına yetişiliyor ve karşılığında ne kaybediliyor.

  • OS22. Ham temsil on üç sütundur: M27/K01’in on bir sütunu, kisi_basi ve a_muhur. Ayrılmış kümedeki sayısı 0,8254’tür ve bu dersin karar öncesi çizgisidir.
  • OS23. Ölçek ve bileşen yönleri yalnız eğitim kümesinden öğrenilir, üç kümeye de aynı sayılarla uygulanır. Bütün kümeden öğrenilseydi ölçüm şişerdi.
  • OS24. Bileşenler ders içinde yazılır: standartlaştırılmış eğitim sütunlarının eşdeğişim dizeyi kurulur, en büyük yönü yineleme ile bulunur, bulunan yön dizeyden çıkarılır ve işlem on üç kez yinelenir. Kitaplık çağrılmaz.
  • OS25. Yineleme sayısı her bileşen için 200’dür; bu sayı sonuca bakılarak seçilmemiştir. Kalan büyüklüğü 101210^{-12}’nin altına düşerse yineleme erken durur.
  • OS26. Bileşen payı, bileşenin taşıdığı değişkenliğin toplam değişkenliğe oranıdır.
  • OS27. Bileşenler etiketi görmez. Sıralamaları değişkenliğe göredir, ayrım gücüne göre değildir.
  • OS28. Model değişmez: derinlik 6 karar ağacı. Taban çizgisi 0,7579’dur.
  • OS29. Yorumlanabilirlik ölçüsü, ağacın bölmelerinin hangi sütundan okunduğudur; her bölme böldüğü satır sayısıyla ağırlıklandırılır.

On Üç Sütun, On Üç Bileşen

# ORTAK — MODELDIR. M27/K01'in KURGU abone tablosu ayni tohumla yeniden uretilir;
# model derinlik 6 karar agacidir. Onceki dersten kalan tek yeni sutun kisi_basi.
import math

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 = {"no": k["no"], "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_ad": k["bolge"][0]}
    for b in BOLGE:
        x["b_" + b[0]] = int(k["bolge"][0] == b[0])
    VERI.append(x)

TEMEL = ["ort_tuketim", "oynaklik", "hane", "memnuniyet", "donem", "sifir_okuma",
         "b_kuzey", "b_guney", "b_dogu", "b_bati", "b_merkez"]
TABAN_ALAN = TEMEL + ["kisi_basi"]
for x in VERI:
    x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3)


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:]


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, alanlar, enaz=2):
    p, en = sum(x["supheli"] for x in s) / len(s), None
    if derinlik and len(s) >= 2 * enaz and 0.0 < p < 1.0:
        for a in alanlar:
            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, alanlar, enaz),
            "sag": agac(en[4], derinlik - 1, alanlar, 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 dogruluk(d, s):
    return sum(tahmin(d, x) == x["supheli"] for x in s) / len(s)


def taban(egt, s):
    c = int(sum(x["supheli"] for x in egt) * 2 > len(egt))
    return sum(x["supheli"] == c for x in s) / len(s)


def olc(alanlar, derinlik=6):
    m = agac(EGT, derinlik, alanlar)
    return dogruluk(m, EGT), dogruluk(m, SIN)

Bileşenleri bulmak için üç adım gerekir: sütunları ortak bir ölçeğe getirmek, eşdeğişim dizeyini kurmak ve en büyük değişkenliği taşıyan yönü bulup dizeyden çıkarmak. Üçüncü adım on üç kez yinelenince on üç bileşen çıkar. Ölçek ve yönlerin hepsi yalnız eğitim kümesinden okunur.

for x in VERI:
    r = uretec(TOHUM + 61000 + x["no"])
    r(), r()
    x["a_muhur"] = int(r() < (0.42 if x["supheli"] else 0.10))
HAM_ALAN = TABAN_ALAN + ["a_muhur"]

ORT = {a: sum(x[a] for x in EGT) / len(EGT) for a in HAM_ALAN}
SAC = {a: max(1e-9, (sum((x[a] - ORT[a]) ** 2 for x in EGT) / len(EGT)) ** 0.5)
       for a in HAM_ALAN}
for x in VERI:
    x["_z"] = [(x[a] - ORT[a]) / SAC[a] for a in HAM_ALAN]

n = len(HAM_ALAN)
C = [[sum(x["_z"][i] * x["_z"][j] for x in EGT) / len(EGT) for j in range(n)]
     for i in range(n)]


def carp(m, v):
    return [sum(m[i][j] * v[j] for j in range(len(v))) for i in range(len(m))]


BILESEN, PAY = [], []
A = [satir[:] for satir in C]
for _ in range(n):
    v = [1.0 / (i + 1) for i in range(n)]
    for _ in range(200):
        w = carp(A, v)
        u = sum(q * q for q in w) ** 0.5
        if u < 1e-12:
            break
        v = [q / u for q in w]
    lam = sum(v[i] * carp(A, v)[i] for i in range(n))
    BILESEN.append(v)
    PAY.append(max(0.0, lam))
    A = [[A[i][j] - lam * v[i] * v[j] for j in range(n)] for i in range(n)]

TOP = sum(PAY)
for x in VERI:
    for i, v in enumerate(BILESEN):
        x["c" + str(i)] = round(sum(x["_z"][j] * v[j] for j in range(n)), 4)

HAM = olc(HAM_ALAN)
print(f"{'temsil':<22} {'sutun':>5} {'pay':>7} {'egitimde':>9} {'ayrilmis':>9} {'fark':>8}")
print(f"{'ham oznitelikler':<22} {n:>5} {'':>7} {HAM[0]:>9.4f} {HAM[1]:>9.4f}")
for k in (1, 2, 3, 5, 8, 11, 13):
    e, s = olc(["c" + str(i) for i in range(k)])
    print(f"{'bilesen ' + str(k):<22} {k:>5} {sum(PAY[:k]) / TOP:>7.3f} {e:>9.4f} "
          f"{s:>9.4f} {s - HAM[1]:>+8.4f}")
print(f"\ntaban cizgisi {taban(EGT, SIN):.4f}")
temsil                 sutun     pay  egitimde  ayrilmis     fark
ham oznitelikler          13            0.8876    0.8254
bilesen 1                  1   0.177    0.8003    0.7381  -0.0873
bilesen 2                  2   0.323    0.8651    0.8175  -0.0079
bilesen 3                  3   0.432    0.8677    0.8056  -0.0198
bilesen 5                  5   0.630    0.9074    0.7778  -0.0476
bilesen 8                  8   0.877    0.9074    0.7460  -0.0794
bilesen 11                11   0.990    0.8995    0.7817  -0.0437
bilesen 13                13   1.000    0.9048    0.7897  -0.0357

taban cizgisi 0.7579

Sorunun ilk yarısının yanıtı tablodadır: hiçbir bileşen sayısında ham özniteliklere yetişilemiyor. En yakın satır iki bileşendir; 0,8175 ile ham temsilin 0,0079 altında, yani iki abone. On üç sütun iki sütuna indirilmiş ve iki abone kaybedilmiştir. Bu, bir sıkıştırma kararı olarak savunulabilir bir dengedir.

Tablonun asıl bulgusu bundan sonra geliyor. Bileşen sayısı arttıkça sayı iyileşmiyor: üç bileşende 0,8056, beşte 0,7778, sekizde 0,7460. Bileşen payı ise düzenli olarak büyüyor — 0,323’ten 0,877’ye. İki sütun aynı yöne gitmiyor. On üç bileşenin hepsi kullanıldığında bilgi kaybı yoktur, temsil ham temsilin döndürülmüş hâlidir ve yine de sayı 0,7897’de kalıyor; fark 0,0357. Karar ağacı bölmelerini eksenlere dik yapar ve döndürülmüş bir eksende aynı ayrımı kurmak için daha çok bölme gerekir. Bileşen temsili modelden bağımsız değildir.

Pay Sıralaması Ayrım Sıralaması Değildir

Bileşenler etiketi hiç görmez; sıralamaları yalnız hangi yönde daha çok değişkenlik olduğuna bakar. Etiketin o yönlerde durup durmadığı ayrı bir sorudur ve ölçülmesi gerekir.

def kullanim(d, s):
    say = {}

    def gez(d, s):
        if "tahmin" in d:
            return
        say[d["alan"]] = say.get(d["alan"], 0) + len(s)
        gez(d["sol"], [x for x in s if x[d["alan"]] < d["esik"]])
        gez(d["sag"], [x for x in s if x[d["alan"]] >= d["esik"]])
    gez(d, s)
    t = sum(say.values())
    return ", ".join(f"{a} {say[a] / t:.2f}"
                     for _, a in sorted((-say[a], a) for a in say)[:4])


print("ham temsilde en cok bolunen:", kullanim(agac(EGT, 6, HAM_ALAN), EGT))
print("bilesen temsilinde        :",
      kullanim(agac(EGT, 6, ["c" + str(i) for i in range(13)]), EGT))
for i in (0, 1):
    y = sorted(((-abs(BILESEN[i][j]), HAM_ALAN[j], BILESEN[i][j]) for j in range(n)))
    print(f"c{i} yukleri (pay {PAY[i] / TOP:.3f}): " +
          ", ".join(f"{a} {w:+.2f}" for _, a, w in y[:4]) +
          f", ... kalan {n - 4} sutunun toplam agirligi "
          f"{sum(abs(w) for _, _, w in y[4:]):.2f}")
print()
print(f"{'tek bilesen':<14} {'pay':>7} {'egitimde':>9} {'ayrilmis':>9}")
for i in range(5):
    e, s = olc(["c" + str(i)])
    print(f"{'c' + str(i):<14} {PAY[i] / TOP:>7.3f} {e:>9.4f} {s:>9.4f}")
ham temsilde en cok bolunen: ort_tuketim 0.35, oynaklik 0.19, a_muhur 0.17, kisi_basi 0.14
bilesen temsilinde        : c0 0.29, c1 0.25, c8 0.12, c2 0.11
c0 yukleri (pay 0.177): kisi_basi +0.54, ort_tuketim +0.53, b_bati -0.34, b_dogu +0.30, ... kalan 9 sutunun toplam agirligi 1.16
c1 yukleri (pay 0.146): oynaklik +0.62, sifir_okuma +0.51, donem +0.42, a_muhur +0.29, ... kalan 9 sutunun toplam agirligi 0.86

tek bilesen        pay  egitimde  ayrilmis
c0               0.177    0.8003    0.7381
c1               0.146    0.8267    0.7421
c2               0.109    0.8188    0.7579
c3               0.105    0.7937    0.7579
c4               0.093    0.8148    0.7659

Son tablo pay sıralamasının ayrım sıralaması olmadığını sayıyla gösteriyor. Payı en büyük bileşen c0, tek başına 0,7381 veriyor — taban çizgisinin 0,0198 altında. Payı yarısı kadar olan c4 ise 0,7659 veriyor ve tabanın üstünde kalıyor. “En çok değişkenliği taşıyan yön” ile “en çok ayıran yön” iki ayrı şeydir, ve bileşenler yalnız birincisine göre sıralandığı için ilk k bileşeni almak ayrım açısından keyfi bir kesmedir.

İki bileşenin birlikte 0,8175 vermesi de buradan anlaşılıyor: c0 tüketim büyüklüğünü, c1 ise oynaklık ile sıfır okumayı taşıyor. Etiketin iki ayrı nedeni iki ayrı bileşene düşmüş durumda ve model ikisini birleştirebiliyor.

Yorumlanabilirlikten Kaybedilen

Kaybın ikinci yarısı sayıda değil, adlarda. Ham temsilde bölmelerin 0,35’i ort_tuketim‘den, 0,19’u oynaklik‘tan, 0,17’si mühür göstergesinden okunuyor. Bu üç satır bir saha ekibine verilebilir: yüksek tüketim, oynak okuma ve mühür kaydı. Bileşen temsilinde aynı liste c0 0,29, c1 0,25, c8 0,12 diye çıkıyor ve hiçbir şey söylemiyor.

Bileşenin ne olduğu ancak yükleri okunarak anlaşılır ve yükler tek bir sütuna işaret etmez. c0 kişi başı tüketim ile ortalama tüketimi ağırlıklı olarak taşıyor, ama geri kalan dokuz sütunun toplam ağırlığı 1,16 — yani bileşenin yarıdan fazlası, dört büyük yükün dışındaki sütunlardan geliyor. “Bu abone niçin şüpheli işaretlendi” sorusunun yanıtı ham temsilde bir sütun adı ve bir eşiktir; bileşen temsilinde on üç sayının ağırlıklı toplamıdır.

Karar, iki kaybın karşılaştırılmasıdır. İki bileşene inmek 0,0079 sayı ve on bir sütunluk saklama kazandırır; karşılığında modelin verdiği her kararın gerekçesini bir tabloya yazma olanağı kaybedilir. Kaçak şüphesi gibi bir alanda ikinci kayıp genellikle daha pahalıdır, çünkü bir aboneye yapılan işlemin gerekçesi sorulabilir. Bileşen temsilinin öznitelik rolü bu yüzden dar bir roldür: sütun sayısı gerçekten yönetilemeyecek kadar büyükse ya da sütunlar birbirinin kopyasıysa değerlidir, tek tek ölçülmüş on üç sütun varken değildir.

Özet

  • Ham on üç sütun ayrılmış kümede 0,8254 veriyor; hiçbir bileşen sayısı buna yetişemiyor, en yakın satır iki bileşenle 0,8175 (fark 0,0079, iki abone).
  • Bileşen payı büyürken ayrılmış küme sayısı büyümüyor: üç bileşende 0,8056, beşte 0,7778, sekizde 0,7460; on üç bileşende bilgi kaybı yokken sayı yine 0,7897’de kalıyor.
  • Payı en büyük bileşen tek başına 0,7381 ile tabanın altında kalırken payı 0,093 olan beşinci bileşen 0,7659 veriyor; pay sıralaması ayrım sıralaması değildir.
  • Yorumlanabilirlik ölçülebilir bir kayıptır: ham temsilde bölmelerin 0,35’i ortalama tüketimden okunuyor, bileşen temsilinde aynı pay adı olmayan bir karışıma düşüyor.
  • Ölçek ve bileşen yönleri yalnız eğitim kümesinden öğrenilir; bütün kümeden öğrenilseydi ölçüm şişerdi.

Sonraki Adım

Dört derste hazırlama adımlarının sayısı arttı ve her birinde aynı cümle tekrarlandı: bu adım yalnız eğitim kümesinden öğrenilir. Ölçek ortalaması, bölge ortancası, seçilen sütun kümesi, bileşen yönleri — dördü de eğitilmiş nesnelerdir ve dördü de elle, ayrı ayrı, doğru sırayla uygulanmak zorundadır. Bu zincir elle uygulandığında kaç adımın yanlış kümeden öğrenildiğini saymak gerekir. Sonraki ders hazırlama ile modeli tek bir nesnede birleştirir ve boru hattı olmadan kaç adımın sızdığını ölçer.

İ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