İçeriğe geç
academia.sh

Ders 03 / 12

Veri ve Model Sürümleme

Aynı ada verilen iki farklı içeriğin ayrılmasının ölçülmesi: dört teslim aynı `olcum-2026` adı altında 2200, 2180, 2160 ve yine 2200 satır getirdiğinde sürümsüz kurulumda tek bir ad dört koşumun tamamını belirsiz bırakıyor ve üç ayrı sınama sayısı 0,8067, 0,8064 ile 0,8078 aynı adın arkasında duruyor, içerik imzasıyla adlandırıldığında üç ad doğuyor ve belirsiz koşum sıfıra iniyor; model tarafında dört koşumun ağırlığı birebir aynı olduğu için yalnız ağırlığa bakan bir model kimliği dört koşumu tek sürümde topluyor ve ancak veri imzası eklendiğinde üç sürüm ayrılıyor; bedel olarak tarih adlı şema 8740 satır saklarken içerik adlı şema 6540 satır saklıyor ve her teslimde imza için 8740 satır okunuyor; çıktı imzası hattın yuttuğu değişikliği görmüyor, altmış kayıt iki kez geldiğinde kaynak imzası değişirken çıktı imzası ve isabet birebir aynı kalıyor.

İçindekiler

Önceki dersin defteri her koşumun kaç satır okuduğunu yazdı. On sekiz koşumun hepsi verisini aynı yerden okudu ve o yerin adı hiç değişmedi. Defter “2200 satır” yazdığında iki koşumun aynı 2200 satırı okuduğunu varsaydık, ama bu varsayım hiçbir yerde sınanmadı.

Bu ders o varsayımı sınar. Veri soyağacı, yani bir sunum değerinden kaynağa giden bağın kaydı, Veri Mühendisliğine Giriş kursunda ölçüldü ve burada tekrarlanmaz. Buradaki soru daha dar: bir ad altındaki içerik değiştiğinde ve ad değişmediğinde, kaç koşum birbirinden ayırt edilemez hâle geliyor.

  • YU19. Kurgu üretici veriyi dört teslimde getirir. Teslimler sırasıyla 2200, 2180, 2160 ve yine 2200 satırdır; dördü de aynı olcum-2026 adıyla yazılır. Dördüncü teslim birincinin içeriğiyle birebir aynıdır.
  • YU20. Veri sürümü bir adla bir içeriğin eşleşmesidir. Üç şema karşılaştırılır: sürümsüz (tek ad, üzerine yazılır), tarih adlı (her teslime bir ad) ve içerik adlı (ad, içerikten üretilen imzayı taşır).
  • YU21. İmza içerikten üretilen kısa bir özettir ve ders içinde yazılır; hiçbir dış kitaplık çağrılmaz. İmza bir güvenlik aracı değil, bir kimlik aracıdır.
  • YU22. Taban çizgisi sürümsüz kurulumdur: tek ad, üzerine yazılan içerik, geriye dönük yeniden üretim yok.
  • YU23. Ölçülen birimler ad sayısı, belirsiz koşum ve saklanan satırdır. Belirsiz koşum, aynı adı taşıyıp o ad altında farklı bir sonuç veren koşumdur.
  • YU24. Öznitelik kodu bu derste sabittir; dört koşum da tam geçmişi görür ve dört basamağa yuvarlar. Değişen tek şey verinin içeriğidir.
  • YU25. Etiket dağılımı {0: 1752, 1: 448}, taban sınıf oranı 0,7964’tür ve bu dersteki isabet sayıları bir başarım iddiası taşımaz. Çözünürlük 0,0017’dir.

Aynı Adın Altındaki İçerik

İlk blok önceki iki dersin kurgu kaynağını, hattını ve modelini aynen yeniden kurar.

# KURGUDUR. Sayac okumalari, hat ve model ders icinde tanimlanir; gercek bir
# ogrenme kitapligi ya da model kayit defteri urunu cagrilmaz.
TOHUM, M32 = 20260218, 0xFFFFFFFF


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


BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"]
TIP = ["mesken", "isyeri"]
DONEM = [f"2026-{a:02d}" for a in range(1, 13)]
ABONE = {}
for i in range(200):
    r = uretec(TOHUM + 37 * i)
    ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)],
                              "baslangic": 10000 + int(r() * 60000)}


def kaynak_uret():
    kayit = []
    for i, (ab, a) in enumerate(ABONE.items()):
        e = a["baslangic"]
        for d in DONEM:
            r = uretec(TOHUM + 101 * i + 7 * DONEM.index(d))
            e += 4 + int(r() * 46)
            kayit.append({"abone": ab, "donem": d, "bolge": a["bolge"], "tip": a["tip"],
                          "endeks": e, "birim": "m3"})
    return kayit


