İçeriğe geç
academia.sh

Ders 07 / 12

Öznitelik Üretme

Var olan sütunlardan yeni sütun çıkarmanın ayrılmış kümede ne kattığının tek tek sayılması: oran özniteliği 0,7778 olan sınama sayısını 0,7897'ye taşırken fark ve eğitimden öğrenilmiş gösterge 0,0040 katıyor, elle konan 25 m³ eşiği 0,0159 ve iki sütunun çarpımı 0,0238 kaybettiriyor, 40 m³ eşiği ise tam sıfır katkı üretiyor. Altı sütun birikimli olarak eklendiğinde eğitim sayısı 0,8466'dan 0,8677'ye çıkarken ayrılmış küme sayısı 0,7897'de tepe yapıp 0,7698'e düşüyor; tek tek pozitif katkı veren üç sütun birlikte eklendiğinde toplam katkı 0,0000 oluyor.

İçindekiler

Önceki altı ders var olan sütunlar üzerinde çalıştı: eksik değer dolduruldu, ölçek yalnız eğitim kümesinden öğrenildi, kategoriler kodlandı, dengesizlik ele alındı, aykırı değerler modele göre değerlendirildi. Hepsinde sütun kümesi aynı kaldı. Hiç yeni sütun üretilmedi ve hiçbir sütun atılmadı; model her derste aynı on bir sayıya baktı.

Bu ders sütun sayısını ilk kez artırır. Sorusu şudur: var olan sütunlardan aritmetikle çıkarılan yeni bir sayı, modele bilgi mi ekler yoksa yalnız arama alanı mı genişletir. Kursun kuralı burada da geçerlidir — bir hazırlama adımı ayrılmış kümede ölçülen katkısı kadar vardır — ve bu derste altı öznitelik tek tek üretilip tek tek ölçülür. Katkısı sıfır ve eksi çıkanlar da tabloya yazılır.

  • OS1. Küme M27/K01’in kurgu abone tablosudur: aynı tohum (20260218), aynı bölme (756 eğitim, 252 doğrulama, 252 sınama), aynı etiket. Ayrılmış küme sınama kümesidir.
  • OS2. Model kurs boyunca sabit tutulur: derinlik 6 karar ağacı. Değişen tek şey sütun kümesidir. Taban çizgisi en sık sınıfı söylemektir ve sınama kümesinde 0,7579’dur.
  • OS3. Karar öncesi çizgi, hazırlama adımlarının bıraktığı on bir sütunun çizgisidir: eğitimde 0,8466, sınamada 0,7778.
  • OS4. Ham okumalar hâlâ elde tutulur. ort_tuketim ve oynaklik bu okumaların bir özetidir ve o özetleme kendisi bir öznitelik üretme kararıydı; ders bu kararı geri açar.
  • OS5. Satır düzeyinde hesaplanan öznitelikler (oran, fark, çarpım, sabit eşik) kümeden hiçbir şey öğrenmez ve bölmeden bağımsızdır.
  • OS6. Kümeden bir sayı öğrenen öznitelik — bölge ortancasının üstünde olmak — o sayıyı yalnız eğitim kümesinden okur ve üç kümeye de aynı sayıyla uygulanır.
  • OS7. Katkı, aynı modelin ayrılmış kümedeki sayısının karar öncesi çizgiden farkıdır. 252 satırlık kümede bir satır 0,0040’a karşılık gelir.

Aynı Sütunlardan Altı Yeni Sayı

Kurulum M27/K01’inkiyle aynıdır ve aynı tohumla aynı kümeyi üretir. Bu kez ham okuma listesi de saklanır, çünkü üretilecek özniteliklerden biri ona dayanır.

# uretme.py — MODELDIR. M27/K01'in KURGU abone tablosu ayni tohumla yeniden uretilir;
# model derinlik 6 karar agacidir ve kurs boyunca sabit kalir.
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),
         "okuma": [round(q, 2) for q in v], "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"]


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)

