İçeriğe geç
academia.sh

Ders 13 / 20

Karışıklık Matrisi

Aynı doğruluğu veren iki modelin hata dağılımının ayrılması: kırk dokuz aday arasında on dört doğruluk değeri birden çok aday tarafından paylaşılır, 0,7817 veren iki aday 61 şüpheliden birinde 16'sını diğerinde 32'sini yakalar ve işaretlenen abone sayısı 26 ile 58 arasında değişir. Saha ziyareti 1, kaçırılan kaçak 6 birim sayıldığında bedel 296 ile 232 olur, taban çizgisinin bedeli 366'dır ve herkesi şüpheli demek 252 ile taban çizgisinden ucuzdur. Doğrulukta en iyi aday bedelde 263 verirken bedelde en iyi aday doğrulukta kırk dokuz aday içinde yirminci sıradadır.

İçindekiler

Önceki konu yedi model ailesini aynı ayrılmış küme üzerinde denedi ve her sayının yanına o sayıyı bulmak için kaç aday denendiğini yazdı. Karşılaştırmanın tamamı tek bir sayı üzerinden yürüdü: doğruluk. Ailenin kattığı fark da, ayar bütçesinin şişirdiği fark da bu tek sayıda okundu. O sayının hangi hataları sakladığı hiç sorulmadı.

Sınama kümesindeki 252 abonenin 61’i şüpheli. Doğruluğu 0,80 olan bir model elli abonede yanılıyor demektir, ama bu elli yanılgının yönü yazmıyor: şüpheli olmayana şüpheli demek ile şüpheliyi gözden kaçırmak aynı hücreye düşüyor. İkisi birbirinin yerine geçmez — birinin bedeli boşa giden bir saha ziyareti, ötekinin bedeli fark edilmemiş bir kaçaktır.

  • MD1. Küme, bölme ve öznitelikler kurs boyunca sabittir: kurgu abone tablosu, 756/252/252 bölme, öznitelik mühendisliği kursunun bıraktığı on iki öznitelik. Değişen tek şey modeldir.
  • MD2. Taban çizgisi değişmez: eğitim kümesinin en sık sınıfını her aboneye söylemek. Bu yordam sınama kümesinde 0,7579 verir.
  • MD3. Olumlu sınıf şüpheli abonedir. Olumlu/olumsuz sözcükleri değer yargısı değil, sayılan sınıfın adıdır.
  • MD4. Model bir olasılık üretir ve bu derste karar eşiği 0,5’te sabittir. Eşiğin kendisi bu konunun üçüncü dersine bırakılır.
  • MD5. Kırk dokuz aday denenir: altı derinlik ile yedi sınıf ağırlığının çarpımı olarak kırk iki karar ağacı, yedi sınıf ağırlığında eğim temelli doğrusal model. Sınıf ağırlığı öznitelik mühendisliği kursundaki biçimiyle kullanılır.
  • MD6. Bu ders model seçmez; kırk dokuz adayın hepsinin sınama kümesindeki sayısı basılır. Doğrulama kümesinden seçim yapmak üçüncü dersin işidir.
  • MD7. Bedel iki kalemden oluşur: işaretlenen her abone için bir saha ziyareti, kaçırılan her şüpheli için bir kaçırılmış kaçak. Ziyaret bedeli işaretlenen bütün abonelere yazılır, ziyaretin sonucu bedeli değiştirmez. Birim değerleri kurgudur ve veriden okunmaz.

Dört Hücre

Karışıklık matrisi (confusion matrix) iki sınıflı bir kararda dört sayı tutar. Model şüpheli dediğinde abone gerçekten şüpheliyse doğru olumlu (true positive), değilse yanlış olumlu (false positive). Model şüpheli demediğinde abone şüpheliyse yanlış olumsuz (false negative), değilse doğru olumsuz (true negative). Doğruluk bu dört sayının ikisini toplayıp dörde böler; kalan bilgi atılır.

# 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):
    n = sum(x.get("w", 1.0) for x in s)
    p = sum(x.get("w", 1.0) * x["supheli"] for x in s) / n
    return 2 * p * (1 - p)


