Ders 09 / 18
Gösterge Tablosu Tasarımı
Aynı on iki ölçüt üç düzende kodlanır ve her düzende kaçının bir bakışta geri okunduğu sayılır: eklenme sırasına dizilmiş düzende 1, her ölçüte bir gösterim verildiğinde 2, karara göre bölünmüş düzende 9 ölçüt geri okunur. Desteklenen karar sayısı sırasıyla 0, 0 ve 3'tür; bakış bütçesi on ikiye çıkarıldığında ilk iki düzen 2 ve 6 ölçüt geri okutur ama yine hiçbir kararı desteklemez. Uzunluk kanalında ayrı ayrı yüzde 1,50 ve yüzde 3,08 hatayla geri okunan iki oranın arasındaki 1,861'lik fark yüzde 34,3 hatayla 2,500 okunur.
İçindekiler
Sekiz derste tek bir gösterim doğru kuruldu: değer bir kanala kodlandı, okuyucu onu geri okudu, aradaki hata sayıldı. Bir rapor tek bir gösterimden oluşmuyor. Karar verecek kişi bir bakışta birden çok sayıyla karşılaşıyor; her sayı doğru kodlanmış olabilir ve sayfa yine de hiçbir kararı desteklemeyebilir.
Bu dersin ölçüsü iki sayıdır: bir bakışta geri okunabilen ölçüt sayısı ve desteklenen karar sayısı. Buradaki gösterge tablosu bir işletim aracı değildir. DevOps ve Gözlemlenebilirlik kursunun gösterge tablosu dersi nöbetçinin ekranını ele almış, “panel bir soruya yanıt veriyor mu” diye denetlemişti; uyarı kuralı ve eşik tasarımı orada kuruldu ve burada tekrarlanmaz. Soru burada başkadır: sayı kanalından geri okunabiliyor mu ve onu karara çevirecek bir dayanağı var mı.
- RP1. Küme K03’ten devralınır ve kurgudur: 3.199 satırlık okuma tablosu, 1.329 abone, üç dönem, beş bölge, tarife basamakları 10/25/40 m³. Tohum koda yazılıdır.
- RP2. Rapor da kurgudur: on iki ölçüt ve üç karar, ölçüm ağını yürüten birimin dönem sonu raporundan gelir.
- RP3. Bir bakış beş göz duraktır. Bu bir karardır; aynı denetim üç, beş, sekiz ve on iki bütçesiyle yeniden koşturulur.
- RP4. Okuma çözünürlüğü çözücüde yazılıdır: metin çubuğu tam hücre sayılır (20 hücre), renk basamağı ancak basamağın orta değerine çözülür (5 basamak), çıplak sayı iki ondalıkla basılır. Kanal büyüklüğü, etiket işareti taşır.
- RP5. Hata eşiği yüzde 5’tir; gerekçesi raporun en küçük karşılaştırmasının bu büyüklükte olmasıdır. Ölçek tavanı da bir karardır ve ölçüt tanımıyla birlikte yazılır.
- RP6. Bir ölçüt üç koşul birden sağlanırsa geri okunmuş sayılır: bakış bütçesinin içinde olmak, hatası eşiğin altında kalmak, bir dayanağı olmak.
Ölçüt, Kanal ve Dayanak
On iki ölçütün tamamı kurgu kümeden hesaplanır. Üçü K05’ten gelir: doğu ortalaması 24,674 m³, kuzeyle farkı 4,463 m³, hiç okuması olmayan 69 abone.
# rapor.py — MODELDIR. K03'un kurgu kumesi ayni tohumla uretilir; uzerine kurgu # bir donem sonu raporu kurulur. Her olcut bir kanala kodlanir, okuyucu geri okur. import math TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26), ("bati", 0.14, 14), ("merkez", 0.18, 23)] 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, ELENEN = [], [] for i in range(HAM): r = uretec(TOHUM + i) b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])] ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05]) ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17]) (ELENEN if r() < 0.046 else ABONE).append( {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2]}) GECERLI = {k["abone_no"] for k 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"] in GECERLI: OKUMA.setdefault(k["abone_no"], {})[d + 1] = t r() def okumalar(donem, bolge=None): return [OKUMA[k["abone_no"]][donem] for k in ABONE if (bolge is None or k["bolge"] == bolge) and donem in OKUMA.get(k["abone_no"], {})] def eksik_oran(donem, bolge=None): kume = [k for k in ABONE if bolge is None or k["bolge"] == bolge] return sum(1 for k in kume if donem not in OKUMA.get(k["abone_no"], {})) / len(kume) d2, d3 = okumalar(2), okumalar(3) sirali = sorted(d3) tum = {b[0]: sum((okumalar(d, b[0]) for d in (1, 2, 3)), []) for b in BOLGE} ort = {b: sum(v) / len(v) for b, v in tum.items()} eksik = {b[0]: eksik_oran(3, b[0]) for b in BOLGE} en_eksik = max(eksik, key=lambda b: eksik[b]) # (kod, ad, deger, birim, olcek tavani). Tavan bir karardir; kanal ona gore kodlar. OLCUT = [ ("O1", "donem 3 toplam tuketim", sum(d3), "m3", 20000.0), ("O2", "abone basina ortalama", sum(d3) / len(d3), "m3", 40.0), ("O3", "ortanca tuketim", (sirali[418] + sirali[419]) / 2, "m3", 40.0), ("O4", "eksik okuma orani", eksik_oran(3) * 100, "%", 50.0), ("O5", "sifir okuma sayisi", sum(1 for v in d3 if v == 0.0), "adet", 50.0), ("O6", "40 m3 ustu abone orani", sum(1 for v in d3 if v > 40) / len(d3) * 100, "%", 5.0), ("O7", "en yuksek bolge ortalamasi", max(ort.values()), "m3", 40.0), ("O8", "dogu-kuzey ortalama farki", ort["dogu"] - ort["kuzey"], "m3", 10.0), ("O9", "donem 2-3 degisim orani", (sum(d3) / len(d3) - sum(d2) / len(d2)) / (sum(d2) / len(d2)) * 100, "%", 20.0), ("O10", "10-25 basamagindaki abone orani", sum(1 for v in d3 if 10 <= v < 25) / len(d3) * 100, "%", 100.0), ("O11", "hic okumasi olmayan abone", sum(1 for k in ABONE if not OKUMA.get(k["abone_no"])), "adet", 100.0), ("O12", "en yuksek eksik okuma orani (" + en_eksik + ")", eksik[en_eksik] * 100, "%", 50.0), ] AD = {o[0]: o[1] for o in OLCUT} DEG = {o[0]: o[2] for o in OLCUT} BIRIM = {o[0]: o[3] for o in OLCUT} TAVAN = {o[0]: o[4] for o in OLCUT} print(f"kurgu kume (tohum {TOHUM}): {len(ABONE)} abone, " f"{sum(len(v) for v in OKUMA.values())} okuma, {len(BOLGE)} bolge") print(f"rapor donem 3 uzerine kurulur: {len(d3)} okuma\n") for k, ad, d, br, tv in OLCUT: print(f" {k:<4} {ad:<38} {d:>10.3f} {br}")
kurgu kume (tohum 20260218): 1329 abone, 3199 okuma, 5 bolge rapor donem 3 uzerine kurulur: 838 okuma O1 donem 3 toplam tuketim 15353.190 m3 O2 abone basina ortalama 18.321 m3 O3 ortanca tuketim 17.845 m3 O4 eksik okuma orani 36.945 % O5 sifir okuma sayisi 28.000 adet O6 40 m3 ustu abone orani 0.955 % O7 en yuksek bolge ortalamasi 24.674 m3 O8 dogu-kuzey ortalama farki 4.463 m3 O9 donem 2-3 degisim orani -6.910 % O10 10-25 basamagindaki abone orani 74.105 % O11 hic okumasi olmayan abone 69.000 adet O12 en yuksek eksik okuma orani (bati) 38.806 %
Aynı Sayının Üç Kanalı
Eşiğin gerekçesi de bu listeden çıkar: raporun taşıdığı en küçük karşılaştırma, küme geneli eksik okuma oranı ile en yüksek bölgenin oranı arasındadır.
# Her kanal bir kodlayici ve bir cozucu ciftidir; okuma cozunurlugu cozucude yazilidir. HUCRE, BASAMAK, ESIK = 20, 5, 0.05 def kodla(kanal, x, tavan): if kanal == "sayi": return round(abs(x), 2) if kanal == "uzunluk": return max(0, min(HUCRE, int(abs(x) / tavan * HUCRE + 0.5))) return max(0, min(BASAMAK - 1, int(abs(x) / tavan * BASAMAK))) def coz(kanal, kod, tavan): if kanal == "sayi": return kod if kanal == "uzunluk": return kod * tavan / HUCRE return (kod + 0.5) * tavan / BASAMAK def hata(kanal, k): x, tavan = DEG[k], TAVAN[k] return abs(coz(kanal, kodla(kanal, x, tavan), tavan) - abs(x)) / abs(x) en_kucuk = (DEG["O12"] - DEG["O4"]) / DEG["O4"] print(f"raporun tasidigi en kucuk karsilastirma: kume geneli eksik okuma orani " f"{DEG['O4']:.3f} ile\n{AD['O12']} {DEG['O12']:.3f} arasinda yuzde " f"{en_kucuk * 100:.1f}. Geri okuma hatasi esigi bu yuzden yuzde {ESIK * 100:.0f}.\n") print(f"{'olcut':<6}{'kaynaktaki sayi':>16} {'kanal':<9}{'kodlanan':>9}" f"{'geri okunan':>13}{'hata %':>9}") for k in ("O9", "O12"): for kanal in ("sayi", "uzunluk", "renk"): print(f"{k:<6}{DEG[k]:>16.3f} {kanal:<9}{kodla(kanal, DEG[k], TAVAN[k]):>9}" f"{coz(kanal, kodla(kanal, DEG[k], TAVAN[k]), TAVAN[k]):>13.3f}" f"{hata(kanal, k) * 100:>9.2f}")
raporun tasidigi en kucuk karsilastirma: kume geneli eksik okuma orani 36.945 ile en yuksek eksik okuma orani (bati) 38.806 arasinda yuzde 5.0. Geri okuma hatasi esigi bu yuzden yuzde 5. olcut kaynaktaki sayi kanal kodlanan geri okunan hata % O9 -6.910 sayi 6.91 6.910 0.00 O9 -6.910 uzunluk 7 7.000 1.31 O9 -6.910 renk 1 6.000 13.17 O12 38.806 sayi 38.81 38.810 0.01 O12 38.806 uzunluk 16 40.000 3.08 O12 38.806 renk 3 35.000 9.81
Çıplak sayının hatası sıfıra yakındır ve bu onu en iyi kanal yapmaz: hatasız okunan 38,81’in iyi mi kötü mü olduğu kaynağın kendisinden okunamaz. Renk basamağı ise beş kovaya böldüğü için iki ölçütte de eşiği aşıyor.
Üç Düzen, İki Sayı
Birinci düzen ölçütlerin eklenme sırasını korur ve hepsini çıplak sayı basar. İkincisi her ölçüte bir gösterim ve bir dayanak verir, sırayı değiştirmez. Üçüncüsü kararlara göre bölümlere ayırır.
# RP3: bir bakis bes gozduraktir; asagida dort butce icin ayni denetim kosar. BUTCE = 5 KARAR = [("ek okuma turu hangi bolgeye", ("O4", "O12", "O8")), ("tarife basamagi siniri gozden gecirilsin mi", ("O3", "O6", "O10")), ("donem 3 toplamasi yenilensin mi", ("O5", "O9", "O11"))] SIRA = ["O1", "O2", "O9", "O4", "O5", "O3", "O6", "O7", "O8", "O10", "O11", "O12"] CESIT = {"O1": "uzunluk", "O2": "renk", "O9": "renk", "O4": "renk", "O5": "uzunluk", "O3": "uzunluk", "O6": "renk", "O7": "uzunluk", "O8": "sayi", "O10": "renk", "O11": "uzunluk", "O12": "renk"} DUZEN = { "eklenme sirasi": [[(k, "sayi", k in ("O8", "O9")) for k in SIRA]], "her olcute bir gosterim": [[(k, CESIT[k], True) for k in SIRA]], "karara gore bolunmus": [[(k, "sayi" if k == "O8" else "uzunluk", True) for k in kk] for _, kk in KARAR], } def denetle(bolumler, butce=BUTCE): """Bir olcut ancak uc kosul birden saglanirsa geri okunmus sayilir: bakis butcesinin icinde olmak, hatasi esigin altinda kalmak, dayanagi olmak.""" okunan = [k for b in bolumler for k, kanal, dayanak in b[:butce] if dayanak and hata(kanal, k) <= ESIK] return okunan, [ad for ad, kk in KARAR if all(k in okunan for k in kk)] print(f"{len(OLCUT)} olcut, {len(KARAR)} karar, hata esigi yuzde {ESIK * 100:.0f}. " f"Son dort sutun: geri okunan olcut / desteklenen karar.\n") print(f"{'duzen':<24}{'gosterilen':>11}{'bakis':>7}" + "".join(f"{'butce ' + str(b):>10}" for b in (3, 5, 8, 12))) for ad, bol in DUZEN.items(): print(f"{ad:<24}{sum(len(b) for b in bol):>11}{len(bol):>7}" + "".join( f"{'/'.join(str(len(x)) for x in denetle(bol, b)):>10}" for b in (3, 5, 8, 12)))
12 olcut, 3 karar, hata esigi yuzde 5. Son dort sutun: geri okunan olcut / desteklenen karar. duzen gosterilen bakis butce 3 butce 5 butce 8 butce 12 eklenme sirasi 12 1 1/0 1/0 1/0 2/0 her olcute bir gosterim 12 1 1/0 2/0 4/0 6/0 karara gore bolunmus 9 3 9/3 9/3 9/3 9/3
Beş göz duraklık bütçede üç düzen sırasıyla 1, 2 ve 9 ölçüt geri okutuyor; desteklenen karar sayısı 0, 0 ve 3.
Asıl bilgi son sütunda. Bütçe on ikiye çıkarıldığında, yani okuyucunun sayfayı baştan sona taradığı varsayıldığında bile ilk iki düzen hiçbir kararı desteklemiyor. Eksik olan yer değil birlikteliktir: bir karar üç ölçütün aynı anda dayanaklı ve eşik altı olmasını ister, ilk iki düzende bu üçlü hiçbir bütçede tamamlanmaz. On iki ölçütün altısını geri okutan bir sayfa sıfır karar destekleyebilir. Üçüncü düzenin bedeli de sayılıdır: dokuz ölçüt gösterir, üçünü dışarıda bırakır ve bir yerine üç bakış ister.
Okuyucunun Gördüğü Sayfa
# Okuyucunun gordugu sey basilir; "<" geri okunmus olcutu isaretler. def cizgi(k, kanal): if kanal == "uzunluk": n = kodla("uzunluk", DEG[k], TAVAN[k]) return "#" * n + "." * (HUCRE - n) if kanal == "renk": return f"basamak {kodla('renk', DEG[k], TAVAN[k]) + 1}/{BASAMAK}".ljust(HUCRE) return f"{DEG[k]:.2f} {BIRIM[k]}".ljust(HUCRE) def bas(baslik, bolumler, adlar=None, kes=None): print(f"--- {baslik} " + "-" * (52 - len(baslik))) for i, b in enumerate(bolumler): if adlar: print(f" [karar: {adlar[i]}]") for j, (k, kanal, dayanak) in enumerate(b[:kes] if kes else b): im = " <" if j < BUTCE and dayanak and hata(kanal, k) <= ESIK else "" print(f" {j + 1:>2}. {AD[k]:<36}{cizgi(k, kanal)}" f"{' dayanak var' if dayanak else ' dayanak yok'}{im}") bas("duzen 1 — eklenme sirasi (bakisa giren bes satir)", DUZEN["eklenme sirasi"], kes=BUTCE) print() bas("duzen 3 — karara gore bolunmus", DUZEN["karara gore bolunmus"], [k[0] for k in KARAR]) gercek = DEG["O12"] - DEG["O4"] okunan = coz("uzunluk", kodla("uzunluk", DEG["O12"], TAVAN["O12"]), TAVAN["O12"]) - \ coz("uzunluk", kodla("uzunluk", DEG["O4"], TAVAN["O4"]), TAVAN["O4"]) print(f"\nO4 hatasi yuzde {hata('uzunluk', 'O4') * 100:.2f}, " f"O12 hatasi yuzde {hata('uzunluk', 'O12') * 100:.2f} — ikisi de esigin altinda.") print(f"aradaki fark: kaynakta {gercek:.3f}, geri okunan {okunan:.3f}, " f"farkin hatasi yuzde {abs(okunan - gercek) / gercek * 100:.1f}")
--- duzen 1 — eklenme sirasi (bakisa giren bes satir) --- 1. donem 3 toplam tuketim 15353.19 m3 dayanak yok 2. abone basina ortalama 18.32 m3 dayanak yok 3. donem 2-3 degisim orani -6.91 % dayanak var < 4. eksik okuma orani 36.95 % dayanak yok 5. sifir okuma sayisi 28.00 adet dayanak yok --- duzen 3 — karara gore bolunmus ---------------------- [karar: ek okuma turu hangi bolgeye] 1. eksik okuma orani ###############..... dayanak var < 2. en yuksek eksik okuma orani (bati) ################.... dayanak var < 3. dogu-kuzey ortalama farki 4.46 m3 dayanak var < [karar: tarife basamagi siniri gozden gecirilsin mi] 1. ortanca tuketim #########........... dayanak var < 2. 40 m3 ustu abone orani ####................ dayanak var < 3. 10-25 basamagindaki abone orani ###############..... dayanak var < [karar: donem 3 toplamasi yenilensin mi] 1. sifir okuma sayisi ###########......... dayanak var < 2. donem 2-3 degisim orani #######............. dayanak var < 3. hic okumasi olmayan abone ##############...... dayanak var < O4 hatasi yuzde 1.50, O12 hatasi yuzde 3.08 — ikisi de esigin altinda. aradaki fark: kaynakta 1.861, geri okunan 2.500, farkin hatasi yuzde 34.3
Son iki satır düzenin kapatmadığı açığı gösteriyor. Birinci bölümdeki iki oran uzunluk kanalında ayrı ayrı yüzde 1,50 ve yüzde 3,08 hatayla, ikisi de eşiğin çok altında geri okunuyor. Ama okuyucunun o bölümde yaptığı iş tek tek değerleri okumak değil aralarındaki farkı okumaktır. Kaynakta 1,861 puan olan fark 2,500 okunuyor: yüzde 34,3 hata. İki küçük hata aynı yöne düşmediği için farkta büyüyor.
Bu, eşiğin yanlış seçildiğini değil ölçülen şeyin değiştiğini gösterir. Bir karar bir farka dayanıyorsa geri okuma hatası farkın üzerinde ölçülmelidir: raporun en küçük karşılaştırması yüzde 5 iken kanalın farkta ürettiği yüzde 34,3 o karşılaştırmayı çevirecek büyüklüktedir.
Özet
- Bir ölçüt üç koşul birden sağlanırsa geri okunmuş sayılır: bakış bütçesinin içinde olmak, geri okuma hatasının eşiğin altında kalması, bir dayanağının bulunması.
- Aynı on iki ölçüt beş göz duraklık bakışta üç düzende sırasıyla 1, 2 ve 9 kez geri okunuyor; desteklenen karar sayısı 0, 0 ve 3’tür. Bütçe on ikiye çıkarıldığında ilk iki düzen 2 ve 6 ölçüt geri okutur ama yine hiçbir kararı desteklemez.
- Karara göre bölünmüş düzenin bedeli sayılıdır: dokuz ölçüt gösterir, üçünü dışarıda bırakır ve bir yerine üç bakış ister. Çıplak sayı hatasız okunur ama dayanaksız olduğu için karar beslemez.
- Tek tek yüzde 1,50 ve yüzde 3,08 hatayla okunan iki oranın arasındaki 1,861’lik fark 2,500 okunur; farkın hatası yüzde 34,3’tür.
Sonraki Adım
Bu ders ölçütleri verilmiş kabul etti ve yalnız sayfada nasıl durduklarını ölçtü. Ölçütün kendisi sorgulanmadı: eksik okuma oranı neyin oranıdır, paydasında kim vardır, bir okuma hangi anda okuma sayılır. Bir ölçüt karar üretmeye başladığı andan itibaren ölçtüğü şeyi oynatmadan da oynatılabilir hâle gelir. Sonraki ders bunu sayar: aynı eksik okuma oranı, ölçüm ağında hiçbir şey değişmeden kaç yoldan oynatılabiliyor, her yol ölçütü ne kadar oynatıyor ve ölçüt yeniden tanımlandığında bu yolların kaçı kapanıyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.