Üretilecek altı öznitelik beş türü temsil eder. Oran, iki sütunun bölümüdür: kişi başına düşen tüketim, hanenin büyüklüğünü tüketimden ayırır. Fark, ham okumaların sonuncusu ile ilki arasındaki değişimdir; oynaklik yalnız açıklığı taşır, yönü taşımaz. Etkileşim özniteliği (interaction feature) iki sütunun çarpımıdır. Eşik göstergesi alan bilgisinden gelir: tarife basamakları 25 ve 40 m³’te durur. Sonuncusu kümeden bir sayı öğrenir — abonenin kendi bölgesindeki ortancanın üstünde olup olmadığı — ve o ortanca yalnız eğitim kümesinden okunur.

for x in VERI:
    o = x["okuma"]
    x["kisi_basi"] = round(x["ort_tuketim"] / x["hane"], 3)
    x["son_ilk_fark"] = round(o[-1] - o[0], 2)
    x["hane_memnuniyet"] = x["hane"] * x["memnuniyet"]
    x["esik_25"] = int(x["ort_tuketim"] > 25)
    x["esik_40"] = int(x["ort_tuketim"] > 40)

ORTANCA = {}
for b in BOLGE:
    v = sorted(x["ort_tuketim"] for x in EGT if x["bolge_ad"] == b[0])
    ORTANCA[b[0]] = v[len(v) // 2]
for x in VERI:
    x["bolge_ustu"] = int(x["ort_tuketim"] > ORTANCA[x["bolge_ad"]])

ONCE = olc(TEMEL)
YENI = ["kisi_basi", "son_ilk_fark", "bolge_ustu", "esik_25", "hane_memnuniyet",
        "esik_40"]
print(f"{'oznitelik':<18} {'tur':<12} {'egitimde':>9} {'ayrilmis':>9} {'katki':>8}")
print(f"{'-- yok --':<18} {'11 sutun':<12} {ONCE[0]:>9.4f} {ONCE[1]:>9.4f}")
for a, t in zip(YENI, ["oran", "fark", "ogrenilmis", "esik", "etkilesim", "esik"]):
    e, s = olc(TEMEL + [a])
    print(f"{a:<18} {t:<12} {e:>9.4f} {s:>9.4f} {s - ONCE[1]:>+8.4f}")
print(f"\ntaban cizgisi {taban(EGT, SIN):.4f}; 25 m3 ustu {sum(x['esik_25'] for x in VERI)} "
      f"satir, 40 m3 ustu {sum(x['esik_40'] for x in VERI)} satir")
oznitelik          tur           egitimde  ayrilmis    katki
-- yok --          11 sutun        0.8466    0.7778
kisi_basi          oran            0.8519    0.7897  +0.0119
son_ilk_fark       fark            0.8571    0.7817  +0.0040
bolge_ustu         ogrenilmis      0.8492    0.7817  +0.0040
esik_25            esik            0.8479    0.7619  -0.0159
hane_memnuniyet    etkilesim       0.8492    0.7540  -0.0238
esik_40            esik            0.8466    0.7778  +0.0000

taban cizgisi 0.7579; 25 m3 ustu 243 satir, 40 m3 ustu 2 satir

Katkı sütununda üç işaret birden var. En büyük kazanç oran özniteliğinden geliyor: 0,0119, yani 252 satırlık kümede üç abone. Bu, aritmetik olarak yeni bilgi taşımayan bir sütundur — ort_tuketim ve hane zaten kümededir — ama ağaç bölmelerini tek sütun üzerinde yapar ve iki sütunun bölümünü bir bölmeyle kuramaz. Oranın kattığı şey bilgi değil, o bilginin bölünebilir biçimidir.

Fark özniteliği ile eğitimden öğrenilmiş gösterge birer satır kazandırıyor: 0,0040. Bu, tek bir abonenin doğru sınıflanmasıdır ve rastlantıdan ayırt edilemeyecek kadar küçüktür. Böyle bir sayı “katkı vardır” diye raporlanamaz; en fazla “ölçüldü ve sıfırdan ayrılamadı” diye raporlanır.

Bu iki sütun arasında bir tür farkı var ve kursun ikinci kuralı tam oradan geçiyor. son_ilk_fark her satırda kendi içinde hesaplanır; kümedeki başka hiçbir satırı görmez, bölmeden önce de sonra da aynı sayıyı verir. bolge_ustu ise bir sayıya — bölge ortancasına — dayanır ve o sayı veriden okunur. Kodda bu ayrım tek satırda duruyor: ortanca sözlüğü EGT üzerinde kuruluyor, VERI üzerinde değil. Kaynak VERI yapılsaydı sütunun değerleri hiç değişmezdi, sınama kümesindeki 252 satır kendi eşiklerinin belirlenmesine katkıda bulunmuş olurdu ve ölçülen katkının bir payı öğrenmeden değil sızıntıdan gelirdi. Üretilen öznitelik de öğrenilmiş bir nesnedir ve öğrendiği yeri yazmak, kattığı sayıyı yazmak kadar zorunludur. Bu ayrım beşinci derste boru hattının kurucu ilkesi olacak.

Sıfırın İki Ayrı Nedeni

Tablonun en öğretici satırı 40 m³ eşiğidir: katkı tam sıfır, eğitim sayısı bile kılpayı değişmemiş. Nedeni son satırda görünüyor — kümede 40 m³’ün üstünde yalnız 2 satır var. Sabite yakın bir sütun hiçbir bölmede en az iki satırlık iki yan üretemez, dolayısıyla ağaç onu hiç seçmez. Sütun eklenmiştir, ölçülmüştür, ve modelin gördüğü ağaç birebir aynıdır.

25 m³ eşiği farklı bir sıfır türüdür ve aslında sıfır bile değil, eksidir: 0,0159 kayıp, dört abone. Bu sütun 243 satırı ayırıyor, yani sabit değil. Ama taşıdığı bilgi ort_tuketim’in içinde zaten var ve ağaç kendi eşiğini veriden arayarak buluyor. Elle konan eşik yeni bir şey söylemiyor, buna karşılık her düğümde bir bölme adayı olarak yarışıyor; eğitim kümesinde biraz daha iyi görünen bir bölme seçtirip ayrılmış kümede daha kötü bir ağaç üretiyor.

En büyük kayıp etkileşim özniteliğinden: 0,0238, altı abone. hane ile memnuniyetin çarpımı iki sütunu tek sayıya sıkıştırıyor ve etiketle ilişkisi bu iki sütunun kendisinden zayıf. Ağaç çarpımı seçtiğinde ayrımı daha kaba yapıyor. Alan bilgisinden gelmeyen, “olur da tutar” diye üretilen etkileşimlerin tipik davranışı budur.

Üç ayrı sıfır-ya-altı nedeni birbirinden ayrılmalıdır: sütun hiç bölünemiyor (40 m³), bilgisi zaten var (25 m³), ya da bilgiyi bozarak taşıyor (çarpım). Üçü de “katkısı yok” diye özetlenirse tabloda kaybolan şey, hangi düzeltmenin işe yarayacağıdır.

Katkılar Toplanmaz

Tek tek ölçülen katkılar üç pozitif değer verdi: 0,0119, 0,0040, 0,0040. Toplamları 0,0199 eder. Sütunlar birikimli olarak eklendiğinde ne olduğuna bakmak gerekir.

birikim = list(TEMEL)
print(f"{'eklenen':<18} {'sutun':>6} {'egitimde':>9} {'ayrilmis':>9} {'katki':>8}")
for a in YENI:
    birikim.append(a)
    e, s = olc(birikim)
    print(f"{a:<18} {len(birikim):>6} {e:>9.4f} {s:>9.4f} {s - ONCE[1]:>+8.4f}")
UC = ["kisi_basi", "son_ilk_fark", "bolge_ustu"]
e, s = olc(TEMEL + UC[:2])
print(f"\nyalniz iki katkili sutun {e:.4f} {s:.4f} {s - ONCE[1]:+.4f}")
e, s = olc(TEMEL + UC)
print(f"yalniz uc katkili sutun  {e:.4f} {s:.4f} {s - ONCE[1]:+.4f}")
eklenen             sutun  egitimde  ayrilmis    katki
kisi_basi              12    0.8519    0.7897  +0.0119
son_ilk_fark           13    0.8598    0.7897  +0.0119
bolge_ustu             14    0.8611    0.7778  +0.0000
esik_25                15    0.8664    0.7698  -0.0079
hane_memnuniyet        16    0.8677    0.7698  -0.0079
esik_40                17    0.8677    0.7698  -0.0079

yalniz iki katkili sutun 0.8598 0.7897 +0.0119
yalniz uc katkili sutun  0.8611 0.7778 +0.0000

İki sütun birbirinden bağımsız olsaydı katkıları toplanırdı. Toplanmıyor. Tek tek 0,0119 ve 0,0040 katan iki sütun birlikte 0,0119 katıyor; üçüncüsü eklendiğinde toplam katkı 0,0000’a iniyor. Tek tek pozitif ölçülen üç öznitelik, birlikte karar öncesi çizgiye geri dönüyor.

Nedeni ağacın açgözlü olmasıdır: her düğümde o an en iyi görünen bölmeyi seçer ve seçim geri alınmaz. Yeni bir sütun, kök düğümde daha iyi görünen bir bölme sunup ağacın geri kalanını tümüyle başka bir yola sokabilir. Katkı, sütunun kendi bilgisi değil, sütunun modelin arama yoluna yaptığı etkidir ve bu etki toplanabilir bir büyüklük değildir.

İki sütun ayrı ayrı okunmalıdır. Eğitim sayısı boyunca tek yönde artıyor: 0,8466’dan 0,8677’ye, altı sütunun her biri onu biraz daha yukarı çekiyor. Ayrılmış küme sayısı ise on iki sütunda tepe yapıp düşüyor ve on yedi sütunda karar öncesi çizginin altında kalıyor. M27/K01’in ikinci dersi bu ayrışmayı kapasiteyi artırarak üretmişti; burada model sabit, artan tek şey sütun sayısı. Öznitelik eklemek de kapasite artırmaktır.

Kursun kuralı bu tabloda somutlaşıyor. Altı sütun üretildi, altısı da makul bir gerekçeyle üretildi, ve ayrılmış kümede ölçüldüğünde geriye tek bir tanesi kaldı. Ölçülmeseydi altısı da kümede kalırdı ve model on yedi sütunla 0,7698’de, karar öncesi çizginin 0,0080 altında çalışırdı — üstelik eğitim sayısı 0,8677’ye çıktığı için tablo daha iyi görünürdü.

Özet

  • Oran özniteliği ayrılmış küme sayısını 0,7778’den 0,7897’ye taşıyor (0,0119, üç abone); fark özniteliği ve eğitimden öğrenilmiş bölge göstergesi 0,0040 katıyor, yani birer abone.
  • Katkısı sıfır ve eksi çıkanlar da yazılır: 40 m³ eşiği tam 0,0000, 25 m³ eşiği 0,0159 kayıp, iki sütunun çarpımı 0,0238 kayıp.
  • Sıfırın nedeni ayrıştırılır: sütun sabite yakın olduğu için bölünemiyor, bilgisi başka sütunda zaten var, ya da bilgiyi bozarak taşıyor.
  • Katkılar toplanmaz: tek tek 0,0119, 0,0040 ve 0,0040 katan üç sütun birlikte 0,0000 katıyor, çünkü katkı sütunun bilgisi değil modelin arama yoluna etkisidir.
  • Sütun sayısı 11’den 17’ye çıkarken eğitim sayısı 0,8466’dan 0,8677’ye tek yönde artıyor, ayrılmış küme sayısı 0,7897’de tepe yapıp 0,7698’e düşüyor; öznitelik eklemek de kapasite artırmaktır.

Sonraki Adım

Bu dersin altı özniteliği sayısal sütunlardan aritmetikle çıkarıldı. Abone tablosunda ise sayısal olmayan iki alan daha var: sözleşmenin başladığı tarih ve saha ekibinin bıraktığı kısa not. İkisi de olduğu gibi bir modele verilemez; ikisinden de birden çok sayı çıkarılabilir. Bir tarihten kaç sayı çıkar, kısa bir metinden kaç sayı çıkar ve bu sayıların toplam katkısı ne olur — sonraki ders bunu ö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