def agac(s, derinlik, alan, enaz=2):        # MODELDIR: agirlikli karar agaci
    n = sum(x.get("w", 1.0) for x in s)
    p = sum(x.get("w", 1.0) * x["supheli"] for x in s) / n
    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 = safsizlik(s) - (sum(x.get("w", 1.0) for x in sol) * safsizlik(sol)
                               + sum(x.get("w", 1.0) for x in 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 agirlikla(egt, w):
    return [dict(x, w=(w if x["supheli"] else 1.0)) for x in egt]


def matris(skor, veri, esik=0.5):           # do, yo, yn, dn
    m = [0, 0, 0, 0]
    for x in veri:
        i = (0 if x["supheli"] else 1) + (0 if skor(x) >= esik else 2)
        m[i] += 1
    return m


NS = sum(x["supheli"] for x in SIN)
print(f"sinama kumesi {len(SIN)} abone, supheli {NS}, "
      f"taban cizgisi {1 - NS / len(SIN):.4f}")
t6 = agac(EGT, 6, ALAN)
m6 = matris(lambda x: olasilik(t6, x), SIN)
print(f"derinlik 6 karar agaci: dogruluk {(m6[0] + m6[3]) / len(SIN):.4f}")
print(f"{'':>18}{'gercek supheli':>16}{'gercek degil':>14}")
print(f"{'supheli dendi':>18}{m6[0]:>16}{m6[1]:>14}")
print(f"{'supheli denmedi':>18}{m6[2]:>16}{m6[3]:>14}")
sinama kumesi 252 abone, supheli 61, taban cizgisi 0.7579
derinlik 6 karar agaci: dogruluk 0.7937
                    gercek supheli  gercek degil
     supheli dendi              24            15
   supheli denmedi              37           176

Doğruluk 0,7937 ve taban çizgisinin üstünde. Matris aynı modeli başka türlü okutuyor: model 61 şüphelinin 24’ünü yakalıyor, 37’sini kaçırıyor, 15 aboneyi de boşuna işaretliyor. Doğruluğun büyük bölümü sağ alt hücreden geliyor — kümede çoğunluk zaten onlar. Taban çizgisinin 0,7579’u tamamen o hücreden gelir: hiç kimseye şüpheli demeyen yordam 191 doğru olumsuz toplar ve 61 yanlış olumsuz biriktirir.

Aynı Sayı, Başka Matris

Doğruluğun bilgi attığı en açık biçimde iki modelin aynı sayıyı vermesiyle görülür. Kırk dokuz aday denenir ve aynı doğruluk değerini paylaşan adaylar aranır.

def olcek(egt, alan):
    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}
    return lambda x: [(x[a] - o[a]) / s[a] for a in alan]


def dogrusal(egt, alan, w, tur=300, adim=0.5):   # MODELDIR: egim temelli dogrusal model
    f, k, b = olcek(egt, alan), [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


ADAYLAR = {}
for d in (3, 4, 5, 6, 7, 8):
    for w in (1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0):
        t = agac(agirlikla(EGT, w), d, ALAN)
        ADAYLAR[f"agac d{d} a{w}"] = matris(lambda x, t=t: olasilik(t, x), SIN)
for w in (1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0):
    s = dogrusal(EGT, ALAN, w)
    ADAYLAR[f"dogrusal a{w}"] = matris(s, SIN)

ESIT = {}
for ad, m in ADAYLAR.items():
    ESIT.setdefault(round((m[0] + m[3]) / len(SIN), 4), []).append(ad)
paylasilan = {d: v for d, v in ESIT.items() if len(v) > 1}
print(f"denenen aday {len(ADAYLAR)}, farkli dogruluk degeri {len(ESIT)}, "
      f"birden cok aday tarafindan paylasilan {len(paylasilan)}")
en = max(paylasilan.items(),
         key=lambda kv: max(ADAYLAR[a][0] for a in kv[1]) - min(ADAYLAR[a][0] for a in kv[1]))
print(f"\n{'aday':<14}{'dogruluk':>9}{'do':>5}{'yo':>5}{'yn':>5}{'dn':>5}{'isaretli':>10}")
for d in sorted(paylasilan, reverse=True)[:3]:
    for ad in paylasilan[d]:
        m = ADAYLAR[ad]
        print(f"{ad:<14}{d:>9.4f}{m[0]:>5}{m[1]:>5}{m[2]:>5}{m[3]:>5}{m[0] + m[1]:>10}")
    print()
print(f"en genis ayrisma dogruluk {en[0]:.4f}: {' / '.join(en[1])}")
denenen aday 49, farkli dogruluk degeri 26, birden cok aday tarafindan paylasilan 14

aday           dogruluk   do   yo   yn   dn  isaretli
agac d5 a1.0     0.8016   23   12   38  179        35
dogrusal a1.0    0.8016   22   11   39  180        33
dogrusal a1.5    0.8016   29   18   32  173        47

agac d3 a1.0     0.7937   17    8   44  183        25
agac d6 a1.0     0.7937   24   15   37  176        39

agac d4 a1.0     0.7817   16   10   45  181        26
agac d8 a1.0     0.7817   32   26   29  165        58

en genis ayrisma dogruluk 0.7817: agac d4 a1.0 / agac d8 a1.0

Kırk dokuz aday yalnız yirmi altı ayrı doğruluk değeri üretiyor ve bunların on dördü birden çok aday tarafından paylaşılıyor. Tablonun ilk bloğu kümenin en yüksek doğruluğunu gösteriyor: 0,8016 değerini üç aday birden veriyor, üstelik iki ayrı model ailesinden. Yakaladıkları şüpheli sayısı 22, 23 ve 29; işaretledikleri abone sayısı 33, 35 ve 47. Doğrulukla bakan biri için üçü aynı modeldir.

Son blok ayrışmanın en genişi. Doğruluğu 0,7817 olan iki aday 61 şüpheliden birinde 16’sını, öbüründe 32’sini yakalıyor — tam iki katı — ve 26’ya karşı 58 abone işaretliyor. Toplam doğru sayısı 197’de eşitleniyor çünkü ikinci modelin kazandığı 16 doğru olumlu, kaybettiği 16 doğru olumsuzla tam takas oluyor. Doğruluk bu takasa kayıtsızdır; matris değildir.

İki Hatanın Bedeli Bir Değil

Takasın kayıtsız kalmadığı yer, iki hata türünün karşılığının sayıldığı yerdir. Kurgu kümede işaretlenen her abone için bir saha ziyareti yazılır, kaçırılan her şüpheli için bir kaçırılmış kaçak. Ziyaretin birimi 1, kaçırılan kaçağınki 6 alınır; bu iki sayı veriden okunmaz, dışarıdan verilir.

ZIYARET, KACAK = 1.0, 6.0


def bedel(m):
    return ZIYARET * (m[0] + m[1]) + KACAK * m[2]


print(f"{'yordam':<24}{'dogruluk':>9}{'ziyaret':>9}{'kacirilan':>11}{'bedel':>8}")
for ad, m in (("taban (hicbiri supheli)", [0, 0, NS, len(SIN) - NS]),
              ("herkes supheli", [NS, len(SIN) - NS, 0, 0]),
              ("agac d4 a1.0", ADAYLAR["agac d4 a1.0"]),
              ("agac d8 a1.0", ADAYLAR["agac d8 a1.0"]),
              ("agac d5 a1.0", ADAYLAR["agac d5 a1.0"]),
              ("dogrusal a1.5", ADAYLAR["dogrusal a1.5"])):
    print(f"{ad:<24}{(m[0] + m[3]) / len(SIN):>9.4f}{m[0] + m[1]:>9}"
          f"{m[2]:>11}{bedel(m):>8.0f}")

a, b = ADAYLAR["agac d4 a1.0"], ADAYLAR["agac d8 a1.0"]
oran = ((a[0] + a[1]) - (b[0] + b[1])) / (b[2] - a[2])
print(f"\nesit bedel orani {oran:.2f}: kacirilan bir kacagin bedeli bir saha "
      f"ziyaretinin {oran:.2f} katini gecince siralama doner")
en_d = max(ADAYLAR, key=lambda k: (ADAYLAR[k][0] + ADAYLAR[k][3]))
en_b = min(ADAYLAR, key=lambda k: bedel(ADAYLAR[k]))
print(f"dogrulukta en iyi aday {en_d}, bedeli {bedel(ADAYLAR[en_d]):.0f}")
print(f"bedelde en iyi aday   {en_b}, dogrulugu "
      f"{(ADAYLAR[en_b][0] + ADAYLAR[en_b][3]) / len(SIN):.4f}")
print(f"bedelde en iyi adayin dogruluk sirasi "
      f"{sorted(ADAYLAR, key=lambda k: -(ADAYLAR[k][0] + ADAYLAR[k][3])).index(en_b) + 1}"
      f" / {len(ADAYLAR)}")
yordam                   dogruluk  ziyaret  kacirilan   bedel
taban (hicbiri supheli)    0.7579        0         61     366
herkes supheli             0.2421      252          0     252
agac d4 a1.0               0.7817       26         45     296
agac d8 a1.0               0.7817       58         29     232
agac d5 a1.0               0.8016       35         38     263
dogrusal a1.5              0.8016       47         32     239

esit bedel orani 2.00: kacirilan bir kacagin bedeli bir saha ziyaretinin 2.00 katini gecince siralama doner
dogrulukta en iyi aday agac d5 a1.0, bedeli 263
bedelde en iyi aday   dogrusal a3.5, dogrulugu 0.7460
bedelde en iyi adayin dogruluk sirasi 20 / 49

Tablonun ikinci satırı doğruluğun tek yönlü bir ölçü olduğunu tek başına gösteriyor. Herkese şüpheli demek doğrulukta 0,2421 verir — kullanılamaz görünen bir sayı — ama bedelde 252 tutar ve taban çizgisinin 366’sından ucuzdur. İki yordam da hiçbir şey öğrenmemiştir; biri doğrulukta, öteki bedelde iyi görünür.

Aynı doğruluğu veren iki adayın bedeli 296 ile 232. Aradaki 64 birim, doğruluğun sakladığı takasın karşılığıdır. Eşit bedel oranı 2,00 çıkıyor: kaçırılan bir kaçağın bedeli bir saha ziyaretinin iki katının altındaysa az işaretleyen model, üstündeyse çok işaretleyen model ucuzdur. Bu oran veriden okunamaz, ölçüm ağının işletmecisinden gelir — aynı iki sayı, oranın 2’nin hangi tarafında olduğuna göre iki ayrı karar.

Son iki satır kırk dokuz adayın tamamına bakıyor. Doğrulukta en iyi aday bedelde 263 veriyor; bedelde en iyi aday doğruluk sıralamasında yirminci sırada. Bir ölçütte tepede olmak öteki ölçütte tepede olmayı getirmiyor ve fark rastlantı düzeyinde değil. Doğruluk, iki hatayı eşit sayan bir bedel hesabıdır; eşit saymayan her hesap başka bir aday seçer.

Özet

  • Karışıklık matrisi iki sınıflı kararı dört sayıya ayırır — doğru olumlu, yanlış olumlu, yanlış olumsuz, doğru olumsuz — ve doğruluk bu dördün ikisini toplayıp toplam gözlem sayısına böler.
  • Kırk dokuz aday yalnız yirmi altı ayrı doğruluk değeri üretir; on dört değer birden çok aday tarafından paylaşılır, yani aynı sayı çoğu zaman birden fazla hata dağılımına karşılık gelir.
  • Doğruluğu 0,7817 olan iki aday 61 şüpheliden 16’sını ve 32’sini yakalar, 26 ve 58 abone işaretler; kazanılan doğru olumlu sayısı kaybedilen doğru olumsuz sayısıyla tam takas olduğu için doğruluk aynı kalır.
  • Saha ziyareti 1, kaçırılan kaçak 6 birim sayıldığında bu iki adayın bedeli 296 ile 232 olur; sıralamanın döndüğü eşit bedel oranı 2,00’dir ve bu sayı veriden değil işletmeden gelir.
  • Herkese şüpheli demek doğrulukta 0,2421 ile taban çizgisinin çok altında kalırken bedelde 252 ile taban çizgisinin 366’sını geçer; doğrulukta en iyi aday ile bedelde en iyi aday aynı değildir.

Sonraki Adım

Bu ders dört hücreyi saydı ama hücrelerden türetilen ölçütleri adlandırmadı. Öznitelik mühendisliği kursunun dengesiz sınıflar dersi, doğru işaretlenen azınlık payına kesinlik, yakalanan azınlık payına duyarlılık dendiğini yazmış, ikisinin tanımını ve birbirine karşı okunmasını bu kursa bırakmıştı. Sonraki ders o sözü öder: dört hücreden dört ölçüt türetir, beş modeli bu ölçütlerde ayrı ayrı sıralar ve kaç ölçütte sıralamanın başının değiştiğini sayar. F1 ölçütünün niçin iki sayının ortalaması değil uyumlu ortalaması olduğu, ortalamanın hangi durumda yanıltıcı bir yüksek değer verdiği ile birlikte 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