İçeriğe geç
academia.sh

Ders 05 / 13

Veri Görsel Denetimi

Altı kurallık bir tarama ham kayıt katmanında dört sorun buluyor ve her biri ayrı bir özeti bozuyor: 0,00 değeri 119 kez tekrarlanıyor ve küme ortalamasını 19,693'te tutuyor, oysa okuma sayılmayan satırlar dışarıda bırakılsa 20,454 olurdu; 45,00 m³ tavanında 20 kayıt birikmiş ve en büyük yüzde 1'in ortalaması 46,597 yerine 44,663 görünüyor; 213 satır sıfır kişilik hanede ölçülmüş tüketim taşıyor ve kişi başına tüketim, karara göre 11,204 ya da 10,617 çıkıyor; dönemler arasındaki satır açıklığı yüzde 33,5 ve ilk dönem ortalaması dengeli aboneler alınınca 20,644'ten 20,868'e çıkıyor. Hiçbir satır silinmiyor. Konu kapanışında keşfin açtığı borç sayılıyor: beş kırılım alanı 23 tekil ve 209 ikili hücre, toplam 232 ayrı alt küme üretiyor ve bunların 33'ü 30 satırdan az.

İçindekiler

Bu konunun ilk dört dersi kümeye hep hesapla yaklaştı: ortalama alındı, dağılım sayıldı, katsayı hesaplandı, matris kuruldu. Hepsinin ortak varsayımı kayıttaki değerlerin ölçülmüş değerler olmasıydı. Oysa keşif sırasında ilk yakalanan şeyler çoğu zaman hesapla değil, tabloya bakarken görülür: aynı değerin şüpheli sıklıkta tekrarı, bir sınırda biriken kayıtlar, birlikte bulunmaması gereken alan bileşimleri, bir dönemin diğerlerinden belirgin biçimde seyrek olması.

Bu dersin ölçüsü denetimin yakaladığı sorun sayısı ve her birinin bozduğu özettir. Dört sorun bulunur, her biri için tek soru sorulur — hangi sayıyı ne kadar oynatıyor — ve hiçbir satır silinmez.

  • EA21. Görsel denetim burada çizim değil, sayıya çevrilmiş bir taramadır: hangi değer kaç kez tekrarlanıyor, kayıtlar nerede birikiyor, hangi alan bileşimi var olamaz, hangi dilim seyrek.
  • EA22. Yığılma aynı değerin beklenenden çok tekrarıdır; ölçüsü en sık görülen değerin satır payıdır. Sürekli bir büyüklükte aynı sayının yüzlerce kez çıkması bir ölçüm değil, bir kayıt uzlaşımıdır.
  • EA23. Kesilme kayıtların bir üst ya da alt sınırda birikmesidir; ölçüsü o sınırdaki kayıt sayısıdır. Kesilme onarılamaz: kesilen değer kayıtta yoktur. Sayılabilecek tek şey kaç kaydın kesildiği ve hangi özetin ne kadar bozulduğudur.
  • EA24. İmkânsız birleşim, tek tek geçerli iki alanın birlikte geçersiz olmasıdır; ölçüsü kuralı bozan satır sayısıdır.
  • EA25. Bu derste hiçbir satır silinmez. Temizleme Veri Toplama ve Hazırlama kursunun işiydi ve orada ölçü satır sayısıydı; burada her sorun için iki hesap yan yana basılır ve aradaki fark yazılır.

Altı Kural, Dört Bulgu

# kesif.py — MODELDIR: K03 ve K04'un kurgu olcum agi ayni tohumla yeniden
# uretilir. Kume kurgudur; hicbir gercek abone, sayac ya da bolge temsil edilmez.
import math
from collections import Counter

TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF
DONEM = ["2026-01", "2026-02", "2026-03"]
TARIFE = [10, 25, 40]
BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26),
         ("bati", 0.14, 14), ("merkez", 0.18, 23)]


def uretec(t: int):
    """Dogrusal eslemeli uretec: tohum koda yazilidir, cikti kosumdan kosuma ayni."""
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki() -> float:
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


def ayrik(u: float, w: list[float]) -> int:
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


