İçeriğe geç
academia.sh

Ders 05 / 09

Veri Türleri

1.400 abone kaydının sekiz alanı sayı olarak depolanır ve sekizinin de ortalaması hesaplanır, ama üçü nitel alandır: bölge kodunun ortalaması alfabetik kodlamada 3,19, büyüklük kodlamasında 2,69 çıkar ve veride tek bir kayıt değişmemiştir. Kesikli ziyaret alanının 1,20 ortalamasına eşit tek bir kayıt yoktur ve kayıtların yüzde 68,3'ü bu ortalamanın altındadır; sürekli tüketim alanı 5 m³ basamağına yuvarlandığında toplam yalnız binde 1,4 kayar ama 229 kayıt tarife basamağı değiştirir.

İçindekiler

Bir önceki konu bir soruyu ölçülebilir hale getirmenin asıl karar olduğunu gösterdi: “etkin abone” tanımı değişince hiçbir hesap değişmeden sayı oynadı. Ama o dört ders boyunca bir şey hiç sorulmadı — tanımın üzerinde çalıştığı verinin kendisi ne tür bir şey. Bir alanın ortalaması alınabilir mi, alınırsa ne anlama gelir, iki değeri arasındaki fark bir büyüklük müdür yoksa yalnız bir etiket farkı mı.

Bu soru teknik bir ayrıntı gibi görünür ve öyle değildir. Bir veri kümesinde her alan bir sayı olarak durabilir; hesap makinesi hepsinin ortalamasını verir ve hiçbirinde hata mesajı üretmez. Türü yanlış atanmış bir alan, kendini bir hatayla değil, anlamı olmayan bir sayıyla gösterir. Bu ders o sayıyı üç ayrı biçimde ölçer.

  • VY1. Veri kümesi bölgesel ölçüm ağının abone kayıtlarıdır: 1.400 satır, sekiz alan, beş bölge. Küme de sayılar da kurgudur; aşağıdaki her değer bir modelin çıktısıdır. Aynı küme bu konunun bütün derslerinde kullanılır.
  • VY2. Nicel veri (quantitative data), değerleri bir büyüklük bildiren veridir: iki değer arasındaki fark bir miktardır. Nitel veri (qualitative data) bir kategori bildirir; değerler ayrıdır ama aralarındaki fark bir miktar değildir.
  • VY3. Nicel bir alan kesikli (discrete) ise yalnız sayılabilir değerler alır ve ara değerlerin karşılığı yoktur; sürekli (continuous) ise iki değer arasında her zaman bir başkası vardır ve ölçüm bir hassasiyetle kesilir.
  • VY4. Bir alanın depolama türü ile veri türü aynı şey değildir. Tam sayı olarak depolanan bir alan nitel olabilir; ondalıklı depolanan bir alanın gerçekte kesikli olması da mümkündür.
  • VY5. Tarife basamağı eşikleri 10, 25 ve 40 m³’tür. Bu eşikler veridir; bu sayfada ölçülmüş değil, modele girdi olarak verilmiştir.

Depolama Türü ile Veri Türü Aynı Şey Değil

// kume.mjs — bolgesel olcum agi kaydi: her satir bir abone, alanlari sayac
// okumasi, saha ziyareti ve memnuniyet notu. MODELDIR, veri kumesi kurgudur.
export const TOHUM = 20260218, KAYIT = 1400;
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 KAYITLAR = Array.from({ length: KAYIT }, (_, i) => {
  const r = uretec(TOHUM + i);
  const b = BOLGE[ayrik(r(), BOLGE.map((x) => x.pay))];
  const tuketim = Math.max(1.2, b.taban * Math.exp((r() + r() + r() - 1.5) * 0.62));
  return { abone_no: 10001 + i, bolge: b.ad,
    tuketim_m3: Math.round(tuketim * 100) / 100,
    sayac_sayisi: ayrik(r(), [0.62, 0.24, 0.10, 0.04]) + 1,
    ziyaret_sayisi: ayrik(r(), [0.38, 0.32, 0.16, 0.08, 0.04, 0.02]),
    memnuniyet: ayrik(r(), b.mem) + 1,
    sicaklik_c: Math.round((6 + r() * 22) * 10) / 10,
    gecen_gun: Math.floor(Math.pow(r(), 1.9) * 210) };
});