def a1_ayikla(kayit):
    ZOR = ("abone", "donem", "bolge", "endeks", "birim")
    tut = [k for k in kayit if all(a in k for a in ZOR)]
    return tut, len(kayit) - len(tut)


def a2_tekille(kayit):
    gor, tut = set(), []
    for k in kayit:
        ad = (k["abone"], k["donem"])
        if ad in gor:
            continue
        gor.add(ad)
        tut.append(k)
    return tut, len(kayit) - len(tut)


def a3_tuketim(kayit):
    tablo = {(k["abone"], k["donem"]): k for k in kayit}
    cikti, dusen = [], 0
    for k in kayit:
        i = DONEM.index(k["donem"])
        if i == 0:
            continue
        onceki = tablo.get((k["abone"], DONEM[i - 1]))
        if onceki is None:
            dusen += 1
            continue
        try:
            f = int(k["endeks"]) - int(onceki["endeks"])
        except (TypeError, ValueError):
            dusen += 1
            continue
        cikti.append(dict(k, m3=f))
    return cikti, dusen


EGITIM = DONEM[1:9]
SINAMA = DONEM[9:]
ESIK = 40


def satirlar():
    v, _ = a1_ayikla(kaynak_uret())
    v, _ = a2_tekille(v)
    v, _ = a3_tuketim(v)
    return v


def etiket(k):
    return 1 if k["m3"] > ESIK else 0


def oznitelikler(kayitlar, pencere=None, basamak=4):
    """Agirliktan bagimsizdir , bir kez hesaplanir."""
    sirali = sorted(kayitlar, key=lambda k: DONEM.index(k["donem"]))
    ab, bo = {}, {}
    for k in sirali:
        ab.setdefault(k["abone"], []).append((DONEM.index(k["donem"]), k["m3"]))
        bo.setdefault(k["bolge"], []).append((DONEM.index(k["donem"]), k["m3"]))

    def ortalama(dizi, i):
        secili = [v for d, v in dizi if (d < i and (pencere is None or d >= i - pencere))]
        return round(sum(secili) / len(secili), basamak) if secili else 0.0

    oz = {}
    for k in kayitlar:
        i = DONEM.index(k["donem"])
        oz[(k["abone"], k["donem"])] = {
            "abone_ort": ortalama(ab[k["abone"]], i),
            "bolge_ort": ortalama(bo[k["bolge"]], i),
            "isyeri": 1 if k["tip"] == "isyeri" else 0}
    return oz


IZGARA = [(a, b, c) for a in (0.6, 0.8, 1.0) for b in (0.0, 0.2, 0.4) for c in (0, 4, 8)]


def puan(o, w):
    return w[0] * o["abone_ort"] + w[1] * o["bolge_ort"] + w[2] * o["isyeri"]


def egit(kayitlar, oz, izgara=None, esik=ESIK, donemler=None):
    izgara = IZGARA if izgara is None else izgara
    donemler = EGITIM if donemler is None else donemler
    kume = [k for k in kayitlar if k["donem"] in donemler]
    en_iyi, en_iyi_w = -1.0, None
    for w in izgara:
        d = sum(1 for k in kume
                if (1 if puan(oz[(k["abone"], k["donem"])], w) > esik else 0) == etiket(k))
        o = d / len(kume)
        if o > en_iyi:
            en_iyi, en_iyi_w = o, w
    return {"agirlik": en_iyi_w, "egitim_isabeti": round(en_iyi, 4),
            "aday": len(izgara), "egitim_satiri": len(kume)}


def sina(kayitlar, model, oz, esik=ESIK, donemler=None):
    donemler = SINAMA if donemler is None else donemler
    kume = [k for k in kayitlar if k["donem"] in donemler]
    d = sum(1 for k in kume
            if (1 if puan(oz[(k["abone"], k["donem"])], model["agirlik"]) > esik else 0)
            == etiket(k))
    return round(d / len(kume), 4)

Dört teslim aşağıdaki blokta koşturulur. Her teslimde aynı kod aynı adla veriyi okur, modeli eğitir ve sonucu tuketim-esigi adıyla yazar. imza içerikten kısa bir özet üretir ve şimdilik yalnız raporlanır; hiçbir karara girmez.

S = satirlar()