_abone, _elenen = [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    k = {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2],
         "hane_kisi": ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05]),
         "memnuniyet": ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17]) + 1}
    (_elenen if r() < 0.046 else _abone).append(k)
_gecerli = {a["abone_no"] for a in _abone}

OKUMA = []
for k in _abone + _elenen:
    r = uretec(TOHUM + 7000 + k["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(k["taban"] * math.exp(
            (r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100 + 0.5) / 100
        if k["abone_no"] not in _gecerli:
            r()
            continue
        OKUMA.append({"abone_no": k["abone_no"], "bolge": k["bolge"],
                      "donem": DONEM[d], "tuketim_m3": t, "hane_kisi": k["hane_kisi"],
                      "memnuniyet": k["memnuniyet"],
                      "basamak": 1 if t < TARIFE[0] else 2 if t < TARIFE[1]
                      else 3 if t < TARIFE[2] else 4})
        r()

def ort(v: list[float]) -> float:
    return sum(v) / len(v)


def hiza(w: list[int], sol: int = 1):
    """Ilk `sol` sutun sola, kalanlar saga yaslanir."""
    return lambda h: "".join(str(v).ljust(w[i]) if i < sol else str(v).rjust(w[i])
                             for i, v in enumerate(h))


# Ham kayit katmani MODELDIR: saha cihazi 45,00 m3'un ustunu okuyamaz ve tavani
# yazar. Analistin eline gecen tablo budur; OKUMA yalnizca kiyas icin durur.
TAVAN = 45.0
KAYIT = [dict(o, tuketim_m3=min(o["tuketim_m3"], TAVAN)) for o in OKUMA]
T = [k["tuketim_m3"] for k in KAYIT]
sik = Counter(T).most_common(1)[0]
donem_say = Counter(k["donem"] for k in KAYIT).values()
ikiz = Counter((k["abone_no"], k["donem"]) for k in KAYIT).values()

KURAL = [
    ("yigilma", "en sik degerin satir payi (yuzde)", 100 * sik[1] / len(T), 1.0,
     f"{sik[0]:.2f} degeri {sik[1]} kez tekrarlaniyor"),
    ("kesilme", "en buyuk degerdeki kayit sayisi", float(Counter(T)[max(T)]), 5.0,
     f"{max(T):.2f} m3 ust sinirinda {Counter(T)[max(T)]} kayit birikmis"),
    ("imkansiz birlesim", "hane 0 iken tuketim > 0 satir",
     float(sum(1 for k in KAYIT if k["hane_kisi"] == 0 and k["tuketim_m3"] > 0)), 1.0,
     "sifir kisilik hanede olculmus tuketim var"),
    ("donem boslugu", "donemler arasi satir acikligi",
     100 * (max(donem_say) - min(donem_say)) / max(donem_say), 10.0,
     f"en seyrek donem {min(donem_say)}, en yogunu {max(donem_say)} satir"),
    ("yinelenen kayit", "ayni abone-donem ciftinin satiri", float(max(ikiz)), 1.5,
     "-"),
    ("tanimsiz deger", "negatif tuketim yazan satir",
     float(sum(1 for t in T if t < 0)), 1.0, "-"),
]
d = hiza([20, 34, 9, 8], 2)
print(d(["sorun", "olculen", "deger", "esik"]) + "  bulgu")
sorun = 0
for ad, olcut, deger, esik, metin in KURAL:
    var = deger >= esik
    sorun += var
    print(d([ad, olcut, f"{deger:.1f}", f"{esik:.1f}"]) + "  " + (metin if var else "-"))
print(f"\n{len(KURAL)} kural yuruldu, {sorun} sorun bulundu; hicbiri satir silmiyor")
sorun               olculen                               deger    esik  bulgu
yigilma             en sik degerin satir payi (yuzde)       3.7     1.0  0.00 degeri 119 kez tekrarlaniyor
kesilme             en buyuk degerdeki kayit sayisi        20.0     5.0  45.00 m3 ust sinirinda 20 kayit birikmis
imkansiz birlesim   hane 0 iken tuketim > 0 satir         213.0     1.0  sifir kisilik hanede olculmus tuketim var
donem boslugu       donemler arasi satir acikligi          33.5    10.0  en seyrek donem 838, en yogunu 1260 satir
yinelenen kayit     ayni abone-donem ciftinin satiri        1.0     1.5  -
tanimsiz deger      negatif tuketim yazan satir             0.0     1.0  -

6 kural yuruldu, 4 sorun bulundu; hicbiri satir silmiyor

Kayıt katmanı bir modeldir ve neyi modellediği açıktır: saha cihazı 45,00 m³’ün üstünü okuyamaz ve tavanı yazar. Analistin eline geçen tablo budur; kesilmemiş değerler yalnız karşılaştırma için elde tutulur.

Dört bulgu dört ayrı türden. 0,00 değeri 3.199 satırın 119’unda, yani yüzde 3,7’sinde geçiyor; sürekli bir büyüklükte bir sayının bu sıklıkta tekrarlanması ölçümden gelmez, okunamayan sayaç için sıfır yazan bir kayıt uzlaşımından gelir. En büyük değerde 20 kayıt birikmiş: iki ondalıklı bir büyüklükte tam olarak aynı en büyük değerin yirmi kez çıkması tavanın imzasıdır. 213 satır sıfır kişilik hanede ölçülmüş tüketim taşıyor; hane_kisi alanı tek başına geçerli, tuketim_m3 alanı tek başına geçerli, birleşimleri geçersiz. Dönemler arasındaki satır açıklığı yüzde 33,5.

Eşiği aşmayan iki kural da bilgi veriyor. Aynı abone ile dönem çifti hiçbir satırda ikiden fazla geçmiyor ve negatif tüketim yazan satır yok. Bunlar aranıp bulunamamış sorunlardır ve aranmış olmaları yazılır; yazılmadığında okur, denetimin o soruyu hiç sormadığını varsayar.

Her Sorunun Oynattığı Sayı

# etki.py — her sorun icin ayni soru: hangi ozeti ne kadar oynatiyor. Hicbir
# satir silinmez; iki hesap yan yana basilir ve fark yazilir.
def kisi_basina(kayitlar, hane_sifiri_bir: bool) -> float:
    v = [k["tuketim_m3"] / (max(k["hane_kisi"], 1) if hane_sifiri_bir else k["hane_kisi"])
         for k in kayitlar if hane_sifiri_bir or k["hane_kisi"] > 0]
    return ort(v)


def donem_ort(kayitlar, donem: str, abone=None) -> float:
    return ort([k["tuketim_m3"] for k in kayitlar
                if k["donem"] == donem and (abone is None or k["abone_no"] in abone)])


tam = {a for a, c in Counter(k["abone_no"] for k in KAYIT).items() if c == len(DONEM)}
UST = round(0.01 * len(T))
ETKI = [
    ("yigilma", sik[1], "kume ortalamasi (m3)",
     ort(T), ort([t for t in T if t > 0]), "sifir yazilan satir okuma sayilmazsa"),
    ("kesilme", Counter(T)[max(T)], "en buyuk yuzde 1'in ortalamasi (m3)",
     ort(sorted(T)[-UST:]), ort(sorted(o["tuketim_m3"] for o in OKUMA)[-UST:]),
     "tavan olmasaydi (yalniz modelde bilinir)"),
    ("imkansiz birlesim", sum(1 for k in KAYIT if k["hane_kisi"] == 0),
     "kisi basina tuketim (m3)", kisi_basina(KAYIT, True), kisi_basina(KAYIT, False),
     "hane 0 satirlari disarida"),
    ("donem boslugu", len(KAYIT) - 3 * len(tam), "ilk donem ortalamasi (m3)",
     donem_ort(KAYIT, DONEM[0]), donem_ort(KAYIT, DONEM[0], tam),
     "yalniz uc donemi tam olan aboneler"),
]
e = hiza([20, 7])
print(e(["sorun", "satir"]) + "  " + "bozulan ozet".ljust(34)
      + "kayitta".rjust(10) + "sorunsuz".rjust(11) + "fark".rjust(9))
for ad, n, ozet, ham, duz, _ in ETKI:
    print(e([ad, n]) + "  " + ozet.ljust(34)
          + f"{ham:10.3f}{duz:11.3f}{duz - ham:+9.3f}")
print()
for ad, _, _, ham, duz, aciklama in ETKI:
    print(f"{ad:<20}{aciklama}; yuzde {100 * (duz - ham) / ham:+.1f}")
sorun                 satir  bozulan ozet                         kayitta   sorunsuz     fark
yigilma                 119  kume ortalamasi (m3)                  19.693     20.454   +0.761
kesilme                  20  en buyuk yuzde 1'in ortalamasi (m3)    44.663     46.597   +1.934
imkansiz birlesim       222  kisi basina tuketim (m3)              11.204     10.617   -0.586
donem boslugu           685  ilk donem ortalamasi (m3)             20.644     20.868   +0.224

yigilma             sifir yazilan satir okuma sayilmazsa; yuzde +3.9
kesilme             tavan olmasaydi (yalniz modelde bilinir); yuzde +4.3
imkansiz birlesim   hane 0 satirlari disarida; yuzde -5.2
donem boslugu       yalniz uc donemi tam olan aboneler; yuzde +1.1

Dört sorun dört ayrı özeti bozuyor ve hiçbiri diğerinin yerine geçmiyor. Sıfır yığılması küme ortalamasını tutuyor: 19,693 yerine, okuma sayılmayan satırlar dışarıda bırakılsa 20,454 olurdu, yani yüzde 3,9. Bu sayı raporlanan her bölge ortalamasının içinde de vardır, çünkü sıfırlar bütün bölgelere dağılmıştır.

Kesilmenin oynattığı sayı ortalama değil, üst uçtur. Küme ortalaması tavandan neredeyse hiç etkilenmez, ama en büyük yüzde 1’in ortalaması 44,663’te kalır; tavan olmasaydı 46,597 olurdu. Bu ikinci sayı yalnız modelde bilinir. Sahada kesilen değer kayıtta yoktur ve geri getirilemez; yapılabilecek tek şey “en yüksek 32 okumanın 20’si tavana dayanmıştır” cümlesini sayının yanına yazmaktır. Kesilmiş bir sütunda en büyük değer, çeyrekler üstü her özet ve üst uçla ilgili her karar, ölçülmüş değil kırpılmış bir sayıya dayanır.

İmkânsız birleşimde durum farklıdır: burada iki savunulabilir karar vardır ve ikisi de bir sayı üretir. Sıfır kişilik hane 1 sayılırsa kişi başına tüketim 11,204 m³, o 222 satır dışarıda bırakılırsa 10,617 m³ çıkar. Aradaki fark yüzde 5,2’dir ve hangisinin doğru olduğunu veri söylemez; söyleyen şey hanenin gerçekte kaç kişi olduğudur, o da kayıtta yoktur.

Dönem boşluğunun oynattığı sayı en küçüğüdür ama yönü öğreticidir. İlk dönem ortalaması kayıtta 20,644 m³’tür; yalnız üç dönemi tam olan aboneler alındığında 20,868 m³ olur. Aradaki 0,224 m³ bir davranış farkı değil, bir bileşim farkıdır: erken düşen aboneler ilk dönemde ortalamanın altında tüketmiştir. Dönemler arası düşüşü davranışa bağlayan bir cümle, bu farkı hesaba katmadan yazılamaz.

Keşfin Açtığı Borç

# borc.py — kesif asamasinda acilan kirilim sayisi: her hucre bakilabilir bir
# alt kume, her bakis sinamanin payini buyuten bir borctur.
ALAN = [("bolge", 5), ("donem", 3), ("basamak", 4), ("memnuniyet", 5),
        ("hane_kisi", 6)]
tekil = sum(k for _, k in ALAN)
ciftler = [(i, j) for i in range(len(ALAN)) for j in range(i + 1, len(ALAN))]
ikili = sum(ALAN[i][1] * ALAN[j][1] for i, j in ciftler)
kucuk, bos = 0, 0
for i, j in ciftler:
    a, b = ALAN[i][0], ALAN[j][0]
    say = Counter((k[a], k[b]) for k in KAYIT)
    bos += ALAN[i][1] * ALAN[j][1] - len(say)
    kucuk += sum(1 for v in say.values() if v < 30)
print(f"{len(ALAN)} kirilim alani, {len(ciftler)} alan cifti")
print(f"tekil kirilim hucresi : {tekil}")
print(f"ikili kirilim hucresi : {ikili}")
print(f"toplam bakilabilir alt kume: {tekil + ikili}")
print(f"bunlarin {kucuk} tanesi 30 satirdan az, {bos} tanesi bos")
print(f"kume 1 tablodur; kesif {tekil + ikili} ayri ozet cikarabilir")
5 kirilim alani, 10 alan cifti
tekil kirilim hucresi : 23
ikili kirilim hucresi : 209
toplam bakilabilir alt kume: 232
bunlarin 33 tanesi 30 satirdan az, 2 tanesi bos
kume 1 tablodur; kesif 232 ayri ozet cikarabilir

Beş kırılım alanı tek başına 23 hücre açıyor, ikili bileşimleri 209 hücre daha. Toplam 232 alt küme, hepsi aynı tablonun içinden çıkıyor ve her biri için bir ortalama, bir oran ya da bir fark hesaplanabilir. Bunların 33’ü 30 satırdan azdır ve küçük hücrede pay büyür: yirmi satırlık bir alt kümenin ortalaması, tek bir kaydın gelip gitmesiyle belirgin biçimde oynar.

Bu sayı bir kusur değil, keşfin doğasıdır. Keşif aşaması tam da bu hücreleri gezmek, hangisinin dikkat çektiğine bakmak ve oradan soru üretmek için vardır. Ama gezilen her hücre, sonradan yapılacak sınamanın payına eklenen bir borçtur — çünkü sınanacak soru, 232 hücrenin arasından en dikkat çekeni olduğu için seçilmiştir.

Özet

  • Altı kurallık tarama dört sorun buldu: yığılma (0,00 değeri satırların yüzde 3,7’sinde), kesilme (45,00 m³’te 20 kayıt), imkânsız birleşim (213 satır) ve dönem boşluğu (yüzde 33,5).
  • Yığılma küme ortalamasını 19,693’te tutar; sıfırlar okuma sayılmazsa 20,454 olur, yani yüzde 3,9’luk bir açıklık her bölge ortalamasının içindedir.
  • Kesilme ortalamayı neredeyse hiç oynatmaz ama en büyük yüzde 1’in ortalamasını 46,597 yerine 44,663 gösterir ve onarılamaz; sayılabilecek tek şey kaç kaydın tavana dayandığıdır.
  • İmkânsız birleşim iki savunulabilir karar bırakır: kişi başına tüketim 11,204 ya da 10,617 m³, aradaki fark yüzde 5,2.
  • Dönem boşluğu ilk dönem ortalamasını 20,644’ten 20,868’e taşır; bu bir davranış değil bir bileşim farkıdır.

Sonraki Adım

Bu konu beş derste bir şey yaptı: kümeyi tanıdı ve soru üretti. Bölgeler arasındaki 4,463 m³’lük farkın karıştırmayla üretilemediği görüldü, doğu dağılımının çarpık olduğu ve elenmeyen çit dışı 30 satırın ortalamayı 0,480 m³ oynattığı ölçüldü, aynı katsayıyı veren üç ayrı ilişkinin dilim ortalamalarıyla ayrıştığı gösterildi, bağımsız yirmi sütunda 190 çiftin 12’sinin eşiği aştığı sayıldı ve dört kayıt sorununun dört ayrı özeti bozduğu yazıldı.

Ortak eksik şudur: bu soruların hiçbiri sınanmadı. Keşif bir farkın var göründüğünü söyler, o farkın raporlanmaya değer olup olmadığını söylemez; bir özetin çarpık olduğunu söyler, hangi özetin raporlanacağına karar vermez. Üstelik keşfin kendisi bir borç bıraktı: 232 kırılım hücresi gezildi ve sınanacak soru bunların arasından seçildi. Sonraki konu, Uygulamalı İstatistik, bu borcu ödemekle başlar — önce raporlanacak özetin seçimini ve o seçimin oynattığı sayıyı ölçer, sonra farkın kendi aralığını ve sınamasını kurar.

İ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