Ders 02 / 13
Kavram Kayması
Girdi hiç değişmeden girdi ile etiket arasındaki kuralın değişmesinin ölçülmesi: yüksek sayılma eşiği 30'dan 27'ye indiğinde girdi tarafında değişen tek bir değer olmamasına karşın 1200 izleme satırının 132'sinin etiketi değişiyor ve modelin isabeti 0,9700'den 0,8150'ye, yani otuz bir çözünürlük adımı düşüyor. Aynı üç gösterge iki kayma türünde yan yana okunduğunda vekil ölçütlerin neyi görüp neyi kaçırdığı sayıya dönüyor: girdi özeti iki senaryoda da hiçbir bantta ateşlemiyor, tahmin payı 0,05 bandında ikisinde de üç dönem ateşleyerek zararsızı zararlıdan ayıramıyor ve 0,10 bandında zararsız kaymada iki dönem ateşlerken zararlı kaymada hiç ateşlemiyor, isabet ise zararsız kaymada susup zararlı kaymada dört dönem ateşleyerek tek ayırt eden ölçü olarak kalıyor.
İçindekiler
Önceki derste kayan şey girdiydi: girdi özeti 25,9220’den 27,0472’ye çıktı, tahmin payı üç dönem uyarı ateşledi ve isabet 0,9700’den 0,9800’e giderek hiç düşmedi. Kural yerinde durduğu için model doğru kalabildi ve ateşleyen uyarıların üçü de yanlış alarm sayıldı.
Bu ders tam tersini kurar. Girdi tarafında tek bir değer bile değişmez; değişen, girdi ile etiket arasındaki kuralın kendisidir. Aynı abonenin aynı geçmişi artık başka bir etiket üretmeye başlar, çünkü “yüksek sayılma” ölçütü kaymıştır. Model hiç dokunulmadan yerinde durur ve ölçülecek soru şudur: önceki dersin üç göstergesi bu durumda ne der.
- MI8. Kaynak, hat, model ve kayma senaryoları kurgudur; gerçek bir öğrenme kitaplığı, izleme ürünü ya da bulut servisi çağrılmaz. Tohum 20260218.
- MI9. Kavram kayması (concept drift) girdi ile etiket arasındaki ilişkinin değişmesidir. Veri kayması girdi dağılımını, kavram kayması kuralı oynatır. Kaymanın ölçüm yordamı Model Değerlendirme, Yorumlanabilirlik ve Etik kursunda kuruldu ve tekrarlanmaz; buradaki ek yalnız üretimdeki ömürdür.
- MI10. Bu kursun etiketi
abone_ort + 6 x isyeri > 30kuralıdır ve kural KAVRAM’dır. Kurgu kavram kayması2026-09‘dan sonra eşiği **30’dan 27’ye** indirir; kayıtlara dokunmaz, yalnız etiket üretir. - MI11. İzleme dönemleri 2026-07…2026-12, dönem başına 200 satır, toplam 1200. İzleme dönemlerinde taban sınıf oranı 0,5342; küme dengelidir.
- MI12. Üç gösterge: girdi özeti (özniteliğin dönem ortalaması), tahmin payı (modelin yüksek dediği satırların oranı) ve isabet. İlk ikisi etiket istemez, üçüncüsü ister.
- MI13. Taban çizgisi izlemesiz kurulumdur: gösterge yok, uyarı yok; bozulma görülmez.
- MI14. Uyarı eşiği iki yönlü bir banttır: ölçü tabandan pay kadar saparsa ateşler.
Taban dönem
2026-08, yani kaymanın başladığı dönemden önceki son dönem. - MI15. Çözünürlük: dönem isabetinin adımı 1/200 = 0,0050. Bu derste düşüş 0,1550, yani otuz bir adım ve bandın çok üstünde; önceki dersin oynaması dört adımdı.
Değişmeyen Girdi, Değişen Kural
İlk blok önceki dersin kurulumunu aynen kurar: kaynak, hattın modele bakan üç aşaması, öznitelikler, karar eşiği ayrı aranan model ve üç gösterge. Model bu derste hiç yeniden eğitilmez; ölçülen şey, sabit bir modelin altından kuralın çekilmesidir.
# KURGUDUR. Olcum aginin sayac okumalari, hattin modele bakan ilk uc asamasi, # esik tabanli model ve kayma senaryolari ders icinde tanimlanir; gercek bir # ogrenme kitapligi, izleme urunu ya da bulut servisi 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): """Donem farkindan tuketim. Onceki donem yoksa satir hesaplanamaz.""" 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 cikti.append(dict(k, m3=int(k["endeks"]) - int(onceki["endeks"]))) return cikti, dusen def satirlar(): v, _ = a1_ayikla(kaynak_uret()) v, _ = a2_tekille(v) v, _ = a3_tuketim(v) return v def oznitelikler(kayitlar, basamak=4): """Oznitelik agirliktan bagimsizdir; tam gecmisten 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] return round(sum(secili) / len(secili), basamak) if secili else 0.0 return {(k["abone"], k["donem"]): { "abone_ort": ortalama(ab[k["abone"]], DONEM.index(k["donem"])), "bolge_ort": ortalama(bo[k["bolge"]], DONEM.index(k["donem"])), "isyeri": 1 if k["tip"] == "isyeri" else 0} for k in kayitlar} 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"] # Etiket, ozniteliklerin GORDUGU bir kurala baglidir. KURAL = KAVRAM. KURAL_ESIK = 30 KURAL_ISYERI = 6 def etiket(oz_k, esik=KURAL_ESIK, isyeri_kat=KURAL_ISYERI): return 1 if oz_k["abone_ort"] + isyeri_kat * oz_k["isyeri"] > esik else 0 IZLEME = DONEM[6:] # 2026-07 .. 2026-12 : uretimde izlenen donemler KARAR_IZGARA = (18, 22, 26, 30, 34) # karar esigi ETIKET esiginden AYRI bir ayardir def tahmin(oz_k, w, karar): return 1 if puan(oz_k, w) > karar else 0 def dengeli_isabet(kume, oz, w, karar, kural=None): c = {(0, 0): 0, (0, 1): 0, (1, 0): 0, (1, 1): 0} for k in kume: o_k = oz[(k["abone"], k["donem"])] c[(tahmin(o_k, w, karar), kural(k, o_k) if kural else etiket(o_k))] += 1 du = c[(1, 1)] / max(c[(1, 1)] + c[(0, 1)], 1) # duyarlilik oz_ = c[(0, 0)] / max(c[(0, 0)] + c[(1, 0)], 1) # ozgulluk return {"isabet": (c[(1, 1)] + c[(0, 0)]) / len(kume), "duyarlilik": du, "ozgulluk": oz_, "dengeli": (du + oz_) / 2, "agirlik": w, "karar": karar} def egit(kayitlar, oz, donemler=None, kural=None): """Egitim = agirlik ucLUsu ILE karar esigini birlikte aramak: 27 x 5 = 135 aday.""" kume = [k for k in kayitlar if k["donem"] in (donemler or DONEM[1:9])] return max((dengeli_isabet(kume, oz, w, karar, kural) for w in IZGARA for karar in KARAR_IZGARA), key=lambda o: o["dengeli"]) def girdi_ozeti(kayitlar, donem, oz): d = [oz[(k["abone"], k["donem"])]["abone_ort"] for k in kayitlar if k["donem"] == donem] return round(sum(d) / len(d), 4) def tahmin_payi(kayitlar, model, oz, donem): d = [tahmin(oz[(k["abone"], k["donem"])], model["agirlik"], model["karar"]) for k in kayitlar if k["donem"] == donem] return round(sum(d) / len(d), 4) def isabet(kayitlar, model, oz, donem, etiketler=None): """etiketler=None -> kural degismemis demektir.""" kume = [k for k in kayitlar if k["donem"] == donem] d = 0 for k in kume: o_k = oz[(k["abone"], k["donem"])] g = etiketler[(k["abone"], k["donem"])] if etiketler else etiket(o_k) d += tahmin(o_k, model["agirlik"], model["karar"]) == g return round(d / len(kume), 4) S = satirlar() OZ = oznitelikler(S) MODEL = egit(S, OZ) IZL = [k for k in S if k["donem"] in IZLEME] dag = {0: 0, 1: 0} for k in IZL: dag[etiket(OZ[(k["abone"], k["donem"])])] += 1 print("izleme satiri:", len(IZL), " donem basina:", len(IZL) // len(IZLEME), " taban sinif orani:", round(dag[0] / len(IZL), 4)) print("model:", MODEL["agirlik"], "/ karar esigi", MODEL["karar"], " dengeli isabet:", round(MODEL["dengeli"], 4))
izleme satiri: 1200 donem basina: 200 taban sinif orani: 0.5342 model: (0.6, 0.0, 4) / karar esigi 18 dengeli isabet: 0.9864
Kavram Kaydığında Ne Görünüyor
İkinci blok kavram kaymasını uygular. kavram_kaydir işlevi kayıtlara dokunmaz; yalnız
2026-09‘dan başlayarak yüksek sayılma eşiğini 27’ye indirilmiş biçimde etiket üretir. Tabloda son
iki sütun önemlidir: kural değişmeseydi o dönemde alınacak isabet ve o dönemde etiketi
değişen satır sayısı.
# ---- KURGU kavram kaymasi: GIRDI AYNI KALIR , kural degisir. # 2026-09'dan sonra "yuksek sayilma" esigi 30'dan 27'ye iniyor. def kavram_kaydir(kayitlar, oz, baslangic="2026-09", yeni_esik=27): b = DONEM.index(baslangic) return {(k["abone"], k["donem"]): etiket(oz[(k["abone"], k["donem"])], yeni_esik if DONEM.index(k["donem"]) >= b else KURAL_ESIK) for k in kayitlar} YENI = kavram_kaydir(S, OZ) print(f"{'donem':<10}{'girdi ozeti':>13}{'tahmin payi':>13}{'isabet':>9}" f"{'kural degismeseydi':>20}{'etiketi degisen':>17}") for d in IZLEME: kume = [k for k in S if k["donem"] == d] ceviren = sum(1 for k in kume if YENI[(k["abone"], d)] != etiket(OZ[(k["abone"], d)])) print(f"{d:<10}{girdi_ozeti(S, d, OZ):>13.4f}{tahmin_payi(S, MODEL, OZ, d):>13.4f}" f"{isabet(S, MODEL, OZ, d, YENI):>9.4f}{isabet(S, MODEL, OZ, d):>20.4f}" f"{ceviren:>17}")
donem girdi ozeti tahmin payi isabet kural degismeseydi etiketi degisen 2026-07 25.9220 0.4550 0.9700 0.9700 0 2026-08 26.0517 0.4700 0.9700 0.9700 0 2026-09 25.9800 0.4550 0.8150 0.9900 39 2026-10 26.3525 0.5100 0.8700 0.9750 31 2026-11 26.3261 0.5100 0.8650 0.9850 30 2026-12 26.5325 0.5150 0.8500 0.9900 32
İsabet 2026-09‘da **0,9700’den 0,8150’ye** düşüyor. Düşüş 0,1550, yani çözünürlüğün otuz
bir adımı; önceki dersin bütün oynaması dört adımdı. Modelde değişen tek bir sayı yoktur ve
girdi tarafında da yoktur: son sütun kaymanın nereden geldiğini söyler, 2026-09’da 39
satırın etiketi değişmiştir. Değişen etiketlerin hepsi hataya dönüşmez, çünkü modelin karar eşiği
bazı satırlarda yeni kuralla zaten uyumludur; sonraki dönemlerde isabet 0,8700 dolayında
tutunur ama eski düzeyine hiç dönmez.
İlk iki sütun tam olarak beklendiği gibi davranır. Girdi özeti 25,9220’den 26,5325’e, tahmin payı 0,4550’den 0,5150’ye gider. Bu iki seri, kavram kayması hiç olmasaydı da birebir aynı olurdu, çünkü ikisi de yalnız girdiye ve modele bakar; kuralın nereye kaydığından haberleri yoktur.
Zararsız Kaymada Ateşleyen, Zararlı Kaymada Susan
Üçüncü blok önceki dersin veri kayması senaryosunu geri getirir ve iki senaryoyu aynı üç göstergeyle, aynı üç bantla yan yana koyar. Tabloda okunacak şey tek tek sayılar değil, satırların birbirine göre durumudur.
# ---- KURGU veri kaymasi (onceki ders): GIRDI kayar , KURAL AYNI KALIR. def kaydir(kayitlar, baslangic="2026-09", egim=0.06): b = DONEM.index(baslangic) return [dict(k, m3=round(k["m3"] * (1.0 + egim * (DONEM.index(k["donem"]) - b + 1)), 4)) if DONEM.index(k["donem"]) >= b and k["tip"] == "isyeri" else dict(k) for k in kayitlar] def uyari(dizi, taban, pay): return [d for d, v in dizi if abs(v - taban) / max(abs(taban), 1e-9) > pay] KAYAN = kaydir(S) OZK = oznitelikler(KAYAN) print(f"{'senaryo':<16}{'olcu':<14}{'taban':>10}{'en buyuk sapma':>16}" f"{'0,05':>7}{'0,10':>7}{'0,20':>7}") for ad, (kay, oz, et) in (("veri kaymasi", (KAYAN, OZK, None)), ("kavram kaymasi", (S, OZ, YENI))): for olcu_ad, dizi in (("girdi ozeti", [(d, girdi_ozeti(kay, d, oz)) for d in IZLEME]), ("tahmin payi", [(d, tahmin_payi(kay, MODEL, oz, d)) for d in IZLEME]), ("isabet", [(d, isabet(kay, MODEL, oz, d, et)) for d in IZLEME])): taban = dict(dizi)[IZLEME[1]] print(f"{ad:<16}{olcu_ad:<14}{taban:>10.4f}" f"{max(abs(v - taban) / taban for _, v in dizi):>16.4f}" + "".join(f"{len(uyari(dizi, taban, p)):>7}" for p in (0.05, 0.10, 0.20))) print("\nkavram kaymasinda degisen satir sayisi:", sum(1 for k in IZL if YENI[(k["abone"], k["donem"])] != etiket(OZ[(k["abone"], k["donem"])])), "/", len(IZL), " girdi tarafinda degisen deger: 0") DUSUS = isabet(S, MODEL, OZ, IZLEME[0], YENI) - isabet(S, MODEL, OZ, IZLEME[2], YENI) print("isabetin dustugu:", f"{DUSUS:.4f}", " donem isabetinin adimi:", f"{1 / 200:.4f}", " yani", round(DUSUS * 200), "adim")
senaryo olcu taban en buyuk sapma 0,05 0,10 0,20 veri kaymasi girdi ozeti 26.0517 0.0382 0 0 0 veri kaymasi tahmin payi 0.4700 0.1596 3 2 0 veri kaymasi isabet 0.9700 0.0206 0 0 0 kavram kaymasi girdi ozeti 26.0517 0.0185 0 0 0 kavram kaymasi tahmin payi 0.4700 0.0957 3 0 0 kavram kaymasi isabet 0.9700 0.1598 4 4 0 kavram kaymasinda degisen satir sayisi: 132 / 1200 girdi tarafinda degisen deger: 0 isabetin dustugu: 0.1550 donem isabetinin adimi: 0.0050 yani 31 adim
Girdi özeti iki senaryoda da hiçbir bantta ateşlemez. Kavram kaymasında bunun başka türlüsü de mümkün değildir: girdi tarafında değişen sıfır değer vardır ve gösterge yalnız girdiye bakar.
Tahmin payı iki kez ateşler ve her ikisinde de yanıltır. 0,05 bandında her iki senaryoda da üç dönem ateşliyor, yani zararsız kaymayı zararlı kaymadan ayırt edemiyor. 0,10 bandında ise tam ters çalışıyor: zararsız kaymada iki dönem ateşliyor, zararlı kaymada hiç. Kavram kaymasındaki 0,0957’lik sapmanın kaymayla ilgisi de yoktur; o seri, kural hiç değişmeseydi de aynıydı. Bir gösterge ateşlediğinde tek başına ne bozulmayı ne de nedenini gösterir.
İsabet tek ayırt eden ölçüdür. Zararsız kaymada sapması 0,0206 ve hiçbir bantta ateşlemiyor; zararlı kaymada sapması 0,1598 ve hem 0,05 hem 0,10 bandında dört dönem ateşliyor. Bu kursun kuralı burada iki yönlü okunur: bir göstergenin ateşlemesi bozulmanın kanıtı olmadığı gibi, susması da sağlamlığın kanıtı değildir; ateşlemesi ile bozulması ayrı ayrı gösterilmeyen gösterge ölçülmemiş sayılır. İzlemesiz taban çizgisinde ise 132 satırın etiketi değişmiş, isabet otuz bir adım düşmüş ve hiçbir şey haber vermemiştir.
Özet
- Kavram kayması girdi ile etiket arasındaki kuralın değişmesidir; veri kaymasının aksine girdi tarafında değişen tek bir değer yoktur.
- Eşik 30’dan 27’ye indiğinde 1200 izleme satırının 132’sinin etiketi değişir ve isabet 0,9700’den 0,8150’ye düşer: 0,1550, yani otuz bir çözünürlük adımı. Model hiç değişmemiştir.
- Girdi özeti iki senaryoda da hiçbir bantta ateşlemez; kavram kaymasında ateşlemesi zaten olanaksızdır, çünkü baktığı yerde değişen bir şey yoktur.
- Tahmin payı 0,05 bandında iki senaryoda da üç dönem ateşleyerek ikisini ayırt edemez, 0,10 bandında ise zararsız kaymada iki dönem ateşleyip zararlı kaymada hiç ateşlemez.
- İsabet tek ayırt eden ölçüdür: zararsız kaymada sapması 0,0206 ve susar, zararlı kaymada 0,1598 ve 0,05 ile 0,10 bantlarında dört dönem ateşler.
Sonraki Adım
İki derste ortaya çıkan sonuç şudur: bozulmayı gören tek gösterge isabettir. Fakat isabet öbür ikisinden farklı bir şey ister, gerçek etiketi. Girdi özeti ile tahmin payı, tahmin üretildiği anda hesaplanabilir; isabet ise satırın gerçekten yüksek olup olmadığı bilinene kadar hesaplanamaz ve o bilgi üretimde tahminle aynı anda gelmez. Bu derste etiket, hesaplama sırasında elde varmış gibi kullanıldı. Sonraki ders bu varsayımı kaldırır: etiket iki dönem sonra geldiğinde bir dönemin isabetinin hangi dönemde bilinebildiğini, bozulmanın olduğu an ile görüldüğü an arasındaki boşluğu ve o boşlukta kaç tahminin ölçülmeden üretildiğini sayar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.