İçeriğe geç
academia.sh

Ders 15 / 20

Eşik Seçimi ve Eğriler

Eşiğin oynattığı iki sayının ve eğri altındaki alanın ayrılması: eşik 0,10'dan 0,90'a çıkarken kesinlik 0,3608'den 1,0000'e yükselir, duyarlılık 0,9344'ten 0,0328'e iner ve bedel 182'den 356'ya çıkar. Doksan dokuz eşik adayı arasından doğrulama kümesiyle seçilen 0,16 sınama kümesinde 181 bedel verir, varsayılan 0,50 eşiğinden 86 birim ucuzdur ve sınamadan okunsaydı 7 birim daha iyi görünürdü. Şüpheli oranı 0,2421'den 0,0354'e indirilince işlem karakteristiği eğrisinin altındaki alan 0,8058'den 0,8624'e çıkarken kesinlik–duyarlılık eğrisininki 0,6212'den 0,4124'e iner.

İçindekiler

Önceki dersin dört ölçütü de karar eşiği 0,5’te okundu. O eşik modelden gelmez: model bir olasılık üretir, eşik o olasılığı bir karara çevirir ve dışarıdan verilir. Sıfır virgül beşin tek gerekçesi iki sınıfın ortasında durmasıdır; şüpheli oranı 0,2421 olan bir kümede bu ortanın niçin doğru yer olduğunu söyleyen bir şey yoktur.

Bu ders eşiği süpürür: aynı model, aynı sınama kümesi, tek değişen eşik. Kesinlik ile duyarlılık her eşikte yeniden hesaplanır, işletme noktası bir bedel hesabıyla seçilir, süpürmenin ürettiği iki eğri sayı olarak basılır.

  • MD16. Model bir olasılık üretir; eşik bu olasılığı karara çevirir ve modelden bağımsızdır. Doksan dokuz eşik denenir, 0,01’den 0,99’a; bu dersin ayar bütçesi budur.
  • MD17. Bedel ilk dersinkidir: işaretlenen her abone için 1 birim saha ziyareti, kaçırılan her şüpheli için 6 birim. İşletme noktası doğrulama kümesinden seçilir; sınama kümesindeki sayı yalnız raporlanır.
  • MD18. Süpürme boyunca eğitim kümesi, öznitelikler ve model sabit kalır.
  • MD19. İşlem karakteristiği eğrisinin yatay ekseni yanlış olumlu oranı, dikey ekseni duyarlılıktır; kesinlik–duyarlılık eğrisinin yatay ekseni duyarlılık, dikey ekseni kesinliktir. Eğriler çizilmez, nokta olarak basılır.
  • MD20. Eğri altındaki alan yamuk kuralıyla hesaplanır ve eşit skorlu gözlemler tek nokta sayılır.
  • MD21. Seyreltilmiş küme sınama kümesindeki şüphelilerin onda birini tutarak kurulur; eğitim ve model değişmez. Kalan yedi şüpheliyle yapılan kestirim oynaktır ve tabanıyla okunur.
  • MD22. Eşik seçimi olasılığın doğru olmasını değil, yalnız sıralamanın doğru olmasını gerektirir.

Eşiği Süpürmek

Eşik yükseldikçe model daha az abone işaretler. İşaretlediklerinde daha çok haklı çıkar, ama kaçırdığı şüpheli sayısı büyü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):
    p = sum(x["supheli"] for x in s) / len(s)
    return 2 * p * (1 - p)


