Ders 08 / 09
Veri Kalitesi Boyutları
Dört kalite boyutunun her biri bir sayı verir: 46 kayıt fiziksel olarak imkânsız okuma taşır, 200 kayıtta zorunlu alan boştur, 104 kayıtta basamak alanı okumayla çelişir, 482 kayıt 90 günden eskidir ve dört kuralı birden geçen 730 kayıt kalır. Eşik sıkılaştıkça 1.400 satır 422'ye iner ve rapor edilen ortalama 24,70'ten 20,83 m³'e düşerken modelin doğrusunu 21,31'de bir kez geçer; elenen satırlar rastgele değildir, en üst tarife basamağının yüzde 88,2'si elenir.
İçindekiler
Bir önceki ders kaynağın hangi kayıtları dışarıda bıraktığını ölçtü ve içeri alınanları sorgusuz kabul etti. Bu ders o varsayımı kaldırır: kayda giren satırın kendisi de kusurlu olabilir. Bir okuma fiziksel olarak imkânsız olabilir, bir alan boş kalabilir, iki alan birbiriyle çelişebilir, bir kayıt aylar önce yazılmış olabilir.
Bu dört sorunun ortak adı veri kalitesidir ve tek bir sayıya indirilemez. Her biri ayrı bir kural, ayrı bir eşik ve ayrı bir sayı ister. Dersin ölçüsü iki katmanlıdır: her boyut için bir sayı, ve eşik değişince kaç satırın elendiği. İkinci katman birinciden daha önemlidir, çünkü temizlenmiş bir küme daha küçük ve daha farklı bir kümedir.
- VY15. Küme, önceki derslerin 1.400 satırlık abone kaydıdır ve bu derste kusurlar eklenir: bozuk okuma, boş alan ve bayat basamak alanı. Kusurlar taban alanlardan sonra çizilir, taban küme değişmez. Küme kurgudur; modelin doğrusu 21,31 m³’tür.
- VY16. Doğruluk (accuracy) okumanın gerçeği verip vermediğidir; burada yalnız fiziksel olarak imkânsız değerler yakalanabilir. Eksiksizlik (completeness) zorunlu alanların dolu olmasıdır.
- VY17. Tutarlılık (consistency) iki alanın birbiriyle uyuşmasıdır: kayıtta ayrıca saklanan tarife basamağı, okumadan hesaplanan basamakla aynı olmalıdır. Güncellik (timeliness) son okumanın üzerinden geçen gündür.
- VY18. Doğruluk eşiği bir sayaç için aylık 120 m³’tür; bu değer modele girdi olarak verilmiştir. Kayan noktalı okuma eşitlikle değil eşikle sınanır, çünkü ölçüm iki ondalık basamakta kesilir ve bir üst sınırla karşılaştırmanın sonucu eşitliğe bağlı olmamalıdır.
Dört Boyut, Dört Sayı
// kalite.mjs — ayni kume, bu kez dort kalite boyutu olculur. MODELDIR: // bozulmalar taban alanlardan SONRA cizilir, taban kume degismez. export const TOHUM = 20260218, KAYIT = 1400, TARIFE = [10, 25, 40], UST_SINIR = 120; const karistir = (x) => { x = Math.imul(x ^ (x >>> 16), 2246822507); x = Math.imul(x ^ (x >>> 13), 3266489909); return (x ^ (x >>> 16)) >>> 0; }; const uretec = (t) => { let s = karistir(t); return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; }; const ayrik = (u, w) => { let t = 0; for (let i = 0; i < w.length; i++) { t += w[i]; if (u < t) return i; } return w.length - 1; }; export const BOLGE = [ { ad: "kuzey", pay: 0.28, taban: 21, mem: [0.05, 0.10, 0.25, 0.40, 0.20] }, { ad: "guney", pay: 0.22, taban: 17, mem: [0.02, 0.08, 0.30, 0.45, 0.15] }, { ad: "dogu", pay: 0.18, taban: 26, mem: [0.20, 0.08, 0.05, 0.12, 0.55] }, { ad: "bati", pay: 0.14, taban: 14, mem: [0.10, 0.15, 0.25, 0.30, 0.20] }, { ad: "merkez", pay: 0.18, taban: 23, mem: [0.06, 0.12, 0.28, 0.34, 0.20] }, ]; export const basamakla = (v) => (v < TARIFE[0] ? 1 : v < TARIFE[1] ? 2 : v < TARIFE[2] ? 3 : 4); export const KAYITLAR = Array.from({ length: KAYIT }, (_, i) => { const r = uretec(TOHUM + i); const b = BOLGE[ayrik(r(), BOLGE.map((x) => x.pay))]; const t = Math.max(1.2, b.taban * Math.exp((r() + r() + r() - 1.5) * 0.62)); const gercek = Math.round(t * 100) / 100; const sayac = ayrik(r(), [0.62, 0.24, 0.10, 0.04]) + 1; const ziyaret = ayrik(r(), [0.38, 0.32, 0.16, 0.08, 0.04, 0.02]); const memnuniyet = ayrik(r(), b.mem) + 1; const sicaklik = Math.round((6 + r() * 22) * 10) / 10; const gecen = Math.floor(Math.pow(r(), 1.9) * 210); // Bozulmalar. Eksik alan ve bayat basamak olasiligi tuketimle artar: // yuksek tuketen sayaclar zor erisilen noktalarda ve daha sik basamak degistirir. const hata = r() < 0.035, isaret = r() < 0.4; const olculen = hata ? (isaret ? -gercek : gercek * 10) : gercek; const bolgeBos = r() < 0.03; const memBos = r() < 0.04 + 0.0035 * gercek; const bayat = r() < 0.05 + 0.0022 * gercek; return { abone_no: 10001 + i, bolge: bolgeBos ? null : b.ad, tuketim_gercek: gercek, tuketim_m3: olculen, bozuk: hata, sayac_sayisi: sayac, ziyaret_sayisi: ziyaret, memnuniyet: memBos ? null : memnuniyet, sicaklik_c: sicaklik, gecen_gun: gecen, basamak_alani: bayat ? basamakla(gercek * 0.8) : basamakla(gercek) }; }); export const ort = (a) => a.reduce((x, y) => x + y, 0) / a.length; export const GERCEK = ort(KAYITLAR.map((k) => k.tuketim_gercek)); // Dort boyut, dort kural. Kayan noktali karsilastirma esitlikle degil esikle // yapilir: UST_SINIR bir sayac icin aylik ust sinirdir, uzerindeki okuma fiziksel // olarak mumkun degildir. export const dogru = (k) => k.tuketim_m3 > 0 && k.tuketim_m3 < UST_SINIR * k.sayac_sayisi; export const eksiksiz = (k) => k.bolge !== null && k.memnuniyet !== null; export const tutarli = (k) => k.basamak_alani === basamakla(k.tuketim_m3); export const guncel = (k, gun) => k.gecen_gun <= gun; if (import.meta.url === `file://${process.argv[1]}`) { const y = (h) => String(h[0]).padEnd(14) + String(h[1]).padEnd(34) + h.slice(2).map((v) => String(v).padStart(10)).join(""); console.log(`model (tohum ${TOHUM}): ${KAYIT} kayit; modelin dogrusu ` + `ortalama ${GERCEK.toFixed(2)} m3, ham ortalama ` + `${ort(KAYITLAR.map((k) => k.tuketim_m3)).toFixed(2)} m3`); console.log("\n" + y(["boyut", "kural", "ihlal", "oran"])); const olcum = [ ["dogruluk", `okuma 0 ile ${UST_SINIR} x sayac arasinda`, KAYITLAR.filter((k) => !dogru(k)).length], ["eksiksizlik", "bolge ve memnuniyet dolu", KAYITLAR.filter((k) => !eksiksiz(k)).length], ["tutarlilik", "basamak alani okumayla uyusuyor", KAYITLAR.filter((k) => !tutarli(k)).length], ["guncellik", "son okuma 90 gunden yeni", KAYITLAR.filter((k) => !guncel(k, 90)).length], ]; for (const [ad, kural, n] of olcum) { console.log(y([ad, kural, n, `%${(100 * n / KAYIT).toFixed(1)}`])); } const hicbiri = KAYITLAR.filter((k) => dogru(k) && eksiksiz(k) && tutarli(k) && guncel(k, 90)).length; const bozuk = KAYITLAR.filter((k) => k.bozuk).length; console.log(`\nmodelde bozulan okuma ${bozuk}, dogruluk kuralinin yakaladigi ` + `${KAYITLAR.filter((k) => !dogru(k)).length}`); console.log(`dort kuralin dordunu birden gecen kayit ${hicbiri}, ` + `yuzde ${(100 * hicbiri / KAYIT).toFixed(1)}`); const y2 = (h) => String(h[0]).padEnd(16) + h.slice(1).map((v) => String(v).padStart(11)).join(""); console.log("\n" + y2(["alan", "dolu", "bos", "doluluk"])); for (const [ad, f] of [["bolge", (k) => k.bolge], ["memnuniyet", (k) => k.memnuniyet], ["tuketim_m3", (k) => k.tuketim_m3], ["gecen_gun", (k) => k.gecen_gun]]) { const dolu = KAYITLAR.filter((k) => f(k) !== null).length; console.log(y2([ad, dolu, KAYIT - dolu, `%${(100 * dolu / KAYIT).toFixed(1)}`])); } }
model (tohum 20260218): 1400 kayit; modelin dogrusu ortalama 21.31 m3, ham ortalama 24.70 m3 boyut kural ihlal oran dogruluk okuma 0 ile 120 x sayac arasinda 46 %3.3 eksiksizlik bolge ve memnuniyet dolu 200 %14.3 tutarlilik basamak alani okumayla uyusuyor 104 %7.4 guncellik son okuma 90 gunden yeni 482 %34.4 modelde bozulan okuma 58, dogruluk kuralinin yakaladigi 46 dort kuralin dordunu birden gecen kayit 730, yuzde 52.1 alan dolu bos doluluk bolge 1357 43 %96.9 memnuniyet 1232 168 %88.0 tuketim_m3 1400 0 %100.0 gecen_gun 1400 0 %100.0
Dört boyut dört ayrı sayı verdi ve hiçbiri diğerinin yerine geçmez. En büyük ihlal güncellikte — 482 kayıt, yüzde 34,4 — ve bu sayı bir veri hatası değildir: kayıtlar doğrudur, yalnız eskidir. En küçük ihlal doğruluktadır ama etkisi en büyüğüdür: 46 bozuk okuma ham ortalamayı 21,31’den 24,70 m³’e çıkarır. İhlal sayısı ile ihlalin sayıya etkisi aynı yönde gitmez; bir kalite raporu ihlal saymakla bitmez, ihlalin rapor edilen sayıyı ne kadar oynattığı da yazılır.
Doğruluk satırının altındaki not asıl sınırı gösteriyor. Modelde 58 okuma bozulmuştur, kural 46’sını yakalar. Kaçan 12 kayıt, birden çok sayacı olan hanelerdedir: eşik sayaç başına 120 m³ olduğu için iki sayaçlı bir hanede 210 m³’lük bozuk bir okuma sınırın altında kalır ve geçerli görünür. Bir doğruluk kuralı yalnız imkânsızı yakalar; yanlış ama mümkün olan değer hiçbir kuralla ayırt edilemez. Kaçan 12 kaydı yakalamanın tek yolu ikinci bir kaynakla karşılaştırmaktır, ve önceki ders o kaynağın da kendi yanlılığını taşıdığını gösterdi.
Alan doluluk tablosu eksiksizliğin alan başına ölçüldüğünü söylüyor. bolge alanı yüzde 96,9,
memnuniyet yüzde 88,0 doludur; tuketim_m3 hiç boş değildir. Kayıt başına bakıldığında dört
kuralın dördünü birden geçen 730 satır kalır — kümenin yalnız yüzde 52,1’i. Boyutlar ayrı ayrı
ölçülür ama birlikte uygulanır ve kesişim her zaman en küçük boyuttan da küçüktür.
Eşik Sıkılaştıkça
// esik.mjs — kalite esigi siklastikca kac satir eleniyor ve rapor edilen sayi // hangi yone gidiyor. Her boyut once tek basina, sonra birlikte uygulanir. import { KAYITLAR, KAYIT, GERCEK, ort, dogru, eksiksiz, tutarli, guncel, basamakla } from "./kalite.mjs"; const y = (h) => String(h[0]).padEnd(26) + h.slice(1).map((v) => String(v).padStart(10)).join(""); const yaz = (ad, l) => { const o = ort(l.map((k) => k.tuketim_m3)); console.log(y([ad, l.length, `%${(100 * l.length / KAYIT).toFixed(1)}`, o.toFixed(2), (o - GERCEK >= 0 ? "+" : "") + (o - GERCEK).toFixed(2)])); }; console.log(`modelin dogrusu ${GERCEK.toFixed(2)} m3; asagidaki her ortalama ` + `olculen alandan hesaplanir`); console.log("\nher boyut tek basina"); console.log(y(["kural", "kalan", "kalan %", "ortalama", "sapma"])); yaz("filtre yok", KAYITLAR); yaz("yalniz dogruluk", KAYITLAR.filter(dogru)); yaz("yalniz eksiksizlik", KAYITLAR.filter(eksiksiz)); yaz("yalniz tutarlilik", KAYITLAR.filter(tutarli)); yaz("yalniz guncellik (90 gun)", KAYITLAR.filter((k) => guncel(k, 90))); const PROFIL = [ ["P0 filtre yok", () => true], ["P1 dogruluk", (k) => dogru(k)], ["P2 + eksiksizlik, 90 gun", (k) => dogru(k) && eksiksiz(k) && guncel(k, 90)], ["P3 + tutarlilik, 60 gun", (k) => dogru(k) && eksiksiz(k) && tutarli(k) && guncel(k, 60)], ["P4 ayni kurallar, 30 gun", (k) => dogru(k) && eksiksiz(k) && tutarli(k) && guncel(k, 30)], ]; console.log("\nesik siklastikca"); console.log(y(["profil", "kalan", "kalan %", "ortalama", "sapma"])); const kalanlar = PROFIL.map(([ad, f]) => { const l = KAYITLAR.filter(f); yaz(ad, l); return l; }); console.log("\nbasamak basina elenme orani (gercek okumaya gore)"); const y2 = (h) => String(h[0]).padEnd(26) + h.slice(1).map((v) => String(v).padStart(11)).join(""); const bas = (b) => KAYITLAR.filter((k) => basamakla(k.tuketim_gercek) === b); console.log(y2(["profil", "elenen", ...[1, 2, 3, 4].map((b) => `bas.${b} (${bas(b).length})`)])); PROFIL.forEach(([ad, f]) => { const d = [1, 2, 3, 4].map((b) => `%${(100 * bas(b).filter((k) => !f(k)).length / bas(b).length).toFixed(1)}`); console.log(y2([ad, KAYITLAR.filter((k) => !f(k)).length, ...d])); }); const p2 = kalanlar[2], p4 = kalanlar[4]; console.log(`\nP2 ile P4 arasinda ${p2.length - p4.length} satir daha elendi, ` + `ortalama ${(ort(p4.map((k) => k.tuketim_m3)) - ort(p2.map((k) => k.tuketim_m3))).toFixed(2)} m3 oynadi`); console.log(`en temiz kume (P4) ${p4.length} satir ve modelin dogrusundan ` + `${(ort(p4.map((k) => k.tuketim_m3)) - GERCEK).toFixed(2)} m3 sapiyor`);
modelin dogrusu 21.31 m3; asagidaki her ortalama olculen alandan hesaplanir her boyut tek basina kural kalan kalan % ortalama sapma filtre yok 1400 %100.0 24.70 +3.39 yalniz dogruluk 1354 %96.7 22.71 +1.41 yalniz eksiksizlik 1200 %85.7 24.32 +3.01 yalniz tutarlilik 1296 %92.6 21.47 +0.17 yalniz guncellik (90 gun) 918 %65.6 24.01 +2.70 esik siklastikca profil kalan kalan % ortalama sapma P0 filtre yok 1400 %100.0 24.70 +3.39 P1 dogruluk 1354 %96.7 22.71 +1.41 P2 + eksiksizlik, 90 gun 761 %54.4 22.37 +1.07 P3 + tutarlilik, 60 gun 608 %43.4 21.05 -0.25 P4 ayni kurallar, 30 gun 422 %30.1 20.83 -0.48 basamak basina elenme orani (gercek okumaya gore) profil elenen bas.1 (48)bas.2 (970)bas.3 (348) bas.4 (34) P0 filtre yok 0 %0.0 %0.0 %0.0 %0.0 P1 dogruluk 46 %4.2 %3.5 %2.6 %2.9 P2 + eksiksizlik, 90 gun 639 %45.8 %44.4 %48.0 %55.9 P3 + tutarlilik, 60 gun 792 %54.2 %55.4 %59.2 %67.6 P4 ayni kurallar, 30 gun 978 %66.7 %69.0 %71.0 %88.2 P2 ile P4 arasinda 339 satir daha elendi, ortalama -1.55 m3 oynadi en temiz kume (P4) 422 satir ve modelin dogrusundan -0.48 m3 sapiyor
İlk tablo boyutları tek tek ölçüyor ve verimlilikleri arasındaki farkı yazıyor. Doğruluk kuralı 46 satır atarak sapmayı 3,39’dan 1,41 m³’e indirir. Güncellik kuralı 482 satır atarak sapmayı yalnız 3,39’dan 2,70 m³’e indirir. Atılan satır sayısı ile kazanılan doğruluk arasında bir bağ yoktur; on kat daha fazla satır atan kural, sapmanın beşte birini bile kapatmaz. Tutarlılık kuralı ise 104 satır atarak sapmayı 0,17 m³’e indirir, çünkü bozuk okumaların çoğu basamak alanıyla da çelişir: iki boyut aynı satırların bir bölümünü ortak yakalar ve boyutlar birbirinden bağımsız değildir.
İkinci tablo eşiği kademeli sıkılaştırıyor ve rapor edilen ortalama 24,70’ten 20,83 m³’e iniyor. Yolda modelin doğrusu olan 21,31’in üzerinden geçiyor: P2’de 22,37, P3’te 21,05. Doğruya en yakın sayı en temiz kümede değil, ortada bir yerdedir ve bunu ancak doğruyu bilen biri görebilir. Gerçek bir çözümlemede o sütun yoktur; elde yalnız “kalan” ve “ortalama” sütunları vardır ve onlara bakan biri eşiği sıkılaştırdıkça sayının düştüğünü görür, doğruya yaklaştığını değil.
Üçüncü tablo düşüşün nedenini yazıyor. Elenme oranı basamak yükseldikçe artar: P4 profilinde birinci basamağın yüzde 66,7’si, dördüncü basamağın yüzde 88,2’si elenir. Elenen satırlar rastgele değildir. Modelde eksik alan ve bayat basamak olasılığı tüketimle birlikte arttığı için, kaliteyi yükselten her kural yüksek tüketenleri orantısız biçimde eler ve ortalamayı aşağı çeker. Küme temizlendikçe daha temiz ama daha yanlı hale gelir.
Buradan iki kayıt çıkar ve bir kalite raporunda ikisi de bulunmalıdır. Birincisi kaç satırın elendiğidir: 1.400’den 422’ye, yüzde 30,1. İkincisi elenenlerin hangi kırılımda toplandığıdır; tek satırlık bir “veri temizlendi” notu bu bilgiyi taşımaz. Eşik bir ayar düğmesi değil, örneklemi yeniden tanımlayan bir karardır: P4’ün 20,83 m³’ü, 1.400 abonenin değil, kayıtları yeterince yeni ve eksiksiz olan 422 abonenin ortalamasıdır ve bu iki cümle aynı şey değildir.
Özet
- Veri kalitesi dört ayrı boyutla ölçülür ve her biri kendi kuralını, eşiğini ve sayısını ister: 46 imkânsız okuma, 200 eksik kayıt, 104 tutarsız basamak, 482 eski kayıt.
- İhlal sayısı ile ihlalin etkisi aynı yönde gitmez: 46 bozuk okuma ortalamayı 3,39 m³ oynatırken 482 eski kayıt yalnız 0,69 m³ oynatır.
- Doğruluk kuralı yalnız imkânsızı yakalar: modelde bozulan 58 okumanın 12’si eşiğin altında kaldığı için geçerli görünür.
- Eşik sıkılaştıkça küme 1.400 satırdan 422’ye iner ve ortalama 24,70’ten 20,83 m³’e düşerken modelin doğrusunun üzerinden bir kez geçer.
- Elenen satırlar rastgele değildir: en üst tarife basamağının yüzde 88,2’si elenir, bu yüzden temizlenmiş küme daha temiz ve aynı zamanda daha yanlıdır.
Sonraki Adım
Bu dört ders verinin ne tür bir şey olduğunu, hangi ölçekte durduğunu, nereden geldiğini ve ne kadar güvenilir olduğunu sordu. Hepsinin ortak varsayımı şuydu: soru sorulabilir bir sorudur ve mesele yalnız doğru cevabı bulmaktır. Kalan 422 satırın her biri bir haneye aittir ve bu kayıtlar tüketim alışkanlığından ev boşken geçen günlere kadar pek çok şeyi bildirir. Bir kırılım yeterince inceltildiğinde satır artık bir örneklem değil, tek bir kişidir. Sonraki ders bir soru kümesini alır ve veriyle cevaplanabilir olanlarla sorulmaması gereken olanları ayırır; bir kırılımın kaç kişilik gruba düştüğünü sayar ve analizin nerede durması gerektiğini ölçülebilir bir eşikle gösterir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.