def imza(metin):
    """Icerikten uretilen kisa bir ozet. Guvenlik degil , kimlik araci."""
    h = 2166136261
    for c in metin:
        h = ((h ^ ord(c)) * 16777619) & 0xFFFFFFFF
    return f"{h:08x}"


def veri_imzasi(kayitlar):
    return imza("|".join(f"{k['abone']}:{k['donem']}:{k['m3']}" for k in kayitlar))


TESLIM = [2200, 2180, 2160, 2200]
KOSUM = []
for no, n in enumerate(TESLIM, start=1):
    kay = S[:n]
    oz = oznitelikler(kay)
    m = egit(kay, oz)
    KOSUM.append({"kosum": no, "veri_adi": "olcum-2026", "satir": n,
                  "veri_imza": veri_imzasi(kay), "model_adi": "tuketim-esigi",
                  "agirlik": m["agirlik"], "sinama": sina(kay, m, oz)})
print(f"{'teslim':<8}{'veri adi':<13}{'satir':>7}{'veri imzasi':>13}"
      f"{'model adi':>15}{'agirlik':>17}{'sinama':>9}")
for k in KOSUM:
    print(f"{k['kosum']:<8}{k['veri_adi']:<13}{k['satir']:>7}{k['veri_imza']:>13}"
          f"{k['model_adi']:>15}{str(k['agirlik']):>17}{k['sinama']:>9.4f}")
print()
print("ayri sinama sayisi:", len(set(k["sinama"] for k in KOSUM)),
      " ayri agirlik:", len(set(k["agirlik"] for k in KOSUM)),
      " ayri veri icerigi:", len(set(k["veri_imza"] for k in KOSUM)))
teslim  veri adi       satir  veri imzasi      model adi          agirlik   sinama
1       olcum-2026      2200     bd88a253  tuketim-esigi    (0.6, 0.4, 0)   0.8067
2       olcum-2026      2180     f008c71c  tuketim-esigi    (0.6, 0.4, 0)   0.8064
3       olcum-2026      2160     cebfcc57  tuketim-esigi    (0.6, 0.4, 0)   0.8078
4       olcum-2026      2200     bd88a253  tuketim-esigi    (0.6, 0.4, 0)   0.8067

ayri sinama sayisi: 3  ayri agirlik: 1  ayri veri icerigi: 3

Tablo iki sütununda hiç değişmez: veri adı dört satırda da olcum-2026, model adı dört satırda da tuketim-esigi. Bir sütununda da hiç değişmez: ağırlık dört koşumda da (0.6, 0.4, 0), yani üretilen model dosyası birebir aynıdır. Değişen iki sütun vardır: içerik imzası üç ayrı değer alır ve sınama isabeti üç ayrı sayı verir.

Adın Kaç İçeriği Var

Sayılacak şey artık nettir. Bir adlandırma şeması, aynı adı taşıyıp farklı sonuç veren koşum bırakıyorsa o koşumlar belirsizdir: hangi içerikten geldikleri addan okunamaz.

def olc(kimlik):
    """Kac ad var , kac kosum belirsiz kaliyor , kac satir saklaniyor."""
    grup = {}
    for k in KOSUM:
        grup.setdefault(kimlik(k), []).append(k)
    belirsiz = sum(len(v) for v in grup.values() if len(set(x["sinama"] for x in v)) > 1)
    return len(grup), belirsiz, sum(v[-1]["satir"] for v in grup.values())


print(f"{'sema':<14}{'veri adi':>10}{'belirsiz kosum':>16}{'saklanan satir':>16}")
for ad, kim in (("surumsuz", lambda k: k["veri_adi"]),
                ("tarih adli", lambda k: f"{k['veri_adi']}@t{k['kosum']}"),
                ("icerik adli", lambda k: f"{k['veri_adi']}@{k['veri_imza']}")):
    a, b, s = olc(kim)
    print(f"{ad:<14}{a:>10}{b:>16}{s:>16}")
print()
print(f"{'model kimligi':<26}{'ayri surum':>12}{'belirsiz kosum':>16}")
for ad, kim in (("yalniz agirlik", lambda k: imza(str(k["agirlik"]))),
                ("veri imzasi + agirlik", lambda k: imza(f"{k['veri_imza']}|{k['agirlik']}"))):
    a, b, _ = olc(kim)
    print(f"{ad:<26}{a:>12}{b:>16}")
print()
print("imza icin okunan satir:", sum(TESLIM))
sema            veri adi  belirsiz kosum  saklanan satir
surumsuz               1               4            2200
tarih adli             4               0            8740
icerik adli            3               0            6540