def agac(s, derinlik, alan, enaz=2):        # MODELDIR: karar agaci
    n = len(s)
    p = sum(x["supheli"] for x in s) / n
    en = None
    if derinlik and n >= 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) - (len(sol) * safsizlik(sol) + len(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 matris(skor, veri, esik=0.5):           # do, yo, yn, dn
    m = [0, 0, 0, 0]
    for x in veri:
        m[(0 if x["supheli"] else 1) + (0 if skor(x) >= esik else 2)] += 1
    return m


def dogrusal(egt, alan, w, tur=300, adim=0.5):   # MODELDIR: egim temelli dogrusal model
    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}
    f = lambda x: [(x[a] - o[a]) / s[a] for a in alan]
    k, b = [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


NS = sum(x["supheli"] for x in SIN)
S = dogrusal(EGT, ALAN, 1.0)        # MODELDIR: olasilik ureten egim temelli dogrusal model
ZIYARET, KACAK = 1.0, 6.0


def nokta(skor, veri, e):
    do, yo, yn, dn = matris(skor, veri, e)
    return {"isaretli": do + yo, "do": do, "yoo": yo / (yo + dn), "du": do / (do + yn),
            "k": do / (do + yo) if do + yo else float("nan"),
            "bedel": ZIYARET * (do + yo) + KACAK * yn}


print(f"{'esik':>5}{'isaretli':>9}{'yakalanan':>10}{'yo orani':>9}"
      f"{'duyarlilik':>11}{'kesinlik':>9}{'bedel':>7}")
for e in (0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90):
    n = nokta(S, SIN, e)
    print(f"{e:>5.2f}{n['isaretli']:>9}{n['do']:>10}{n['yoo']:>9.4f}"
          f"{n['du']:>11.4f}{n['k']:>9.4f}{n['bedel']:>7.0f}")
 esik isaretli yakalanan yo orani duyarlilik kesinlik  bedel
 0.10      158        57   0.5288     0.9344   0.3608    182
 0.20      100        45   0.2880     0.7377   0.4500    196
 0.30       66        34   0.1675     0.5574   0.5152    228
 0.40       47        29   0.0942     0.4754   0.6170    239
 0.50       33        22   0.0576     0.3607   0.6667    267
 0.60       24        18   0.0314     0.2951   0.7500    282
 0.70       17        12   0.0262     0.1967   0.7059    311
 0.80        8         8   0.0000     0.1311   1.0000    326
 0.90        2         2   0.0000     0.0328   1.0000    356

İki sütun ters yönde ilerliyor. Eşik 0,10’da model 158 abone işaretliyor, 61 şüphelinin 57’sini yakalıyor, kesinliği 0,3608. Eşik 0,90’da yalnız 2 abone işaretliyor, ikisinde de haklı, ama duyarlılık 0,0328. Kesinlik düzgün artmıyor: 0,60’ta 0,7500 iken 0,70’te 0,7059’a iniyor, çünkü paydası da modelle birlikte küçülüyor. Duyarlılık ise eşikte azalmayan bir işlevdir, paydası sabittir.

Son sütun kararı veren sütun: bedel 0,10 eşiğinde 182, 0,90 eşiğinde 356. Aradaki 174 birim tamamen eşiğin ürünüdür; model, öznitelikler ve eğitim kümesi hiç değişmedi.

İşletme Noktası Bir Bedel Hesabıyla Seçilir

Eşik bir ayar değişkenidir ve kursun kuralı burada da geçerlidir: hangi kümeden okunduğu yazılmadan seçilmiş sayılmaz.

ESIKLER = [i / 100 for i in range(1, 100)]
bd = min(ESIKLER, key=lambda e: nokta(S, DOG, e)["bedel"])
bs = min(ESIKLER, key=lambda e: nokta(S, SIN, e)["bedel"])
print(f"denenen esik adayi {len(ESIKLER)}, dogrulama kumesi {len(DOG)} abone")
print(f"{'isletme noktasi':<22}{'esik':>6}{'isaretli':>9}{'yakalanan':>10}"
      f"{'dogrulama':>11}{'sinama':>8}")
for ad, e in (("varsayilan", 0.50), ("dogrulamadan secilen", bd),
              ("sinamadan secilen", bs)):
    n = nokta(S, SIN, e)
    print(f"{ad:<22}{e:>6.2f}{n['isaretli']:>9}{n['do']:>10}"
          f"{nokta(S, DOG, e)['bedel']:>11.0f}{n['bedel']:>8.0f}")
denenen esik adayi 99, dogrulama kumesi 252 abone
isletme noktasi         esik isaretli yakalanan  dogrulama  sinama
varsayilan              0.50       33        22        205     267
dogrulamadan secilen    0.16      121        51        160     181
sinamadan secilen       0.13      138        55        173     174

Doğrulama kümesindeki doksan dokuz adayın en ucuzu 0,16 eşiğidir ve o kümede 160 birim tutar; aynı eşik sınama kümesinde 181 birim veriyor. Varsayılan 0,50 eşiği ise 267 birim: eşiği seçmek 86 birim, üçte bire yakın bir kazanç sağlıyor ve bu kazanç modelden değil, çıktısının nasıl okunduğundan geliyor.

Üçüncü satır seçimin kaynağını ölçüyor. Sınama kümesindeki en küçük bedel 0,13 eşiğinde, 174 birim. Aradaki 7 birim, seçimi sınama kümesinden okuyan birinin fazladan iyi görünen payıdır — küçük bir sayıdır çünkü bedel eğrisi eşiğe göre yayvandır, ama işareti hep aynı yöndedir.

İki Eğri ve Dengesizlik

Süpürme iki eğri üretir. İşlem karakteristiği eğrisi (ROC) yanlış olumlu oranına karşı duyarlılığı gösterir; kesinlik–duyarlılık eğrisi duyarlılığa karşı kesinliği. Farkları şüpheli oranı değiştiğinde ortaya çıkar.

def egri(skor, veri):               # ROC ve kesinlik-duyarlilik noktalari
    p = sorted(((skor(x), x["supheli"]) for x in veri), key=lambda t: -t[0])
    P = sum(y for _, y in p)
    N = len(p) - P
    do = yo = i = 0
    n = [(0.0, 0.0, 1.0)]
    while i < len(p):
        j = i
        while j < len(p) and p[j][0] == p[i][0]:
            j += 1
        d = sum(y for _, y in p[i:j])
        do, yo, i = do + d, yo + (j - i) - d, j
        n.append((yo / N, do / P, do / (do + yo)))
    return n


def alan_roc(n, sinir=1.0):         # yamuk kurali; sinir yanlis olumlu oranini kirpar
    return sum((min(b[0], sinir) - a[0]) * (a[1] + b[1]) / 2
               for a, b in zip(n, n[1:]) if a[0] < sinir) / sinir


def alan_kd(n):                     # duyarlilik ekseninde basamak toplami
    return sum((b[1] - a[1]) * b[2] for a, b in zip(n, n[1:]))


SEY = [x for i, x in enumerate(SIN) if not x["supheli"] or i % 10 == 0]
sabit = lambda x: 0.5
print(f"{'sinama kumesi':<15}{'satir':>6}{'supheli':>8}{'oran':>7}{'ROC':>8}{'KD':>8}"
      f"{'sabit ROC':>10}{'sabit KD':>9}")
for ad, v in (("gercek dagilim", SIN), ("seyreltilmis", SEY)):
    n, s, ns = egri(S, v), egri(sabit, v), sum(x["supheli"] for x in v)
    print(f"{ad:<15}{len(v):>6}{ns:>8}{ns / len(v):>7.4f}{alan_roc(n):>8.4f}"
          f"{alan_kd(n):>8.4f}{alan_roc(s):>10.4f}{alan_kd(s):>9.4f}")
for h in (0.50, 0.70):
    r = [nokta(S, v, max(e for e in ESIKLER if nokta(S, v, e)["du"] >= h))["k"]
         for v in (SIN, SEY)]
    print(f"duyarlilik {h:.2f} ustunde kesinlik: gercek dagilim {r[0]:.4f}, "
          f"seyreltilmis {r[1]:.4f}")
sinama kumesi   satir supheli   oran     ROC      KD sabit ROC sabit KD
gercek dagilim    252      61 0.2421  0.8058  0.6212    0.5000   0.2421
seyreltilmis      198       7 0.0354  0.8624  0.4124    0.5000   0.0354
duyarlilik 0.50 ustunde kesinlik: gercek dagilim 0.5161, seyreltilmis 0.2500
duyarlilik 0.70 ustunde kesinlik: gercek dagilim 0.4624, seyreltilmis 0.1667

İki eğri ters yönde hareket ediyor. Şüpheli oranı 0,2421’den 0,0354’e inince işlem karakteristiği eğrisinin altındaki alan 0,8058’den 0,8624’e çıkıyor, kesinlik–duyarlılık eğrisininki 0,6212’den 0,4124’e iniyor. Yükselişin bir bölümü yedi şüpheliyle yapılan kestirimin oynaklığıdır; asıl mesele son iki sütunda. Sabit skorlu yordamın işlem karakteristiği eğrisi her iki kümede de 0,5000 verir; bu eğrinin tabanı şüpheli oranına bakmaz. Öteki eğrinin tabanı ise doğrudan şüpheli oranıdır.

Son iki satır bunun işletmedeki karşılığı. Duyarlılık 0,50’nin üstünde tutulduğunda kesinlik gerçek dağılımda 0,5161, seyreltilmiş kümede 0,2500; 0,70’in üstünde tutulduğunda 0,4624’e karşı 0,1667. Alan 0,86 okurken, şüphelilerin yarısını yakalamak için işaretlenen her dört aboneden üçü boşa gidiyor. Dengesiz kümede yanıltıcı olan eğri, tabanı dengesizlikle birlikte hareket etmeyen eğridir.

Tek Sayının Sakladığı

Eğri altındaki alan bütün eşikleri tek sayıda toplar ve toplarken iki şeyi düşürür: hangi eşikte çalışıldığını ve eğrinin hangi bölgesinin işe yaradığını.

T3 = agac(EGT, 3, ALAN)                    # MODELDIR: derinlik 3 karar agaci
S1 = dogrusal(EGT, ["ort_tuketim"], 1.0)   # MODELDIR: tek oznitelikli dogrusal model
print(f"{'model':<22}{'ROC':>8}{'yo<0.10':>9}{'KD':>8}{'en iyi bedel':>14}"
      f"{'farkli skor':>12}")
for ad, s in (("dogrusal, 12 alan", S), ("agac d3, 12 alan", lambda x: olasilik(T3, x)),
              ("dogrusal, ort_tuketim", S1)):
    n = egri(s, SIN)
    print(f"{ad:<22}{alan_roc(n):>8.4f}{alan_roc(n, 0.10):>9.4f}{alan_kd(n):>8.4f}"
          f"{min(nokta(s, SIN, e)['bedel'] for e in ESIKLER):>14.0f}"
          f"{len({round(s(x), 12) for x in SIN}):>12}")
model                      ROC  yo<0.10      KD  en iyi bedel farkli skor
dogrusal, 12 alan       0.8058   0.3364  0.6212           174         252
agac d3, 12 alan        0.7222   0.2553  0.4485           197           8
dogrusal, ort_tuketim   0.7138   0.3008  0.5589           213         241

Asıl okuma son iki satırda. İki modelin işlem karakteristiği alanı 0,7222 ile 0,7138, arada 0,0084 var — bu ölçüye göre neredeyse eşitler. Öbür üç sütun aynı fikirde değil: kesinlik–duyarlılık alanında tek öznitelikli model 0,1104 puan önde, yanlış olumlu oranının 0,10 altında kaldığı bölgede 0,0455 puan önde, en iyi bedelde 16 birim geride. Üç okuma, üç ayrı kazanan.

Sekiz ayrı skor üreten derinlik 3 ağacı ile 241 ayrı skor üreten tek öznitelikli model eğri üzerinde bambaşka ilerler: biri sekiz büyük basamak, öteki yüzlerce küçük adım. Alan ikisini de aynı sayıya sıkıştırır. Kursun kuralına burada bir madde eklenir: hangi eşikte çalışılacağı yazılmadan eğri altındaki alan bir işletme kararına çevrilemez.

Özet

  • Eşik yükseldikçe duyarlılık azalmayan biçimde düşer ama kesinlik düzgün artmaz: 0,60 eşiğinde 0,7500 olan kesinlik 0,70 eşiğinde 0,7059’a iner. Doksan dokuz eşik adayı bedeli 182 ile 356 arasında oynatır; model ve eğitim kümesi hiç değişmez.
  • Doğrulamadan seçilen 0,16 eşiği sınamada 181 birim verir, varsayılan 0,50 eşiğinden 86 birim ucuzdur; aynı seçim sınamadan okunsaydı 7 birim daha iyi görünürdü.
  • Şüpheli oranı 0,2421’den 0,0354’e inince işlem karakteristiği alanı 0,8058’den 0,8624’e çıkar, kesinlik–duyarlılık alanı 0,6212’den 0,4124’e iner; birinci eğrinin tabanı her iki kümede 0,5000, ikincisininki şüpheli oranının kendisidir.
  • İşlem karakteristiği alanı 0,0084 farkla eşit sayılan iki model, kesinlik–duyarlılık alanında 0,1104 ve en iyi bedelde 16 birim ayrışır.

Sonraki Adım

Bu dersin tamamı sıralamaya dayandı. Eşik süpürüldü, eğriler basıldı, işletme noktası seçildi; hiçbirinde modelin söylediği sayının kendisinin doğru olması gerekmedi. Bütün skorlar artan bir işlevden geçirilse sıralama değişmez, iki eğri aynı kalır, işletme noktası aynı aboneleri işaretler. Oysa model bir abone için 0,80 dediğinde bu sayının bir karşılığı olmalıdır: 0,80 denen abonelerin yaklaşık yüzde sekseni şüpheli çıkmalıdır. Sonraki ders söylenen olasılık ile gerçekleşen oranı aralık aralık yan yana basar, sıralaması iyi kalibrasyonu kötü bir modelin varlığını gösterir ve düzeltmeyi yalnız doğrulama kümesinden öğrenilen tek değişkenli bir eşleme olarak yazar.

İ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