// Alfabetik kodlama: bolge adlari siralanip 1'den numaralandirilir.
export const KOD_A = Object.fromEntries(BOLGE.map((b) => b.ad).sort()
  .map((ad, j) => [ad, j + 1]));
export const ort = (a) => a.reduce((x, y) => x + y, 0) / a.length;
const farkli = (f) => new Set(KAYITLAR.map(f)).size;

export const ALANLAR = [
  { ad: "abone_no", depo: "tam sayi", tur: "nitel", olcum: "-", f: (k) => k.abone_no },
  { ad: "bolge_kodu", depo: "tam sayi", tur: "nitel", olcum: "-", f: (k) => KOD_A[k.bolge] },
  { ad: "memnuniyet", depo: "tam sayi", tur: "nitel", olcum: "sirali", f: (k) => k.memnuniyet },
  { ad: "sayac_sayisi", depo: "tam sayi", tur: "nicel", olcum: "kesikli", f: (k) => k.sayac_sayisi },
  { ad: "ziyaret_sayisi", depo: "tam sayi", tur: "nicel", olcum: "kesikli", f: (k) => k.ziyaret_sayisi },
  { ad: "gecen_gun", depo: "tam sayi", tur: "nicel", olcum: "kesikli", f: (k) => k.gecen_gun },
  { ad: "tuketim_m3", depo: "ondalik", tur: "nicel", olcum: "surekli", f: (k) => k.tuketim_m3 },
  { ad: "sicaklik_c", depo: "ondalik", tur: "nicel", olcum: "surekli", f: (k) => k.sicaklik_c },
];

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} abone kaydi, ${BOLGE.length} bolge, ` +
    `${ALANLAR.length} alan; sekiz alanin tamami sayi olarak depolanmistir`);
  const y = gen([16, 11, 8, 10, 9, 12]);
  console.log("\n" + y(["alan", "depolanan", "tur", "olcum", "farkli", "ortalama"]));
  for (const a of ALANLAR) {
    console.log(y([a.ad, a.depo, a.tur, a.olcum, farkli(a.f),
      ort(KAYITLAR.map(a.f)).toFixed(2)]));
  }
  const anlamli = ALANLAR.filter((a) => a.tur === "nicel").length;
  console.log(`\nsekiz alanin sekizi icin ortalama hesaplandi; ` +
    `${anlamli} tanesi nicel, ${ALANLAR.length - anlamli} tanesi degil`);
}
model (tohum 20260218): 1400 abone kaydi, 5 bolge, 8 alan; sekiz alanin tamami sayi olarak depolanmistir

alan              depolanan     tur     olcum   farkli    ortalama
abone_no           tam sayi   nitel         -     1400    10700.50
bolge_kodu         tam sayi   nitel         -        5        3.19
memnuniyet         tam sayi   nitel    sirali        5        3.56
sayac_sayisi       tam sayi   nicel   kesikli        4        1.55
ziyaret_sayisi     tam sayi   nicel   kesikli        6        1.20
gecen_gun          tam sayi   nicel   kesikli      209       69.39
tuketim_m3          ondalik   nicel   surekli     1099       21.31
sicaklik_c          ondalik   nicel   surekli      221       16.98

sekiz alanin sekizi icin ortalama hesaplandi; 5 tanesi nicel, 3 tanesi degil

Son sütun bu dersin asıl bulgusudur: sekiz alanın sekizi için de bir ortalama çıktı. abone_no alanının ortalaması 10 700,50’dir ve bu sayı doğrudur — 1.400 abone numarasının aritmetik ortalaması gerçekten budur. Aynı sayının hiçbir karşılığı yoktur: ortalama abone numarası diye bir kavram yoktur, çünkü abone numaraları arasındaki fark bir miktar değil bir ayrımdır. Sayı hesaplandı, doğru hesaplandı ve ölçülen bir şey yok.

farkli sütunu türü tahmin etmeye yarayan bir işarettir ama karar vermez. bolge_kodu alanı beş ayrı değer alır ve nitel olduğu buradan sezilebilir. sayac_sayisi de yalnız dört değer alır, ama nicel ve kesikliktir: iki sayaçlı bir hane bir sayaçlıdan gerçekten bir sayaç fazladır. Ayrımı yapan şey değer sayısı değil, değerler arasındaki farkın bir miktar bildirip bildirmediğidir. tuketim_m3 alanı 1.099 farklı değer alır; bu, alanın sürekli olduğunu değil, ölçümün iki ondalık basamakta kesildiğini gösterir. Sürekli bir büyüklük depolandığı anda hep kesikli görünür; süreklilik depolanan değerin değil, ölçülen şeyin özelliğidir.

memnuniyet alanı üçüncü bir durumdadır. Beş değeri sıralıdır — 4 notu 3 notundan iyidir — ama 4 ile 3 arasındaki uzaklığın 2 ile 1 arasındakine eşit olduğunu söyleyen bir ölçüm yoktur. Bu ders onu nitel sayar ve sıralı olduğunu not eder; sıralamanın hangi özetlere izin verdiği sonraki dersin konusudur.

Türü Yanlış Atanan Alanın Ürettiği Sayı

Tür ataması bir etiketleme işi değildir; rapora giren sayıyı doğrudan oynatır. Aşağıdaki blok üç yanlış atamayı sırayla ölçer.

// tur-hatasi.mjs — ayni alan iki turle okundugunda cikan iki sayi yan yana.
import { KAYITLAR, BOLGE, KOD_A, ort } from "./kume.mjs";

// Kodlama B: bolgeler kayit sayisina gore buyukten kucuge numaralanir.
const sayim = Object.fromEntries(BOLGE.map((b) => [b.ad,
  KAYITLAR.filter((k) => k.bolge === b.ad).length]));
const KOD_B = Object.fromEntries(Object.keys(sayim)
  .sort((x, y) => sayim[y] - sayim[x]).map((ad, j) => [ad, j + 1]));
const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j])
  : String(v).padEnd(B[0]))).join("");

console.log("bolge_kodu nitel bir alandir; iki kodlama da savunulabilir");
const y1 = gen([10, 9, 9, 9]);
console.log(y1(["bolge", "kayit", "kod A", "kod B"]));
for (const ad of Object.keys(sayim)) console.log(y1([ad, sayim[ad], KOD_A[ad], KOD_B[ad]]));
const oA = ort(KAYITLAR.map((k) => KOD_A[k.bolge]));
const oB = ort(KAYITLAR.map((k) => KOD_B[k.bolge]));
console.log(`kod A ortalamasi ${oA.toFixed(2)}, kod B ortalamasi ${oB.toFixed(2)}, ` +
  `fark ${(oB - oA).toFixed(2)} — veride tek bir kayit degismedi`);

// Kesikli alan: ortalama ile dagilim yan yana.
const z = KAYITLAR.map((k) => k.ziyaret_sayisi), oz = ort(z);
const DEGER = [0, 1, 2, 3, 4, 5];
const say = (v) => z.filter((x) => x === v).length;
// Ondalikli esitlik dogrudan sinanmaz; 0.005 esigi bir ziyaretin yuzde yarimidir
// ve bu kumede iki farkli tam sayi degerini asla ayni sayamaz.
const EPS = 0.005, esit = z.filter((v) => Math.abs(v - oz) < EPS).length;
const alti = z.filter((v) => v < oz).length;
console.log(`\nziyaret_sayisi: ortalama ${oz.toFixed(2)}, ortanca ` +
  `${[...z].sort((a, b) => a - b)[z.length / 2]}, tepe deger ` +
  `${DEGER.reduce((a, v) => (say(v) > say(a) ? v : a), 0)}`);
const y2 = gen([10, 9, 10, 12]);
console.log(y2(["ziyaret", "kayit", "yuzde", "kumulatif"]));
let ku = 0;
for (const v of DEGER) { ku += say(v);
  console.log(y2([v, say(v), (100 * say(v) / z.length).toFixed(1), ku])); }
console.log(`ortalamaya esit kayit ${esit}; ortalamanin altinda ${alti} kayit, ` +
  `yuzde ${(100 * alti / z.length).toFixed(1)}`);

// Surekli alan kesikli okundugunda: 5 m3 basamagina yuvarlama.
const ESIK = [10, 25, 40];
const basamak = (v) => (v < ESIK[0] ? 1 : v < ESIK[1] ? 2 : v < ESIK[2] ? 3 : 4);
const ham = KAYITLAR.map((k) => k.tuketim_m3), yuv = ham.map((v) => Math.round(v / 5) * 5);
const kayan = ham.filter((v, i) => basamak(v) !== basamak(yuv[i])).length;
const top = (a) => a.reduce((x, y) => x + y, 0);
console.log(`\ntuketim_m3 sureklidir; 5 m3 basamagina yuvarlanirsa toplam ` +
  `${top(ham).toFixed(1)} m3 yerine ${top(yuv).toFixed(1)} m3 olur, fark ` +
  `${(top(yuv) - top(ham)).toFixed(1)} m3 (binde ` +
  `${(1000 * (top(yuv) - top(ham)) / top(ham)).toFixed(1)})`);
console.log(`ortalama ${ort(ham).toFixed(2)} yerine ${ort(yuv).toFixed(2)}; ` +
  `${kayan} kayit tarife basamagi degistirir`);
const y3 = gen([12, 9, 14, 9]);
console.log(y3(["basamak", "ham", "yuvarlanmis", "fark"]));
for (const b of [1, 2, 3, 4]) {
  const h = ham.filter((v) => basamak(v) === b).length;
  const u = yuv.filter((v) => basamak(v) === b).length;
  console.log(y3([`${b} (${b === 4 ? "40+" : `<${ESIK[b - 1]}`} m3)`, h, u, u - h]));
}
bolge_kodu nitel bir alandir; iki kodlama da savunulabilir
bolge         kayit    kod A    kod B
kuzey           408        4        1
guney           282        3        2
dogu            240        2        4
bati            209        1        5
merkez          261        5        3
kod A ortalamasi 3.19, kod B ortalamasi 2.69, fark -0.51 — veride tek bir kayit degismedi

ziyaret_sayisi: ortalama 1.20, ortanca 1, tepe deger 0
ziyaret       kayit     yuzde   kumulatif
0               514      36.7         514
1               442      31.6         956
2               237      16.9        1193
3               106       7.6        1299
4                62       4.4        1361
5                39       2.8        1400
ortalamaya esit kayit 0; ortalamanin altinda 956 kayit, yuzde 68.3

tuketim_m3 sureklidir; 5 m3 basamagina yuvarlanirsa toplam 29828.2 m3 yerine 29870.0 m3 olur, fark 41.8 m3 (binde 1.4)
ortalama 21.31 yerine 21.34; 229 kayit tarife basamagi degistirir
basamak           ham   yuvarlanmis     fark
1 (<10 m3)         48             3      -45
2 (<25 m3)        970           853     -117
3 (<40 m3)        348           488      140
4 (40+ m3)         34            56       22

İlk blok nitel alana uygulanan ortalamayı ölçüyor. Bölge kodu iki biçimde verilebilir ve ikisi de savunulabilir: adları alfabetik sıralayıp numaralamak ya da bölgeleri kayıt sayısına göre büyükten küçüğe numaralamak. Birinci kodlamada ortalama bölge kodu 3,19, ikincisinde 2,69 çıkar. Veride hiçbir kayıt değişmemiştir; değişen tek şey etiketlere iliştirilen sayılardır. Bu, nitel bir alanın ortalamasının veriye değil kodlamaya ait olduğunu gösteren en kısa kanıttır. Bir raporda “ortalama bölge kodu 3,19” satırı varsa o satır bir bulgu değil, bir sıralama kararının gölgesidir.

İkinci blok kesikli bir alanı sürekli sayınca ne olduğunu gösteriyor. Ziyaret sayısının ortalaması 1,20’dir; hesap doğrudur. Ama 1.400 kaydın hiçbiri 1,20 ziyaret almamıştır, çünkü yarım ziyaret diye bir şey yoktur. Ortalamaya eşit kayıt sayısı sıfırdır. Dahası kayıtların yüzde 68,3’ü bu ortalamanın altındadır: en kalabalık grup 514 kayıtla hiç ziyaret almamış abonelerdir. “Abone başına 1,20 saha ziyareti” cümlesi tek bir aboneyi bile tarif etmez; “abonelerin yüzde 36,7’si hiç ziyaret almamıştır” cümlesi aynı veriden çıkar ve bambaşka bir şey söyler. İkisi de doğrudur ve ikisi zıt karar önerir — biri ziyaret yükünün dengeli olduğunu, diğeri bir kesimin hiç görülmediğini gösterir. Kesikli bir alan için rapora giren sayı ortalama değil dağılımdır; ortalama yalnız o dağılımın yanında bir özettir.

Üçüncü blok sürekli bir alanın kesikli okunmasını ölçüyor ve şaşırtıcı sonucu buradadır. Tüketim 5 m³ basamağına yuvarlandığında toplam 29 828,2 m³’ten 29 870,0 m³’e çıkar: fark binde 1,4. Toplam neredeyse hiç kımıldamaz, çünkü yukarı ve aşağı yuvarlamalar birbirini götürür. Aynı işlem 229 kaydın tarife basamağını değiştirir. Birinci basamaktaki 48 kayıt 3’e iner, üçüncü basamak 348’den 488’e çıkar. Yuvarlama toplamı korur, sınıflandırmayı bozar. Toplam tüketim üzerinden rapor veren biri yuvarlamanın zararsız olduğunu söyleyebilir ve haklıdır; tarife basamağı dağılımı üzerinden rapor veren biri aynı işlemin kayıtların altıda birini başka basamağa taşıdığını söyler ve o da haklıdır. Hangi kararın zararsız olduğu, sorulan soruya bağlıdır.

Üç ölçüm de aynı kuralı yazıyor: bir sayının yanında hangi tür atamasıyla üretildiği yazılmıyorsa o sayı okunamaz. Bölge kodu ortalaması hangi kodlamada, ziyaret ortalaması hangi dağılımın yanında, tüketim ortalaması yuvarlanmış mı — bu üç bilgi olmadan üç sayı da savunulamaz.

Özet

  • Depolama türü veri türünü belirlemez: sekiz alanın sekizi de sayı olarak durur, üçü niteldir ve ortalaması hesaplanabilse de bir büyüklük bildirmez.
  • Nicel ile niteli ayıran şey değer sayısı değil, iki değer arasındaki farkın bir miktar bildirip bildirmediğidir; sayac_sayisi dört değerle nicel, bolge_kodu beş değerle niteldir.
  • Nitel bir alanın ortalaması kodlamaya aittir: aynı 1.400 kayıt alfabetik kodlamada 3,19, büyüklük kodlamasında 2,69 verir ve veride hiçbir şey değişmemiştir.
  • Kesikli bir alan sürekli sayılınca ortalama karşılığı olmayan bir değere iner: 1,20 ziyaret ortalamasına eşit kayıt yoktur ve kayıtların yüzde 68,3’ü bu değerin altındadır.
  • Sürekli bir alanın yuvarlanması toplamı binde 1,4 oynatır ama 229 kaydın tarife basamağını değiştirir; aynı kararın zararsız olup olmadığı sorulan soruya göre değişir.

Sonraki Adım

Bu ders bir alanın ortalamasının alınıp alınamayacağını sordu ve memnuniyet alanında yarım bir cevapla kaldı: 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. Aynı belirsizlik sicaklik_c alanında da vardır — iki sıcaklık toplanabilir mi, biri diğerinin iki katı sayılabilir mi. Nicel ve nitel ayrımı bu soruları cevaplamaya yetmiyor, çünkü ayrım fazla kaba. Sonraki ders alanları dört ölçüm ölçeğine yerleştirir ve her ölçekte hangi özetin meşru olduğunu sayar: sıralayıcı bir alana verilen iki savunulabilir sayısal kodlama, bölgelerin memnuniyet sıralamasını baştan sona ters çevirir.

İ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