model kimligi               ayri surum  belirsiz kosum
yalniz agirlik                       1               4
veri imzasi + agirlik                3               0

imza icin okunan satir: 8740

Sürümsüz kurulumda tek bir ad vardır ve dört koşumun dördü de belirsizdir. Bu satır kursun kuralının veri tarafındaki hâlidir: 0,8078 sayısı bir rapora girdiğinde onu üreten içerik artık yoktur, çünkü dördüncü teslim üçüncünün üzerine yazmıştır. Saklanan satır sütunu bunu doğrular: sürümsüz şema en az yeri tutar, 2200 satır, ve karşılığında geçmişin tamamını kaybeder.

Tarih adlı şema belirsizliği sıfıra indirir, ama bir kusuru vardır: dört ad üretir, oysa üç içerik vardır. Birinci ve dördüncü teslim birebir aynı içeriktir ve tarih şeması bunu göremediği için aynı 2200 satırı iki kez saklar. İçerik adlı şema aynı belirsizliği üç adla ve 6540 satırla karşılar; dördüncü teslim hiç yeni yer tutmaz, çünkü imzası zaten defterdedir.

İmza Neyi İmzalar

veri_imzasi hattın çıktısını imzalar, yani abone, dönem ve hesaplanmış tüketim üçlüsünü. Bu bir seçimdir ve bedeli vardır: hattın yuttuğu bir üretici değişikliği çıktı imzasına hiç yansımaz. Aşağıdaki blok bunu ölçer. Üretici, temmuz ayında altmış kaydı iki kez göndersin; kaynak değişmiştir ama tekilleştirme aşaması yinelenen satırları düşürür.

def kaynak_imzasi(kayitlar):
    return imza("|".join(f"{k['abone']}:{k['donem']}:{k['endeks']}" for k in kayitlar))


def hatta_ver(kaynak):
    v, _ = a1_ayikla(kaynak)
    v, _ = a2_tekille(v)
    v, _ = a3_tuketim(v)
    return v


ham = kaynak_uret()
# Uretici 60 kaydi iki kez gonderdi: kaynak degisti , hat onu yutuyor.
yinelenen = ham + [dict(k) for k in ham if k["abone"] <= "A060" and k["donem"] == "2026-07"]
print(f"{'teslim':<12}{'kaynak satiri':>15}{'kaynak imzasi':>15}"
      f"{'cikti satiri':>14}{'cikti imzasi':>14}{'sinama':>9}")
for ad, kaynak in (("saglam", ham), ("yinelenen", yinelenen)):
    c = hatta_ver(kaynak)
    oz2 = oznitelikler(c)
    m2 = egit(c, oz2)
    print(f"{ad:<12}{len(kaynak):>15}{kaynak_imzasi(kaynak):>15}{len(c):>14}"
          f"{veri_imzasi(c):>14}{sina(c, m2, oz2):>9.4f}")
print()
print(f"{'teslim':<8}{'satir':>7}{'sinama satiri':>15}{'cozunurluk':>12}")
for n in TESLIM[:3]:
    sk = [k for k in S[:n] if k["donem"] in SINAMA]
    print(f"{n:<8}{n:>7}{len(sk):>15}{1 / len(sk):>12.4f}")
teslim        kaynak satiri  kaynak imzasi  cikti satiri  cikti imzasi   sinama
saglam                 2400       d501f04f          2200      bd88a253   0.8067
yinelenen              2460       93576832          2200      bd88a253   0.8067

teslim    satir  sinama satiri  cozunurluk
2200       2200            600      0.0017
2180       2180            594      0.0017
2160       2160            588      0.0017

Kaynak imzası değişti, çıktı imzası birebir aynı kaldı ve isabet de aynı. İki teslimin sürüm kaydı aynı satırı gösterir, oysa üreticiden gelen içerik farklıdır. Bu, hattın doğru davranışıdır ve sürümlemenin bir sınırıdır: çıktı imzası hattın yuttuğu değişikliği görmez. Ters yönde de eksiktir; kaynağı imzalayan bir şema burada bir sürüm farkı işaretler, oysa modele giden veri hiç değişmemiştir. İki imza iki ayrı soruyu yanıtlar ve hangisinin tutulduğu yazılmadan bir veri sürümü eksik kalır.

Alt tablo bir başka ayrıntıyı kapatır. Teslim küçüldükçe sınama kümesi de küçülür: 600, 594 ve 588 satır. Üç teslimde çözünürlük 0,0017’de kalır, ama karşılaştırılan sayılar aynı kümede ölçülmüş değildir. 0,8067 ile 0,8064 arasındaki fark bu yüzden bir başarım farkı olarak okunamaz.

