Ders 06 / 09
Ölçüm Ölçekleri
On alan dört ölçeğe yerleştirilir ve dört özetle çarpılan 40 hücrenin tamamı hesaplanır, 28'i meşru çıkar, 12'si hesaplanmış ama ölçeğin desteklemediği sayıdır. Sıralayıcı memnuniyet alanına verilen iki savunulabilir kodlama — 1,2,3,4,5 ile 0,4,6,7,8 — bölge sıralamasını ters çevirir: birinci bölge beşinciye düşer, tek bir not değişmeden. Aralık ölçeğinde aynı iki okumanın oranı sıfır noktası değişince 4,67'den 1,08'e iner, farkı ise 22,0 birimde sabit kalır.
İçindekiler
Bir önceki ders alanları nicel ve nitel diye ikiye ayırdı ve iki yerde takıldı. memnuniyet
alanının değerleri sıralıdır, ama 4 ile 3 arasındaki uzaklığın 2 ile 1 arasındakine eşit olduğunu
kimse ölçmemiştir. sicaklik_c alanı niceldir, ama bir okumanın diğerinin iki katı sayılıp
sayılamayacağı belirsiz kaldı. İkisi de aynı yere işaret ediyor: nicel ve nitel ayrımı fazla kaba.
Bu ders alanları dört ölçüm ölçeğine (measurement scale) yerleştirir. Ölçek, alanın değerleri üzerinde hangi işlemin anlamlı olduğunu söyler; anlamlı işlem kümesi de hangi özetin meşru olduğunu belirler. Dersin bulgusu şudur: bir hesabın yapılabilmesi onun meşru olduğu anlamına gelmez.
- VY6. Küme, bir önceki dersteki 1.400 satırlık abone kaydıdır; iki türetilmiş alan eklenir:
tarife_basamagi(tüketimin 10, 25 ve 40 m³ eşiklerine göre düştüğü basamak) veokuma_gunu(gözlem penceresinde okumanın yapıldığı gün numarası). Küme kurgudur. - VY7. Sınıflayıcı ölçek (nominal scale) yalnız eşitliğe izin verir. Sıralayıcı ölçek (ordinal scale) sıralamayı da ekler ama iki komşu basamak arasındaki uzaklığı bildirmez.
- VY8. Aralık ölçeği (interval scale) farkları anlamlı kılar; sıfır noktası anlaşmayla seçilmiştir ve bir yokluk bildirmez. Oran ölçeği (ratio scale) gerçek bir sıfıra dayanır, bu yüzden oran ifadeleri de anlamlıdır.
- VY9. Dört özet dört ayrı işlem ister: tepe değer eşitlik, ortanca sıralama, ortalama eşit aralıklar, oran ifadesi gerçek bir sıfır. İstediği işlem ölçekte tanımlı değilse bir özet hesaplanabilir ama meşru değildir.
Kırk Hücrenin Kaçı Meşru
// olcekler.mjs — ayni kume, bu kez her alan bir olcege yerlestirilir ve dort // ozet her alan icin hesaplanir. MODELDIR, veri kumesi kurgudur. export const TOHUM = 20260218, KAYIT = 1400, TARIFE = [10, 25, 40]; 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 KOD = Object.fromEntries(BOLGE.map((b) => b.ad).sort().map((a, j) => [a, j + 1])); 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 tuketim = 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); return { abone_no: 10001 + i, bolge: b.ad, tuketim_m3: tuketim, sayac_sayisi: sayac, ziyaret_sayisi: ziyaret, memnuniyet, sicaklik_c: sicaklik, gecen_gun: gecen, okuma_gunu: 300 - gecen, tarife_basamagi: tuketim < TARIFE[0] ? 1 : tuketim < TARIFE[1] ? 2 : tuketim < TARIFE[2] ? 3 : 4 }; }); // Olcek, alanin degerleri uzerinde hangi islemin anlamli oldugunu soyler. export const OLCEK = { siniflayici: { esit: 1, sira: 0, fark: 0, oran: 0 }, siralayici: { esit: 1, sira: 1, fark: 0, oran: 0 }, aralik: { esit: 1, sira: 1, fark: 1, oran: 0 }, oran: { esit: 1, sira: 1, fark: 1, oran: 1 }, }; export const ALANLAR = [ { ad: "abone_no", olcek: "siniflayici", f: (k) => k.abone_no }, { ad: "bolge (kod)", olcek: "siniflayici", f: (k) => KOD[k.bolge] }, { ad: "memnuniyet", olcek: "siralayici", f: (k) => k.memnuniyet }, { ad: "tarife_basamagi", olcek: "siralayici", f: (k) => k.tarife_basamagi }, { ad: "sicaklik_c", olcek: "aralik", f: (k) => k.sicaklik_c }, { ad: "okuma_gunu", olcek: "aralik", f: (k) => k.okuma_gunu }, { ad: "tuketim_m3", olcek: "oran", f: (k) => k.tuketim_m3 }, { ad: "sayac_sayisi", olcek: "oran", f: (k) => k.sayac_sayisi }, { ad: "ziyaret_sayisi", olcek: "oran", f: (k) => k.ziyaret_sayisi }, { ad: "gecen_gun", olcek: "oran", f: (k) => k.gecen_gun }, ]; export const ort = (a) => a.reduce((x, y) => x + y, 0) / a.length; const tepe = (a) => { const s = new Map(); for (const v of a) s.set(v, (s.get(v) ?? 0) + 1); return [...s].sort((x, y) => y[1] - x[1] || x[0] - y[0])[0][0]; }; const ortanca = (a) => [...a].sort((x, y) => x - y)[Math.floor(a.length / 2)]; const bolgeOrani = (f) => { const o = BOLGE.map((b) => ort(KAYITLAR.filter((k) => k.bolge === b.ad).map(f))); return Math.max(...o) / Math.min(...o); }; // Her ozet bir islem ister: tepe deger esitlik, ortanca siralama, aritmetik // ortalama esit araliklar, oran ifadesi gercek bir sifir noktasi. export const OZET = [ { ad: "tepe deger", ister: "esit", h: (f) => tepe(KAYITLAR.map(f)).toFixed(1) }, { ad: "ortanca", ister: "sira", h: (f) => ortanca(KAYITLAR.map(f)).toFixed(1) }, { ad: "ortalama", ister: "fark", h: (f) => ort(KAYITLAR.map(f)).toFixed(2) }, { ad: "bolge orani", ister: "oran", h: (f) => bolgeOrani(f).toFixed(2) }, ]; const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j]) : String(v).padEnd(B[0]))).join(""); if (import.meta.url === `file://${process.argv[1]}`) { console.log(`model (tohum ${TOHUM}): ${KAYIT} kayit, ${ALANLAR.length} alan, ` + `${OZET.length} ozet — ${ALANLAR.length * OZET.length} hucrenin tamami hesaplanabilir`); const y = gen([17, 14, 12, 11, 11, 14, 8]); console.log("\n" + y(["alan", "olcek", ...OZET.map((o) => o.ad), "mesru"])); let mesru = 0; for (const a of ALANLAR) { const izin = OLCEK[a.olcek]; const hucre = OZET.map((o) => o.h(a.f) + (izin[o.ister] ? " " : "*")); const m = OZET.filter((o) => izin[o.ister]).length; mesru += m; console.log(y([a.ad, a.olcek, ...hucre, `${m}/${OZET.length}`])); } console.log(`\n* isaretli hucre hesaplandi ama olcek o islemi desteklemez`); console.log(`${ALANLAR.length * OZET.length} hucrenin ${mesru} tanesi mesru, ` + `${ALANLAR.length * OZET.length - mesru} tanesi degil`); }
model (tohum 20260218): 1400 kayit, 10 alan, 4 ozet — 40 hucrenin tamami hesaplanabilir alan olcek tepe deger ortanca ortalama bolge orani mesru abone_no siniflayici 10001.0 10701.0* 10700.50* 1.00* 1/4 bolge (kod) siniflayici 4.0 3.0* 3.19* 5.00* 1/4 memnuniyet siralayici 4.0 4.0 3.56* 1.08* 2/4 tarife_basamagi siralayici 2.0 2.0 2.26* 1.38* 2/4 sicaklik_c aralik 7.7 16.8 16.98 1.03* 3/4 okuma_gunu aralik 300.0 249.0 230.61 1.03* 3/4 tuketim_m3 oran 14.5 20.0 21.31 1.86 4/4 sayac_sayisi oran 1.0 1.0 1.55 1.09 4/4 ziyaret_sayisi oran 0.0 1.0 1.20 1.11 4/4 gecen_gun oran 0.0 51.0 69.39 1.10 4/4 * isaretli hucre hesaplandi ama olcek o islemi desteklemez 40 hucrenin 28 tanesi mesru, 12 tanesi degil
Kırk hücrenin kırkı da bir sayı verdi ve hiçbiri hata üretmedi. Meşru olan 28’dir; 12 hücre
ölçeğin desteklemediği bir işlemi kullanmıştır. Bu 12 sayı yanlış hesaplanmış değildir —
bolge (kod) alanının bölge oranı gerçekten 5,00’tir. O oranın karşılığı yoktur: bölge kodları
sıralanınca beşinci bölgenin birinciden “beş kat” fazla bir şeyi olmaz. Ölçek yükseldikçe meşru
özet sayısı artar, sınıflayıcıda 1’den oranda 4’e; ölçekler birbirini kapsar. Bu yüzden bir
alanı olduğundan yüksek bir ölçeğe yerleştirmek sessiz bir hatadır: hesap yapılır, sayı çıkar,
uyarı gelmez.
Ters yönde okunduğunda ikinci bir uyarı çıkıyor. Meşru olmak yararlı olmak değildir. tuketim_m3
alanının tepe değeri 14,5’tir ve oran ölçeğinde meşrudur; ama alan 1.099 farklı değer aldığı için
14,5 yalnız iki kez tekrar etmiş bir okumadır ve kümeyi tarif etmez. Ölçek bir alt sınır koyar,
üst sınır koymaz.
Sıralayıcı Alanın Ortalaması Kime Aittir
Yıldız işaretli hücrelerin en tehlikelisi memnuniyet alanının 3,56 ortalamasıdır, çünkü yanlış
görünmez. Aşağıdaki blok o sayının neye bağlı olduğunu ölçüyor.
// kodlama.mjs — siralayici alanin ortalamasi iki savunulabilir kodlamada // yan yana; ayrica aralik olceginde oran ifadesinin sifir noktasina bagimliligi. import { KAYITLAR, BOLGE, ort } from "./olcekler.mjs"; // A: basamaklar esit araliklidir. B: uclar arasi mesafe daha buyuktur — // "cok kotu" ile "kotu" arasi, "iyi" ile "cok iyi" arasindan uzaktir. const KOD_A = [1, 2, 3, 4, 5], KOD_B = [0, 4, 6, 7, 8]; const NOT = ["cok kotu", "kotu", "orta", "iyi", "cok iyi"]; const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j]) : String(v).padEnd(B[0]))).join(""); const ortanca = (a) => [...a].sort((x, y) => x - y)[Math.floor(a.length / 2)]; console.log("memnuniyet basamaklari ve iki kodlama"); const y0 = gen([12, 8, 8, 8]); console.log(y0(["basamak", "not", "kod A", "kod B"])); NOT.forEach((n, j) => console.log(y0([j + 1, n, KOD_A[j], KOD_B[j]]))); const satir = BOLGE.map((b) => { const l = KAYITLAR.filter((k) => k.bolge === b.ad).map((k) => k.memnuniyet); return { ad: b.ad, n: l.length, dagilim: [1, 2, 3, 4, 5].map((v) => l.filter((x) => x === v).length), a: ort(l.map((v) => KOD_A[v - 1])), b: ort(l.map((v) => KOD_B[v - 1])), med: ortanca(l) }; }); const sira = (alan) => { const s = [...satir].sort((x, y) => y[alan] - x[alan]); return Object.fromEntries(s.map((x, j) => [x.ad, j + 1])); }; const sA = sira("a"), sB = sira("b"); console.log("\nbolge basina memnuniyet: dagilim ayni, iki kodlama iki siralama verir"); const y1 = gen([9, 7, 22, 9, 8, 9, 8, 9]); console.log(y1(["bolge", "kayit", "dagilim 1..5", "kod A", "sira A", "kod B", "sira B", "ortanca"])); for (const s of satir) { console.log(y1([s.ad, s.n, s.dagilim.join(" "), s.a.toFixed(2), sA[s.ad], s.b.toFixed(2), sB[s.ad], s.med])); } const yerDegisen = satir.filter((s) => sA[s.ad] !== sB[s.ad]).length; console.log(`${yerDegisen} bolgenin sirasi degisti; en buyuk kayma ` + `${satir.map((s) => Math.abs(sA[s.ad] - sB[s.ad])).sort((x, y) => y - x)[0]} basamak`); const enA = satir.find((s) => sA[s.ad] === 1), enB = satir.find((s) => sB[s.ad] === 1); console.log(`kod A birincisi ${enA.ad}, kod B birincisi ${enB.ad}; ` + `${enA.ad} kod B'de ${sB[enA.ad]}. sirada`); console.log(`iki hesap da dogru, iki kodlama da savunulabilir, tek bir not degismedi`); // Aralik olcegi: sifir noktasi anlasmayla belirlenmistir, oran ona bagimlidir. const sicak = KAYITLAR.map((k) => k.sicaklik_c); const KAYDIRMA = [0, -273.15, 32]; // ayni olcumun uc ayri sifir noktasindaki degeri const ETIKET = ["yerel olcek", "mutlak sifira dayali", "baska bir anlasma"]; const a = Math.max(...sicak), b = Math.min(...sicak); console.log(`\nen sicak okuma ${a.toFixed(1)}, en soguk okuma ${b.toFixed(1)} (yerel olcek)`); const y2 = gen([24, 11, 11, 9, 9]); console.log(y2(["olcek", "en sicak", "en soguk", "fark", "oran"])); KAYDIRMA.forEach((d, j) => { const x = j === 2 ? a * 1.8 + 32 : a - d, y = j === 2 ? b * 1.8 + 32 : b - d; console.log(y2([ETIKET[j], x.toFixed(1), y.toFixed(1), (x - y).toFixed(1), (x / y).toFixed(2)])); }); console.log(`ilk iki olcegin birimi ayni, sifir noktasi farkli: fark ` + `${(a - b).toFixed(1)} birim olarak sabit kalir, oran 4.67'den 1.08'e iner`);
memnuniyet basamaklari ve iki kodlama basamak not kod A kod B 1 cok kotu 1 0 2 kotu 2 4 3 orta 3 6 4 iyi 4 7 5 cok iyi 5 8 bolge basina memnuniyet: dagilim ayni, iki kodlama iki siralama verir bolge kayit dagilim 1..5 kod A sira A kod B sira B ortanca kuzey 408 17 37 107 170 77 3.62 2 6.36 2 4 guney 282 8 23 89 123 39 3.57 3 6.38 1 4 dogu 240 44 25 17 24 130 3.71 1 5.88 5 5 bati 209 16 34 47 67 45 3.44 4 5.97 4 4 merkez 261 18 45 55 94 49 3.43 5 5.98 3 4 3 bolgenin sirasi degisti; en buyuk kayma 4 basamak kod A birincisi dogu, kod B birincisi guney; dogu kod B'de 5. sirada iki hesap da dogru, iki kodlama da savunulabilir, tek bir not degismedi en sicak okuma 28.0, en soguk okuma 6.0 (yerel olcek) olcek en sicak en soguk fark oran yerel olcek 28.0 6.0 22.0 4.67 mutlak sifira dayali 301.1 279.1 22.0 1.08 baska bir anlasma 82.4 42.8 39.6 1.93 ilk iki olcegin birimi ayni, sifir noktasi farkli: fark 22.0 birim olarak sabit kalir, oran 4.67'den 1.08'e iner
İki kodlama da savunulabilir. Birincisi basamakları eşit aralıklı sayar. İkincisi “çok kötü” ile “kötü” arasını diğer komşu basamaklar arasından uzak alır: en alt basamak bir şikâyeti bildirir ve bir üstünden farkı, “iyi” ile “çok iyi” farkından büyüktür. Hangisinin doğru olduğunu veri söylemez, çünkü veride basamaklar arası uzaklığı ölçen bir şey yoktur.
Sonuç, aynı 1.400 nottan iki farklı sıralama çıkmasıdır. Kod A’da birinci bölge dogu, kod B’de
beşinci; üç bölgenin sırası değişti, en büyük kayma dört basamaktır. Nedeni dağılım sütununda
yazılı: dogu bölgesinin 240 kaydından 130’u en üst, 44’ü en alt basamaktadır. Bu uçlaşmış
dağılım, basamakları eşit sayan kodlamada yükselir, alt ucu ağır cezalandıranda dibe düşer.
guney bölgesinin 282 kaydı ortada toplanmıştır ve iki kodlamada da sarsılmaz.
Aynı veriden birbiriyle çelişen iki doğru sayı çıktı. “Memnuniyeti en yüksek bölge dogu” ile
“memnuniyeti en düşük bölge dogu” cümlelerinin ikisi de aynı notlardan, aritmetik hata
yapılmadan üretilmiştir. Aradaki tek fark bir kodlama kararıdır ve o karar hiçbir raporda
görünmez.
Ortanca sütunu bir çıkış yolu gösteriyor ama tam bir çözüm değil. Ortanca herhangi bir artan kodlamada aynı basamağı verir, çünkü sıralamadan başkasına dayanmaz. Bedeli çözünürlüktür: beş bölgenin dördü 4 ortancasına sahiptir. Karar kuralı bundan çıkar: sıralama gerekiyorsa dağılımın kendisi raporlanır; ortalama verilecekse yanına hangi kodlamayla üretildiği yazılır.
Son tablo aralık ölçeğindeki karşılığını veriyor. En sıcak ve en soğuk okumanın oranı yerel
ölçekte 4,67’dir; sıfır noktası 273,15 birim aşağıda olan bir ölçekte aynı iki okumanın oranı
1,08’e iner, farkı ise iki ölçekte de 22,0 birimdir. Bir oranın veriye ait olması için sıfırın bir
yokluğu bildirmesi gerekir. tuketim_m3 alanında sıfır tüketim gerçekten tüketim yokluğudur;
bir bölgenin diğerinin 1,86 katı tükettiği ifadesi bu yüzden ölçekten değil veriden gelir.
Özet
- Dört ölçek birbirini kapsar: sınıflayıcı eşitlik, sıralayıcı sıralama, aralık fark, oran bölme.
- Kırk hücrenin kırkı hesaplandı, 28’i meşru çıktı; 12 hücre ölçeğin desteklemediği bir işleme dayanan sayıdır ve hiçbir hata üretmez.
- Meşru olmak yararlı olmak değildir:
tuketim_m3alanının tepe değeri oran ölçeğinde meşrudur ama 1.099 farklı değer arasında iki kez geçen bir okumadır. - Sıralayıcı bir alanın ortalaması kodlamaya aittir: iki savunulabilir kodlama bölge sıralamasını ters çevirir, birinci bölge beşinciye düşer.
- Aralık ölçeğinde fark veriye, oran sıfır noktasına aittir: aynı iki okumanın oranı 4,67 iken sıfır kaydırılınca 1,08 olur, farkı 22,0 birimde kalır.
Sonraki Adım
Bu iki ders alanın türünü ve ölçeğini sordu, ama ikisi de kümeyi hazır kabul etti. Sorulmayan şey satırların nereden geldiğidir. Ortalama tüketim, saha ziyaretlerinden derlenen kayıtlarda başka, faturalama kayıtlarından türetilen özette başka, sayaçların kendiliğinden gönderdiği okumalarda başka çıkar. Üçü de doğru toplanmıştır, çünkü her kaynak kimin kayda girdiğine dair bir karar taşır. Sonraki ders bu üç kaynağı ayırır ve aynı büyüklüğün kaynaktan kaynağa ne kadar kaydığını sayar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.