Modelin Kimliği Ağırlığından İbaret Değildir

Alt tablo dersin en sessiz bulgusunu taşır. Model dosyası dört koşumda da aynıdır, dolayısıyla modeli kendi içeriğine göre adlandıran bir şema dört koşumu tek bir sürümde toplar ve dördünü de belirsiz bırakır. Bu, veri tarafındaki hatanın aynadaki görüntüsüdür: orada bir ad üç içeriği örtüyordu, burada bir içerik üç sayıyı örtüyor.

Dört model dosyası birbirinin yerine konabilir görünür, çünkü aynı ağırlıkları taşırlar. Yerlerine konamazlar: her biri farklı bir veri kümesinde ölçülmüştür ve bildirdikleri sayı 0,8067, 0,8064 ve 0,8078’dir. Aradaki 0,0014 ile 0,0011 fark çözünürlüğün altında değildir, çünkü sınama kümesinin boyu da teslimle birlikte değişmiştir. Ağırlığa veri imzası eklendiğinde kimlik üç sürüme ayrılır ve belirsiz koşum 0’a iner. Bir model sürümü, model dosyasının değil, model dosyasıyla onu üreten veri sürümünün birlikte imzasıdır.

Sürümlemenin Bedeli ve Söylemediği

Bedel üç kalemdir. Birincisi saklanan satırdır: içerik adlı şema 6540 satır tutar, sürümsüz şemanın 2,97 katı. İkincisi okunan satırdır: imza içerikten hesaplandığı için her teslimde bütün satırlar bir kez daha okunur, dört teslimde 8740 satır. Üçüncüsü eklenen adımdır: yazma işlemi artık imza hesaplamak ve defter satırı eklemek zorundadır.

Bunun karşılığında alınan şey dar ve kesindir: sürümleme hangi içeriğin hangi sayıyı ürettiğini söyler. Söylemediği şeyse hangi içeriğin doğru olduğudur. Üç teslimden hangisinin eksik geldiğini, hangisinin tam olduğunu ve 0,8078 sayısının güvenilir olup olmadığını üç imza da söylemez; onu söyleyen şey Veri Mühendisliğine Giriş kursunda ölçülen denetimlerdir. Sürümleme bir kalite aracı değil, bir kimlik aracıdır ve katkısı yalnız belirsiz koşum sayısıyla ölçülür.

Özet

  • Dört teslim aynı olcum-2026 adıyla 2200, 2180, 2160 ve yine 2200 satır getirdi; ad hiç değişmedi, içerik üç ayrı imza aldı ve sınama isabeti 0,8067, 0,8064 ile 0,8078 oldu.
  • Sürümsüz şemada tek ad vardır ve dört koşumun dördü de belirsizdir; içerik adlı şemada üç ad vardır ve belirsiz koşum 0’dır.
  • Tarih adlı şema belirsizliği aynı şekilde kapatır ama dört ad üretip 8740 satır saklar; içerik adlı şema aynı işi üç ad ve 6540 satırla, yani sürümsüz şemanın 2,97 katıyla yapar, çünkü dördüncü teslimin birinciyle aynı olduğunu görür.
  • Çıktı imzası hattın yuttuğu değişikliği görmez: altmış kayıt iki kez geldiğinde kaynak imzası değişir, çıktı imzası ve isabet birebir aynı kalır. Hangi imzanın tutulduğu yazılmadan bir veri sürümü eksik kalır.
  • Model dosyası dört koşumda da birebir aynıdır. Yalnız ağırlığa bakan bir model kimliği dört koşumu tek sürümde toplar; veri imzası eklendiğinde üç sürüm ayrılır ve belirsiz koşum 0 olur.
  • Sürümleme hangi içeriğin hangi sayıyı ürettiğini söyler, hangisinin doğru olduğunu söylemez; o soru denetimlerin işidir.

Sonraki Adım

Üç derste koşumun kendisi kayda geçti ve sürümlendi: hangi kalemlerle koşulduğu yazıldı, hangi içeriği okuduğu bir imzaya bağlandı ve aynı adın arkasındaki üç içerik birbirinden ayrıldı. Bütün bu iş eğitim tarafında yapıldı. Modele giren özniteliğin eğitim sırasında bir kodla, üretimde çağrıldığında başka bir kodla hesaplanıyor olabileceği hiç sorulmadı. Sonraki ders o iki yolu yan yana koyar ve tek bir soruyu ölçer: ağırlıklar birebir aynıyken isabet neden düşüyor.

İ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