---
title: 'Veri Analitiğine Giriş'
source: 'https://academia.sh/tr/kurslar/veri-analitigine-giris'
language: tr
updated: '2026-08-17T04:40:07+00:00'
license: 'CC BY-SA 4.0'
lessons: 9
outcomes:
    - 'Analitik türlerini sordukları soruya ve gerektirdikleri veriye göre ayırır'
    - 'Ölçüm ölçeklerini sınıflandırır ve her ölçekte hangi özetin meşru olduğunu gösterir'
    - 'Bir analiz sorusunu ölçülebilir biçimde tanımlar ve tanımın sayıyı ne kadar oynattığını yazar'
---

# Veri Analitiğine Giriş

Bir sayının hiçbir hesap yapılmadan, tanım anında oynadığının gösterilmesi: aynı ham kümeden iki savunulabilir etkin abone tanımının iki farklı sayı vermesi, analitik türlerinin gerektirdiği veri ve eldeki kümeyle cevaplanamayan tür, analiz akışının kaç kez soruya geri döndüğü, aynı sorunun üç rolde farklı çıktıya dönüşmesi, veri türü yanlış atandığında ortaya çıkan anlamsız özet, ölçeğin izin verdiği özet, kaynağın taşıdığı yanlılık, kalite eşiği değişince elenen satır sayısı ve veriyle cevaplanabilir olduğu halde sorulmaması gereken soru.

## Analitik Kavramı

Veriden karara giden zincirin ve o zincirdeki kararların sayıyla ölçülmesi: aynı ham kümeden iki savunulabilir tanımla hesaplanan etkin abone sayısının farkı, betimsel, tanısal, öngörücü ve önerici analitiğin gerektirdiği veri ile eldeki kümeyle cevaplanamayan soru sayısı, analiz akışının kaç adımda soruya geri döndüğü, aynı sorunun veri analisti, iş analisti ve veri bilimci elinde farklı çıktıya dönüşmesi.

### Veri Analitiği Nedir

Source: https://academia.sh/tr/kurslar/veri-analitigine-giris/veri-analitigi-nedir

Tek bir abone tablosundan 'etkin abone sayısı' üç savunulabilir tanımla hesaplanıyor ve üç ayrı sayı çıkıyor: sözleşme kaydı etkin olan 3 849, son 30 günde okuma gönderen 3 548, sözleşmesi açık olan 4 211. İlk iki tanımın toplamları yalnız 301 fark ediyor ama 645 abone üzerinde anlaşmıyorlar; tek serbest sayı olan pencere 14 günden 90 güne açıldığında sayı 1 859'dan 3 750'ye çıkıyor. Hiçbir hesap değişmedi, yalnız tanım değişti.

Bir rapordaki sayının nereden geldiği sorulduğunda verilen ilk cevap çoğunlukla hesabı anlatır:
hangi satırlar toplandı, hangi bölme yapıldı. Bu müfredat başka bir yere bakar. Bir sayı çoğu
zaman hesap yüzünden değil, hesap başlamadan önce alınmış bir **tanım kararı** yüzünden o
değerdedir. Hesap doğru yapılmış olabilir ve sayı yine de başka bir sayı olabilirdi.

Veri analitiği, bir soruyu veriyle cevaplanabilir duruma getirme ve çıkan sayıyı bir karara
bağlama işidir. Bu dersin ölçtüğü şey zincirin ilk halkasıdır: bir soru ölçülebilir kılınırken
alınan kararlar sayıyı ne kadar oynatıyor. Ölçü birimi **farktır** — aynı veriden, aynı soruya,
iki savunulabilir kararla kaç farklı sayı çıkıyor.

- **AK1.** Veri kümesi bir **bölgesel ölçüm ağının** abone kayıtlarıdır: su sayaçlarından okuma
  toplayan, okumaları faturaya çeviren ve saha ekibine iş emri açan bir ağ. Ağ da kayıtlar da
  **kurgudur**; aşağıdaki bütün sayılar bir modelin çıktısıdır, ölçülmüş bir kurulumun değil.
- **AK2.** Tablo hazırdır ve bu kursta **veri kümesi** olarak kullanılır. Şema tasarımı,
  normalizasyon ve sorgu yazımı Veritabanı Temelleri kursunda kuruldu; burada tekrarlanmaz.
- **AK3.** Ölçüm günü **0**'dır. Adı `Gun` ile biten her alan o günden geriye sayılan gün
  sayısıdır: `sonOkumaGun` 4 ise sayaç dört gün önce okuma göndermiştir.
- **AK4.** Sayaçların okuma döngüsü modelde aylıktır. Bir sayacın 30 gün boyunca hiç okuma
  göndermemesi olağan değildir; 14 gün göndermemesi olağandır.
- **AK5.** Sözleşme durumu üç değer alır: `etkin`, `askida`, `kapali`. Bu alan **kayıt
  sisteminin** durumudur; sayacın davranışıyla arasında zorunlu bir bağ yoktur.
- **AK6.** Soru şudur: **ağda kaç etkin abone var.** Soru bu haliyle bir hesap değil, bir tanım
  isteğidir.

#### Ham Kayıtta Ne Var

Soruyu cevaplamadan önce elde ne olduğuna bakılır. Aşağıdaki blok kümeyi kurar ve tek bir çapraz
tablo basar: sözleşme durumu ile sayacın son okuma zamanı. İkisi arasındaki uyuşmazlık dersin geri
kalanının kaynağıdır.

```js
// kume.mjs — bolgesel olcum aginin abone kayitlari; MODELDIR, kayitlar kurgudur.
// Olcum gunu 0'dir; "gun" ile biten alanlar o gunden geriye sayilan gun sayisidir.
export const TOHUM = 20260601, ABONE = 4800, BOLGE = ["kuzey", "guney", "dogu", "bati", "merkez"];
const uretec = (t) => { let s = t >>> 0;
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; };
const r = uretec(TOHUM);
const sec = (u, d) => { let t = 0; for (const [a, p] of d) { t += p; if (u < t) return a; }
  return d.at(-1)[0]; };

export const KAYITLAR = Array.from({ length: ABONE }, (_, i) => {
  const bolge = BOLGE[Math.floor(r() * 5)];
  const basamak = sec(r(), [[1, 0.46], [2, 0.34], [3, 0.20]]);
  const baglantiGun = 30 + Math.floor(r() * 2900);
  // Kapanis olasiligi en dusuk tarife basamaginda yuksektir ve kapanislar son aylara yigilir.
  const kapanmaP = [0.16, 0.09, 0.05][basamak - 1];
  const kapanisGun = r() < kapanmaP
    ? Math.min(baglantiGun - 1, Math.floor(r() * r() * 420)) : null;
  const askida = kapanisGun === null && r() < 0.085;
  const sozlesme = kapanisGun !== null ? "kapali" : askida ? "askida" : "etkin";
  // Sayacin son okumasindan bu yana gecen gun. Kapali ve askidaki abonelerin bir bolumu
  // hala okuma gonderir; etkin abonelerin bir bolumu (arizali sayac, bos konut) gondermez.
  const g = sozlesme === "etkin" ? (r() < 0.13 ? 31 + Math.floor(r() * 300) : Math.floor(r() * 29))
    : sozlesme === "askida" ? (r() < 0.34 ? Math.floor(r() * 29) : 31 + Math.floor(r() * 250))
    : (r() < 0.11 ? Math.floor(r() * 29) : 31 + Math.floor(r() * 500));
  const tuketim = Math.round((2 + basamak * 4 + r() * 9) * 10) / 10;
  const ucret = Math.round((6 + basamak * basamak * 7) * (0.85 + r() * 0.3));
  return { i, bolge, basamak, baglantiGun, kapanisGun, sozlesme, sonOkumaGun: g,
    tuketim, ucret, destek: r() < 0.22 ? 1 + Math.floor(r() * 3) : 0 };
});

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(`tohum ${TOHUM}: ${ABONE} satir, ${Object.keys(KAYITLAR[0]).length} alan`);
  console.log("alanlar: " + Object.keys(KAYITLAR[0]).join(", ") + "\n");
  const y = gen([12, 9, 11, 11, 11]);
  console.log(y(["sozlesme", "abone", "0-30 gun", "31-90 gun", "90+ gun"]));
  for (const s of ["etkin", "askida", "kapali"]) {
    const l = KAYITLAR.filter((k) => k.sozlesme === s);
    console.log(y([s, l.length, l.filter((k) => k.sonOkumaGun <= 30).length,
      l.filter((k) => k.sonOkumaGun > 30 && k.sonOkumaGun <= 90).length,
      l.filter((k) => k.sonOkumaGun > 90).length]));
  }
  const t = (f) => KAYITLAR.filter(f).length;
  console.log(y(["toplam", ABONE, t((k) => k.sonOkumaGun <= 30),
    t((k) => k.sonOkumaGun > 30 && k.sonOkumaGun <= 90), t((k) => k.sonOkumaGun > 90)]));
}
```

```
tohum 20260601: 4800 satir, 10 alan
alanlar: i, bolge, basamak, baglantiGun, kapanisGun, sozlesme, sonOkumaGun, tuketim, ucret, destek

sozlesme        abone   0-30 gun  31-90 gun    90+ gun
etkin            3849       3376         88        385
askida            362        121         55        186
kapali            589         51         59        479
toplam           4800       3548        202       1050
```

Tablo dört köşesiyle okunur. Sol üst köşe beklenen durumdur: sözleşmesi etkin olan 3 376 abonenin
sayacı son 30 gün içinde okuma göndermiştir. Sağ üst köşe beklenmeyendir: sözleşmesi etkin olan
385 abonenin sayacı 90 günden uzun süredir susmaktadır. Sol alt köşe de beklenmeyendir: sözleşmesi
kapalı olan 51 abonenin sayacı son 30 gün içinde okuma göndermiştir.

Bu iki köşe bir veri hatası değildir; ikisinin de olağan bir açıklaması vardır. Susan sayaç arızalı
olabilir ya da konut boş olabilir. Kapalı sözleşmeden okuma gelmesi, kapanış kaydının işlenmesiyle
sayacın sökülmesi arasında geçen süredir. **Kayıt sistemi ile fiziksel dünya farklı hızlarda
ilerler** ve tablo ikisini ayrı sütunlarda tutar.

Soru bu tabloya sorulduğunda cevap tek değildir, çünkü "etkin abone" sözü hangi sütuna
bakılacağını söylemez.

#### Üç Tanım, Üç Sayı

Aşağıdaki blok aynı kümeye üç tanımı ayrı ayrı uygular ve sonuçları yan yana basar. Üçü de
savunulabilir tanımlardır: birincisi kayıt sistemine, ikincisi sayacın davranışına, üçüncüsü
sözleşmenin hukuki durumuna bakar.

```js
// etkin.mjs — ayni ham kumeden "etkin abone sayisi": uc savunulabilir tanim yan yana.
import { KAYITLAR, ABONE, TOHUM } from "./kume.mjs";

const TANIM = [
  { ad: "A: sozlesme kaydi etkin", f: (k) => k.sozlesme === "etkin" },
  { ad: "B: 30 gunde okuma var", f: (k) => k.sonOkumaGun <= 30 },
  { ad: "C: sozlesme acik", f: (k) => k.sozlesme !== "kapali" },
];
const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j])
  : String(v).padEnd(B[0]))).join("");

const S = TANIM.map((t) => new Set(KAYITLAR.filter(t.f).map((k) => k.i)));
const y = gen([26, 8, 10]);
console.log(`tohum ${TOHUM}: ${ABONE} abone kaydi, tek tablo, tek olcum gunu\n`);
console.log(y(["tanim", "abone", "% kayit"]));
TANIM.forEach((t, a) => console.log(y([t.ad, S[a].size,
  ((100 * S[a].size) / ABONE).toFixed(1)])));

const z = gen([10, 9, 11, 11, 13]);
console.log("\n" + z(["cift", "fark", "yalniz ilk", "yalniz son", "anlasmazlik"]));
for (const [a, b] of [[0, 1], [2, 0], [2, 1]]) {
  const i1 = [...S[a]].filter((i) => !S[b].has(i)).length;
  const i2 = [...S[b]].filter((i) => !S[a].has(i)).length;
  console.log(z([`${"ABC"[a]} - ${"ABC"[b]}`, S[a].size - S[b].size, i1, i2, i1 + i2]));
}

// B tanimindaki tek serbest sayi pencere uzunlugudur; okuma dongusu aylik oldugu icin
// 30 gunden kisa pencere sayacin hic gonderemedigi bir sikligi sorar.
const w = gen([9, 9, 12]);
console.log("\n" + w(["pencere", "abone", "A'ya oran"]));
for (const p of [14, 21, 30, 45, 60, 90]) {
  const n = KAYITLAR.filter((k) => k.sonOkumaGun <= p).length;
  console.log(w([`${p} gun`, n, (n / S[0].size).toFixed(2)]));
}
```

```
tohum 20260601: 4800 abone kaydi, tek tablo, tek olcum gunu

tanim                        abone   % kayit
A: sozlesme kaydi etkin       3849      80.2
B: 30 gunde okuma var         3548      73.9
C: sozlesme acik              4211      87.7

cift           fark yalniz ilk yalniz son  anlasmazlik
A - B           301        473        172          645
C - A           362        362          0          362
C - B           663        714         51          765

pencere      abone   A'ya oran
14 gun        1859        0.48
21 gun        2733        0.71
30 gun        3548        0.92
45 gun        3602        0.94
60 gun        3654        0.95
90 gun        3750        0.97
```

Üç tanım üç sayı verdi: 3 849, 3 548 ve 4 211. Aradaki en büyük fark 663 abonedir, kayıtların
yüzde 13,8'i. Hiçbir hesap değişmedi — üç tanım da tek bir süzme işlemidir ve hiçbiri diğerinden
daha karmaşık değildir. Değişen tek şey hangi sütuna bakıldığıdır.

İkinci tablo daha önemli bir şey yazıyor. A ile B'nin toplamları yalnız **301** fark ediyor, ama
iki tanımın **anlaşmadığı abone sayısı 645**. 473 abone yalnız A'da, 172 abone yalnız B'de. Toplam
fark küçük görünüyor çünkü iki yönlü anlaşmazlığın büyük bölümü birbirini götürüyor. **Toplamların
yakın olması, iki tanımın aynı kişileri saydığı anlamına gelmez.** Bir raporda "iki yöntem de
yaklaşık aynı sonucu veriyor" cümlesi yazılacaksa, ölçülmesi gereken şey toplamların farkı değil,
kayıt düzeyindeki anlaşmazlıktır.

#### Pencere de Bir Karardır

B tanımı bir sayı içeriyor: 30 gün. Bu sayı veriden gelmedi, seçildi. Üçüncü tablo seçimin
bedelini yazıyor: pencere 14 güne indirildiğinde etkin abone 1 859'a düşüyor, 90 güne açıldığında
3 750'ye çıkıyor. Aynı tablo, aynı soru, aynı hesap; sonuç iki katından fazla oynuyor.

Pencerenin her değeri savunulabilir değildir. AK4 okuma döngüsünün aylık olduğunu söylüyor; 14
günlük pencere, sayacın göndermesi beklenmeyen bir sıklığı ölçüt yapar ve etkin abonelerin yarısını
susmuş sayar. 90 günlük pencere ise ters yöne düşer: üç ay boyunca hiç okuma göndermemiş bir sayacı
etkin sayar. 30 ile 60 arasındaki değerler sonucu yalnız 106 abone oynatıyor — yani bu aralıkta
tanım sağlamdır. **Bir eşiğin savunulabilirliği, sonucun o eşik etrafında ne kadar oynadığına
bakılarak ölçülür.** Eşiği 14'ten 21'e taşımak sayıyı 874 abone oynatıyor; 45'ten 60'a taşımak 52
abone. İlk bölge kırılgan, ikinci bölge kararlı.

#### Sıralama da Oynar

Bir raporda tek bir toplam nadiren durur. Toplamın yanında bir kırılım olur ve birileri o
kırılımın en üstündeki satıra göre iş yapar: önce hangi bölgeye gidilecek, bütçe önce nereye
verilecek. Tanım kararı toplamı oynatıyorsa sıralamayı da oynatır.

```js
// bolge.mjs — tanim karari yalniz toplami degil siralamayi da oynatir: bes bolge, iki tanim.
import { KAYITLAR, BOLGE } from "./kume.mjs";

const oran = (l, f) => l.filter(f).length / l.length;
const sat = BOLGE.map((b) => {
  const l = KAYITLAR.filter((k) => k.bolge === b);
  return { b, n: l.length, a: oran(l, (k) => k.sozlesme === "etkin"),
    c: oran(l, (k) => k.sonOkumaGun <= 30) };
});
// Sira 1 = en dusuk oran, yani raporda "once bakilacak" bolge.
const sira = (alan) => new Map([...sat].sort((x, y) => x[alan] - y[alan])
  .map((s, i) => [s.b, i + 1]));
const sA = sira("a"), sB = sira("c");

const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j])
  : String(v).padEnd(B[0]))).join("");
const y = gen([9, 8, 10, 8, 10, 8, 8]);
console.log(y(["bolge", "abone", "A orani", "A sira", "B orani", "B sira", "kayma"]));
for (const s of sat) {
  console.log(y([s.b, s.n, s.a.toFixed(4), sA.get(s.b), s.c.toFixed(4), sB.get(s.b),
    sB.get(s.b) - sA.get(s.b)]));
}
const ilk = (alan) => [...sat].sort((x, y2) => x[alan] - y2[alan]);
const yay = (alan) => Math.max(...sat.map((s) => s[alan])) - Math.min(...sat.map((s) => s[alan]));
console.log(`\nA tanimiyla ilk bakilacak bolge ${ilk("a")[0].b}, B tanimiyla ${ilk("c")[0].b}`);
console.log(`B'de ilk iki bolgeyi ayiran fark ${(ilk("c")[1].c - ilk("c")[0].c).toFixed(4)}, ` +
  `bes bolgenin tum yayilimi ${yay("c").toFixed(4)}`);
```

```
bolge       abone   A orani  A sira   B orani  B sira   kayma
kuzey         929    0.7976       3    0.7277       3       0
guney         913    0.7985       4    0.7240       1      -3
dogu          999    0.8248       5    0.7648       5       0
bati          969    0.7905       1    0.7245       2       1
merkez        990    0.7970       2    0.7525       4       2

A tanimiyla ilk bakilacak bolge bati, B tanimiyla guney
B'de ilk iki bolgeyi ayiran fark 0.0005, bes bolgenin tum yayilimi 0.0408
```

Listenin başı değişti: A tanımıyla ilk bakılacak bölge batı, B tanımıyla güney. Merkez iki sıra
yukarı kaydı, güney üç sıra aşağı. Doğu her iki tanımda da en iyi bölge kaldı — kayma her satırda
olmuyor, ama karar verilen satırda oluyor.

Nedeni son satırda yazılı. Beş bölgenin oranı B tanımında yalnız 0,0408 aralığa yayılıyor. İki
tanım arasındaki fark ise ağ genelinde 6,3 puandır — ikinci tablodaki yüzde 80,2 ile yüzde 73,9
arasındaki fark. **Gruplar arası fark, tanım değişikliğinin ürettiği kaymadan küçükse sıralama
bölgelerin değil tanımın bir özelliğidir.** B tanımında ilk iki bölgeyi ayıran fark 0,0005;
güneyde tek bir sayacın okuma göndermesi (661 yerine 662) sıralamayı ters çevirir. Saha ekibini bu
listenin başına göre yönlendirmek, bir yuvarlama farkına göre yönlendirmektir.

#### Kararı Yazılmayan Sayı

Bu dersin ürettiği sayı 3 548'dir: son 30 gün içinde okuma göndermiş abone sayısı. Yanında üç
karar durur ve üçü de yazılmadan sayı raporlanamaz:

- **Hangi sütun ölçüt.** Sayacın davranışı ölçüt alındı, sözleşme kaydı değil. Gerekçe: soru "kaç
  aboneye fatura kesilebilir" sorusuna hizmet ediyorsa okuma olmadan fatura da olmaz.
- **Pencere 30 gün.** Gerekçe: okuma döngüsü aylıktır ve sonuç 30 ile 60 arasında 106 abone
  oynuyor, yani seçim bu aralıkta sonucu belirlemiyor.
- **Sözleşme durumu süzülmedi.** Sözleşmesi kapalı 51 abone, okuma gönderdiği için sayının içinde
  kaldı. Gerekçe: fatura kesilebilirlik sorusunda bunlar da sayılır; kapanışın işlenmemiş olması
  ayrı bir sorundur.

Bu üç satır yazılmadığında geriye 3 548 sayısı kalır ve o sayı bir bulgu değil, bir seçimdir.
**Kararı yazılmayan sayı ölçülmemiş sayılır.** Bu kural müfredat boyunca sürecek ve her derste
aynı biçimde uygulanacak: rapor edilen sayı, onu üretirken alınan kararlar, kararı değiştirince
ortaya çıkan fark.

Buradan çıkan ikinci sonuç daha rahatsız edicidir. "Veri konuşur" diye bir şey yoktur. Bu tabloda
üç doğru sayı vardır ve hiçbiri diğerini yanlışlamaz; hangisinin raporlanacağını belirleyen şey
veri değil, sorunun ne için sorulduğudur. Aynı tablodan bir sayaç değiştirme listesi çıkarılacaksa
A ile B'nin anlaşmadığı 645 abone hedeftir; bir fatura kesimi yapılacaksa B'dir; bir sözleşme
sayımı raporlanacaksa C. Analitiğin işi bu üç sayıdan birini seçmek değil, hangisinin hangi soruya
karşılık geldiğini yazmaktır.

#### Özet

- Veri analitiği bir soruyu ölçülebilir duruma getirme işidir; sayı çoğu zaman hesap sırasında
  değil, tanım sırasında belirlenir.
- Tek bir abone tablosundan "etkin abone" üç savunulabilir tanımla üç ayrı sayı verir: 3 849
  (sözleşme kaydı etkin), 3 548 (son 30 günde okuma var), 4 211 (sözleşme açık).
- Toplamların yakınlığı anlaşmayı göstermez: A ile B'nin toplam farkı 301, ama kayıt düzeyinde
  anlaşmadıkları abone sayısı 645.
- Tanımın içindeki eşik de bir karardır; pencere 14 günden 90 güne açıldığında sayı 1 859'dan
  3 750'ye çıkar. Eşiğin savunulabilirliği sonucun o eşik etrafındaki oynaklığıyla ölçülür.
- Tanım kararı sıralamayı da oynatır: ilk bakılacak bölge A tanımıyla batı, B tanımıyla güneydir
  ve B'de ilk iki bölgeyi tek bir sayacın okuması ayırır.
- Bir sayının yanında hangi kararla üretildiği yazılmıyorsa o sayı bir bulgu değil bir seçimdir;
  kararı yazılmayan sayı ölçülmemiş sayılır.

#### Sonraki Adım

Bu ders tek bir soruyu ölçülebilir duruma getirdi: **kaç etkin abone var.** Sorunun kendisi
sorgulanmadı. Oysa aynı tabloya sorulabilecek sorular tek bir çeşit değildir. "Kaç abone var"
sorusu geçmişi anlatır; "abone sayısı neden düştü" sorusu bir neden ister; "gelecek çeyrekte kaç
abone olacak" sorusu bir tahmin ister; "hangi aboneye önce gidilmeli" sorusu bir eylem önerir.
Dördü de aynı tabloya sorulabilir, ama dördü aynı veriyle cevaplanamaz. Sonraki ders bu dört soru
çeşidini ayırır ve bir soru kümesinde kaçının eldeki kümeyle cevaplanabildiğini sayar.

### Analitik Türleri

Source: https://academia.sh/tr/kurslar/veri-analitigine-giris/analitik-turleri

Aynı abone tablosuna sorulan 16 soru betimsel, tanısal, öngörücü ve önerici olarak ayrılıyor; cevaplanabilir soru sayısı iki karara göre 2 ile 7 arasında oynuyor. Türetilmiş alan var sayılınca 5 soru açılıyor, öngörücü soru için istenen geçmiş derinliği 3 dönemden 12 döneme çıkınca 2 soru kapanıyor. Önerici türün dört sorusu dört karar bileşiminin hiçbirinde açılmıyor, çünkü tabloda olan bitenin kaydı var, denenenin kaydı yok.

Önceki ders tek bir soruyu ölçülebilir duruma getirdi: ağda kaç etkin abone var. Sorunun kendisi
sorgulanmadı. Oysa aynı tabloya sorulabilecek sorular tek çeşit değildir ve çeşit değiştiğinde
tablodan istenen şey de değişir. "Kaç abone var" sorusu kayıtta duranı özetler; "abone sayısı
neden düştü" bir neden ister; "gelecek ay kaç abone olacak" bir tahmin ister; "hangi aboneye önce
gidilmeli" bir eylemin sonucunu ister.

Bu ders dört çeşidi ayırır ve her çeşidin **hangi veriyi istediğini** ölçer. Ölçülen sayı, bir soru
kümesinde eldeki veriyle cevaplanabilen soru sayısıdır. Bu sayının da bir tanımı vardır ve tanım
iki karara bağlıdır; iki karar değiştiğinde aynı 16 soru üzerinden çıkan cevap sayısı 2 ile 7
arasında oynar.

- **AK7.** Eldeki küme önceki dersin abone tablosudur; yanına sayaç okumalarının **son dört aylık
  özeti** eklenmiştir. Geçmiş derinliği dört dönemdir. Küme de sorular da **kurgudur**.
- **AK8.** Soru kümesi 16 sorudan oluşur, her türden dördü.
- **AK9.** Bir soru **cevaplanabilir** sayılır: istediği her alan ya kümede durur ya
  türetilebilir ve istediği geçmiş derinliği elde vardır. Cevabın **doğru** olup olmadığı ayrı
  bir sorudur; burada ölçülen şey verinin yeterliliğidir, cevabın niteliği değil.
- **AK10.** **Türetilebilir alan** diskte durmaz ama duran alanlardan hesaplanır. Hesabı bir
  karar ister: önceki dersin "hangi aboneler paydaya girer" sorusu her türetmede yeniden çıkar.
- **AK11.** İki karar ölçülür. Birincisi: türetilebilir alan "var" sayılır mı (sıkı okuma) yoksa
  sayılmaz mı (gevşek okuma). İkincisi: öngörücü bir soruyu cevaplanabilir saymak için en az kaç
  dönem geçmiş istenir — 3 mü, 12 mi.

#### Dört Çeşit Soru

Dört tür, dört ayrı zaman kipine karşılık gelir.

**Betimsel analitik** (descriptive analytics) *ne oldu* sorusunu sorar. Kayıtta duranı özetler:
sayar, toplar, oranlar, kırar. Önceki dersin bütün işi betimseldi. İstediği veri kayıtta duranın
kendisidir; bu yüzden dört tür arasında veri isteği en hafif olanıdır.

**Tanısal analitik** (diagnostic analytics) *neden oldu* sorusunu sorar. Bir neden ister ve neden
kayıtta bir alan olarak durmuyorsa, nedeni ayırt edecek bir karşılaştırma ister. Kapanış nedeni
kaydedilmemişse, kapanan aboneleri kapanmayanlarla karşılaştırmak bir **birliktelik** verir; o
birlikteliğin neden olduğunu söylemek ayrı bir karardır ve veriden çıkmaz.

**Öngörücü analitik** (predictive analytics) *ne olacak* sorusunu sorar. Geçmişte gözlenen bir
düzenin sürdüğü varsayımına dayanır, dolayısıyla düzeni görecek kadar geçmiş ister. "Kaç dönem
yeter" sorusunun veriden gelen bir cevabı yoktur; bu bir eşik kararıdır ve bu dersin ikinci ölçüsü
odur.

**Önerici analitik** (prescriptive analytics) *ne yapılmalı* sorusunu sorar. Bir eylemin sonucunu
ister: indirim verilirse ne olur, ziyaret yapılırsa ne değişir. Eylem hiç denenmemişse sonucu
kayıtta yoktur; denenmiş ama sonucu kaydedilmemişse de yoktur.

#### Eldeki Küme ve Soru Kümesi

```js
// envanter.mjs — eldeki kume ile bir soru kumesi; her soru bir tur ve bir veri istegidir.
// MODELDIR: alanlar da sorular da bolgesel olcum aginin kurgusundan gelir.
export const DERINLIK = 4; // elde kac donemlik (aylik) gecmis duruyor

export const VAR = new Set(["abone kimligi", "bolge", "tarife basamagi", "baglanti gunu",
  "kapanis gunu", "sozlesme durumu", "son okuma gunu", "aylik tuketim", "aylik ucret",
  "destek talebi sayisi"]);

// Turetilebilir alan diskte durmaz ama duran alanlardan hesaplanir; hesabi bir karar ister.
export const TURETILEBILIR = new Map([
  ["abone yasi", "baglanti gunu"],
  ["kapanma orani", "kapanis gunu + sozlesme durumu"],
  ["abone basina tuketim", "aylik tuketim + abone kimligi"],
  ["tuketim degisim hizi", "aylik tuketim (dort donem)"],
]);

export const SORULAR = [
  { s: "kac abone son 30 gunde okuma gonderdi", t: "betimsel", a: ["son okuma gunu"], d: 1 },
  { s: "hangi bolgede abone basina tuketim yuksek", t: "betimsel",
    a: ["bolge", "abone basina tuketim"], d: 1 },
  { s: "tarife basamaklarina gore abone dagilimi", t: "betimsel", a: ["tarife basamagi"], d: 1 },
  { s: "dort ayda toplam tuketim nasil degisti", t: "betimsel", a: ["tuketim degisim hizi"], d: 4 },
  { s: "aboneler sozlesmeyi neden kapatti", t: "tanisal", a: ["kapanis nedeni"], d: 1 },
  { s: "okuma dususu bir kesintiden mi geldi", t: "tanisal", a: ["kesinti kaydi"], d: 1 },
  { s: "destek artisi tarife degisiminden mi", t: "tanisal",
    a: ["destek talebi sayisi", "tarife degisim gecmisi"], d: 1 },
  { s: "kapanma orani basamaga gore degisiyor mu", t: "tanisal",
    a: ["kapanma orani", "tarife basamagi"], d: 1 },
  { s: "gelecek ay kac abone kapatir", t: "ongorucu", a: ["kapanma orani"], d: 1 },
  { s: "gelecek ceyrekte toplam tuketim ne olur", t: "ongorucu", a: ["tuketim degisim hizi"], d: 4 },
  { s: "hangi abonenin sayaci gelecek ay susar", t: "ongorucu", a: ["okuma gecmisi"], d: 1 },
  { s: "gelecek ay destek talebi sayisi ne olur", t: "ongorucu", a: ["destek gecmisi"], d: 1 },
  { s: "hangi aboneye once saha ziyareti yapilmali", t: "onerici", a: ["mudahale ve sonucu"], d: 1 },
  { s: "basamak degistirilirse kapanma azalir mi", t: "onerici",
    a: ["mudahale ve sonucu", "tarife degisim gecmisi"], d: 1 },
  { s: "sayac yenileme butcesi hangi bolgeye", t: "onerici", a: ["mudahale ve sonucu"], d: 1 },
  { s: "kapanacak aboneye indirim teklif edilmeli mi", t: "onerici",
    a: ["mudahale ve sonucu"], d: 1 },
];
export const TURLER = ["betimsel", "tanisal", "ongorucu", "onerici"];

// Iki karar: turetilmis alan "var" sayilir mi, ve ongorucu soru kac donem gecmis ister.
export function eksik(soru, gevsek) {
  return soru.a.filter((x) => !VAR.has(x) && !(gevsek && TURETILEBILIR.has(x)));
}
export function cevaplanir(soru, gevsek, ongoruSarti) {
  const gereken = soru.t === "ongorucu" ? Math.max(soru.d, ongoruSarti) : soru.d;
  return eksik(soru, gevsek).length === 0 && gereken <= DERINLIK;
}

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(`elde ${VAR.size} alan ve ${DERINLIK} donemlik gecmis var; ` +
    `${TURETILEBILIR.size} alan turetilebilir\n`);
  const y = gen([45, 10, 7]);
  console.log(y(["soru", "tur", "donem"]) + "  eksik alan (siki okuma)");
  for (const q of SORULAR) {
    const e = eksik(q, false);
    console.log(y([q.s, q.t, q.d]) + "  " + (e.length ? e.join(", ") : "-"));
  }
}
```

```
elde 10 alan ve 4 donemlik gecmis var; 4 alan turetilebilir

soru                                                tur  donem  eksik alan (siki okuma)
kac abone son 30 gunde okuma gonderdi          betimsel      1  -
hangi bolgede abone basina tuketim yuksek      betimsel      1  abone basina tuketim
tarife basamaklarina gore abone dagilimi       betimsel      1  -
dort ayda toplam tuketim nasil degisti         betimsel      4  tuketim degisim hizi
aboneler sozlesmeyi neden kapatti               tanisal      1  kapanis nedeni
okuma dususu bir kesintiden mi geldi            tanisal      1  kesinti kaydi
destek artisi tarife degisiminden mi            tanisal      1  tarife degisim gecmisi
kapanma orani basamaga gore degisiyor mu        tanisal      1  kapanma orani
gelecek ay kac abone kapatir                   ongorucu      1  kapanma orani
gelecek ceyrekte toplam tuketim ne olur        ongorucu      4  tuketim degisim hizi
hangi abonenin sayaci gelecek ay susar         ongorucu      1  okuma gecmisi
gelecek ay destek talebi sayisi ne olur        ongorucu      1  destek gecmisi
hangi aboneye once saha ziyareti yapilmali      onerici      1  mudahale ve sonucu
basamak degistirilirse kapanma azalir mi        onerici      1  mudahale ve sonucu, tarife degisim gecmisi
sayac yenileme butcesi hangi bolgeye            onerici      1  mudahale ve sonucu
kapanacak aboneye indirim teklif edilmeli mi    onerici      1  mudahale ve sonucu
```

Son sütun eksikleri iki gruba ayırıyor. Bir grup **türetilebilir** alanlardır: abone başına
tüketim, kapanma oranı, tüketim değişim hızı. Bunlar diskte durmaz ama duran alanlardan hesaplanır.
Diğer grup **hiç olmayan** alanlardır: kapanış nedeni, kesinti kaydı, okuma geçmişi, destek
geçmişi, tarife değişim geçmişi, müdahale ve sonucu. Bunlar hesapla üretilemez, çünkü kaynakta
kaydedilmemişlerdir.

Ayrım önemlidir, çünkü ilk grup bir karara açıktır, ikinci grup değildir. Türetilebilir alanın
"var" sayılıp sayılmaması bir okuma tercihidir. Hiç olmayan alanın var sayılması diye bir tercih
yoktur; o veri toplanana kadar soru cevapsızdır.

#### İki Karar, İki Sayı

```js
// karar.mjs — ayni 16 soru, ayni tablo, iki karar: cevaplanabilir soru sayisi yan yana.
import { SORULAR, TURLER, DERINLIK, cevaplanir, eksik } from "./envanter.mjs";

const BILESIM = [
  { ad: "siki / 3 donem", g: false, o: 3 },
  { ad: "gevsek / 3 donem", g: true, o: 3 },
  { ad: "siki / 12 donem", g: false, o: 12 },
  { ad: "gevsek / 12 donem", g: true, o: 12 },
];
const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j])
  : String(v).padEnd(B[0]))).join("");

const y = gen([20, 10, 9, 10, 9, 8]);
console.log(`elde ${DERINLIK} donemlik gecmis var; asagidaki sayilar cevaplanabilir soru sayisi\n`);
console.log(y(["karar bilesimi", ...TURLER, "toplam"]));
const satir = BILESIM.map((b) => {
  const c = TURLER.map((t) =>
    SORULAR.filter((q) => q.t === t && cevaplanir(q, b.g, b.o)).length);
  console.log(y([b.ad, ...c, c.reduce((x, v) => x + v, 0)]));
  return c.reduce((x, v) => x + v, 0);
});

console.log(`\nayni 16 soru: en dusuk ${Math.min(...satir)}, en yuksek ${Math.max(...satir)} ` +
  `cevap; fark ${Math.max(...satir) - Math.min(...satir)} soru`);
const acilan = SORULAR.filter((q) => !cevaplanir(q, false, 3) && cevaplanir(q, true, 3));
console.log(`turetilmis alan sayilinca acilan ${acilan.length} soru: ` +
  acilan.map((q) => q.t).join(", "));
for (const t of TURLER) {
  const hic = SORULAR.filter((q) => q.t === t)
    .every((q) => BILESIM.every((b) => !cevaplanir(q, b.g, b.o)));
  if (hic) {
    const n = SORULAR.filter((q) => q.t === t);
    const ortak = [...new Set(n.flatMap((q) => eksik(q, true)))];
    console.log(`\n${t} tur dort kararin hicbirinde acilmiyor: ${n.length} soru, 0 cevap`);
    console.log(`hicbir kararla kapanmayan eksik: ${ortak.join(", ")}`);
  }
}
```

```
elde 4 donemlik gecmis var; asagidaki sayilar cevaplanabilir soru sayisi

karar bilesimi        betimsel  tanisal  ongorucu  onerici  toplam
siki / 3 donem               2        0         0        0       2
gevsek / 3 donem             4        1         2        0       7
siki / 12 donem              2        0         0        0       2
gevsek / 12 donem            4        1         0        0       5

ayni 16 soru: en dusuk 2, en yuksek 7 cevap; fark 5 soru
turetilmis alan sayilinca acilan 5 soru: betimsel, betimsel, tanisal, ongorucu, ongorucu

onerici tur dort kararin hicbirinde acilmiyor: 4 soru, 0 cevap
hicbir kararla kapanmayan eksik: mudahale ve sonucu, tarife degisim gecmisi
```

Aynı tablo, aynı 16 soru; cevaplanabilir soru sayısı 2 ile 7 arasında. Fark 5 sorudur, kümenin
neredeyse üçte biri. İki kararın hiçbiri veriye dokunmadı; ikisi de "elimizde ne var" sorusunun
cevabını değiştirdi.

Birinci karar tek başına en büyük etkiyi yapıyor. Türetilmiş alan var sayılınca 5 soru açılıyor:
iki betimsel, bir tanısal, iki öngörücü. Bu karar bedava değildir. Kapanma oranı türetilecekse
payda seçilmelidir ve önceki ders paydanın üç savunulabilir değeri olduğunu gösterdi. Yani
"türetilebilir alan vardır" demek, sorunun cevabına yeni bir tanım kararı eklemek demektir.
**Gevşek okuma soruyu açar ama beraberinde yazılması gereken karar sayısını artırır.**

İkinci karar yalnız öngörücü satırı oynatıyor: derinlik şartı 3'ten 12'ye çıkınca iki öngörücü
soru kapanıyor, toplam 7'den 5'e iniyor. Elde dört dönem geçmiş var; bu 3 şartını geçer, 12
şartını geçmez. Şartın kendisi veriden okunmaz. Dört dönemin bir yıllık dalgalanmayı
göstermeyeceğini savunmak da, dört dönemin bir aylık tahmine yeteceğini savunmak da mümkündür.
Rapora yazılması gereken şey hangisinin seçildiğidir.

Tanısal satır dört kararda en fazla 1'e çıkıyor. Açılan soru kapanma oranının tarife basamağına
göre değişip değişmediğidir ve verdiği şey bir birlikteliktir: hangi basamakta kapanmanın daha sık
olduğu. Kapanışın nedeninin basamak olduğu sonucu bu tablodan çıkmaz. Nedeni ayırt edecek şey ya
kapanış nedeninin kaydı ya da nedeni tek başına değiştiren bir karşılaştırmadır; kümede ikisi de
yok. **Bir tanısal sorunun cevaplanabilir sayılması, cevabın bir neden olacağı anlamına gelmez.**

#### Kapanmayan Boşluk

Dört satırın hepsinde önerici sütunu sıfırdır. Bu, dersin en sağlam sayısıdır çünkü hiçbir karara
duyarlı değildir. Ortak eksik iki alandır ve biri belirleyicidir: **müdahale ve sonucu.**

Tablo olan bitenin kaydıdır. Hangi abonenin sözleşmesi kapandı, ne zaman kapandı, kapanmadan önce
ne kadar tüketti — hepsi yazılı. Yazılı olmayan şey şudur: o aboneye bir şey yapıldı mı, yapıldıysa
ne yapıldı, yapıldıktan sonra ne oldu. Bir indirim teklifinin kapanmayı azaltıp azaltmadığı,
ancak bazı abonelere teklif verilip bazılarına verilmediği ve ikisinin sonucunun ayrı ayrı
kaydedildiği bir düzenekten okunur. Böyle bir düzenek kurulmadıysa veri kümesi ne kadar büyürse
büyüsün bu soru cevaplanmaz.

Buradan çıkan kural şudur: **veri toplamak bir analiz kararıdır ve analizden önce alınır.** Önerici
sorulara cevap veren bir ağ, o soruları soracağını bilerek müdahale kaydı tutan ağdır. Elde tutulan
kaydın türü hangi soruların sorulabileceğini belirler; soru kümesi genişledikçe kayıt kendiliğinden
genişlemez.

#### Özet

- Dört analitik türü dört ayrı soru sorar: ne oldu (betimsel), neden oldu (tanısal), ne olacak
  (öngörücü), ne yapılmalı (önerici). Türün değişmesi tablodan istenen veriyi değiştirir.
- Aynı 16 soru ve aynı tablo üzerinde cevaplanabilir soru sayısı 2 ile 7 arasında oynar; iki karar
  veriye hiç dokunmadan bu farkı üretir.
- Türetilmiş alanın var sayılması 5 soru açar ama her türetme yeni bir tanım kararı ekler;
  öngörücü derinlik şartı 3'ten 12'ye çıkınca iki soru kapanır.
- Cevaplanabilir sayılan tanısal soru bir birliktelik verir; nedeni ayırt edecek kayıt ya da
  karşılaştırma kümede yoktur.
- Önerici türün dört sorusu dört karar bileşiminin hiçbirinde açılmaz, çünkü kümede müdahale ve
  sonucunun kaydı yoktur; veri toplama kararı analizden önce alınır.

#### Sonraki Adım

Bu ders ile önceki ders birlikte bir izlenim bırakabilir: önce soru seçilir, sonra türü belirlenir,
sonra veri yeter mi diye bakılır, sonra hesap yapılır. Sıralı bir liste gibi görünüyor. Gerçekte bu
liste bir kez baştan sona koşmaz. Önceki dersteki pencere kararı, ancak veriye bakıldıktan sonra
savunulabilir hale geldi; bu dersteki derinlik şartı, ancak soru kümesi yazıldıktan sonra bir sayı
kazandı. Her ikisinde de sonraki adımda öğrenilen bir şey, önceki adımda yazılmış bir kararı
değiştirdi. Sonraki ders analiz iş akışını beş adımda kurar ve akışın kaç kez geriye döndüğünü
sayar.

### Analiz İş Akışı

Source: https://academia.sh/tr/kurslar/veri-analitigine-giris/analiz-is-akisi

Soru, veri, çözümleme, bulgu ve iletişim adımlarından oluşan beş adımlık akış, 12 kararla birlikte koşturuluyor: kararların 10'u ait olduğu adımdan sonra görülüyor. Kararlar görüldükçe yazıldığında akış 10 geri dönüş ve 33 adım ziyareti üretiyor, her karar ait olduğu adımda yazıldığında 5 dönüş ve 15 ziyarete, bir ön bakış eklendiğinde 1 dönüş ve 8 ziyarete iniyor. Kalan tek dönüş kapanmaz, çünkü içeriği ham veride değil çözümlemenin çıktısındadır. Muhasebe kararı değişince aynı akış 33 yerine 15 ziyaret verir.

Önceki iki ders bir izlenim bırakmış olabilir: önce soru seçilir, sonra türü belirlenir, sonra veri
yeter mi diye bakılır, sonra hesap yapılır. Sıralı bir liste gibi görünüyor. Gerçekte bu liste bir
kez baştan sona koşmaz. Birinci dersteki 30 günlük pencere, ancak tabloya bakılıp okuma
döngüsünün aylık olduğu görüldükten sonra savunulabilir hale geldi; ikinci dersteki derinlik şartı,
ancak soru kümesi yazıldıktan sonra bir sayı kazandı.

Bu ders akışı beş adımda kurar ve akışın doğrusal olmadığını bir sayıyla gösterir. Ölçü **geri
dönüş sayısıdır**: sonraki bir adımda görülen bir karar yüzünden kaç kez önceki bir adıma dönmek
gerekti. Yanına ikinci bir sayı konur: akışın beş adımı toplam kaç kez koşturuldu.

- **AK12.** Akış beş adımdır: **soru**, **veri**, **çözümleme**, **bulgu**, **iletişim**. Akış da
  kararlar da **kurgudur**; kararlar önceki iki dersin abone sayımından alınmıştır.
- **AK13.** Bir **geri dönüş**, sonraki bir adımda görülen bir kararın ait olduğu adıma dönülmesi
  ve aradaki adımların yeniden koşturulmasıdır.
- **AK14.** **Adım ziyareti** şöyle sayılır: akış bir kez baştan sona koşarsa 5 ziyaret olur; $f$
  adımından $a$ adımına bir dönüş $f - a + 1$ ziyaret ekler. Bu bir **muhasebe kararıdır** ve
  dersin sonunda değiştirilecektir.
- **AK15.** Bir karar **önceden yazılabilir** sayılır: ait olduğu adımda, sonraki adımın çıktısına
  bakılmadan yazılabiliyorsa. Yazılamıyorsa kararın içeriği ancak sonraki adımda öğrenilir.
- **AK16.** Süre ölçülmez. Sayılan şey dönüş ve ziyarettir.

#### Beş Adım

**Soru** adımı sorulacak şeyi ölçülebilir duruma getirir: hangi tanım, hangi ölçüm günü, sonuç
hangi kararı besleyecek, kim okuyacak. Birinci dersin bütün konusu bu adımdı.

**Veri** adımı sorunun istediği alanları bulur ve kümenin gerçek durumunu görür: hangi alan dolu,
hangi satır yinelenmiş, hangi değer eksik. İkinci dersin envanteri bu adımın çıktısıdır.

**Çözümleme** adımı süzer, gruplar, özetler; sayı burada çıkar. Tablo tasarımı ve sorgu yazımı
Veritabanı Temelleri kursunda kuruldu, burada tekrarlanmaz; bu adımda ölçülen şey sözdizimi değil,
süzme ve gruplama kararlarıdır.

**Bulgu** adımı sayıyı bir cümleye çevirir: kırılım, sıralama, karşılaştırma. **İletişim** adımı
bulguyu bir karara bağlar ve okuyacak tarafa yazar. Son iki adım karar üretmez, kararları tüketir
— ve tam bu yüzden orada görülen eksik bir karar akışı en başa gönderir.

#### Kararlar Nerede Doğar, Nerede Görülür

```js
// akis.mjs — bes adimli analiz akisi ve akisi geriye donduren kararlar. MODELDIR:
// kararlar onceki iki dersin abone sayimindan alinmis, akis kurgudur.
export const ADIM = ["soru", "veri", "cozumleme", "bulgu", "iletisim"];

// ait: kararin yazilmasi gereken adim. gorulur: kararin fark edildigi adim.
// onceden: karar, ait oldugu adimda veriye bakmadan yazilabilir mi.
export const KARARLAR = [
  { ad: "etkin abone tanimi", ait: 1, gorulur: 1, onceden: true },
  { ad: "olcum gunu", ait: 1, gorulur: 1, onceden: true },
  { ad: "okuma penceresi 30 gun", ait: 1, gorulur: 2, onceden: false },
  { ad: "kapali sozlesmeden gelen okuma", ait: 1, gorulur: 2, onceden: false },
  { ad: "bolge kirilimi istenecek", ait: 1, gorulur: 4, onceden: true },
  { ad: "raporu okuyacak taraf", ait: 1, gorulur: 5, onceden: true },
  { ad: "karsilastirma donemi", ait: 1, gorulur: 5, onceden: true },
  { ad: "bolgesi bos satirlar", ait: 2, gorulur: 3, onceden: false },
  { ad: "yinelenen abone kaydi", ait: 2, gorulur: 3, onceden: false },
  { ad: "basamak alani metin mi sayi mi", ait: 2, gorulur: 3, onceden: true },
  { ad: "siralama olcutu oran mi sayi mi", ait: 3, gorulur: 4, onceden: true },
  { ad: "esik yakininda siralama oynak", ait: 3, gorulur: 4, onceden: false },
];

// Icerigi ham veriye bakinca ogrenilen kararlar: bir on bakis bunlari one ceker.
export const VERIDEN = new Set(["okuma penceresi 30 gun", "kapali sozlesmeden gelen okuma",
  "bolgesi bos satirlar", "yinelenen abone kaydi"]);

// Bir geri donus, gorulur adimindan ait adimina donmek ve arasini yeniden kosmaktir.
export const donus = (k) => k.gorulur - k.ait;
export const bedel = (k) => k.gorulur - k.ait + 1;
export const politika = (yazili, onBakis = false) => {
  const d = KARARLAR.filter((k) => donus(k) > 0 && !(yazili && k.onceden)
    && !(onBakis && VERIDEN.has(k.ad)));
  return { donus: d.length, liste: d,
    ziyaret: ADIM.length + (onBakis ? 1 : 0) + d.reduce((s, k) => s + bedel(k), 0) };
};

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(`akis ${ADIM.length} adim: ${ADIM.join(" -> ")}`);
  console.log(`${KARARLAR.length} karar yazilmasi gerekiyor\n`);
  const y = gen([33, 12, 12, 9, 10]);
  console.log(y(["karar", "ait adim", "gorulur", "mesafe", "onceden"]));
  for (const k of KARARLAR) {
    console.log(y([k.ad, `${k.ait} ${ADIM[k.ait - 1]}`, `${k.gorulur} ${ADIM[k.gorulur - 1]}`,
      donus(k), k.onceden ? "evet" : "hayir"]));
  }
  const g = KARARLAR.filter((k) => donus(k) > 0);
  console.log(`\n${KARARLAR.length} kararin ${g.length} tanesi ait oldugu adimdan sonra goruluyor`);
  console.log(`bunlarin ${g.filter((k) => VERIDEN.has(k.ad)).length} tanesinin icerigi ham veriye ` +
    `bakinca ogrenilir: ${g.filter((k) => VERIDEN.has(k.ad)).map((k) => k.ad).join("; ")}`);
}
```

```
akis 5 adim: soru -> veri -> cozumleme -> bulgu -> iletisim
12 karar yazilmasi gerekiyor

karar                                ait adim     gorulur   mesafe   onceden
etkin abone tanimi                     1 soru      1 soru        0      evet
olcum gunu                             1 soru      1 soru        0      evet
okuma penceresi 30 gun                 1 soru      2 veri        1     hayir
kapali sozlesmeden gelen okuma         1 soru      2 veri        1     hayir
bolge kirilimi istenecek               1 soru     4 bulgu        3      evet
raporu okuyacak taraf                  1 soru  5 iletisim        4      evet
karsilastirma donemi                   1 soru  5 iletisim        4      evet
bolgesi bos satirlar                   2 veri 3 cozumleme        1     hayir
yinelenen abone kaydi                  2 veri 3 cozumleme        1     hayir
basamak alani metin mi sayi mi         2 veri 3 cozumleme        1      evet
siralama olcutu oran mi sayi mi   3 cozumleme     4 bulgu        1      evet
esik yakininda siralama oynak     3 cozumleme     4 bulgu        1     hayir

12 kararin 10 tanesi ait oldugu adimdan sonra goruluyor
bunlarin 4 tanesinin icerigi ham veriye bakinca ogrenilir: okuma penceresi 30 gun; kapali sozlesmeden gelen okuma; bolgesi bos satirlar; yinelenen abone kaydi
```

Tablo iki sütunla okunur. Sol sütun kararın nereye ait olduğunu, sağ sütun nerede görüldüğünü
söyler. On iki kararın yalnız ikisi doğduğu yerde görülüyor: etkin abone tanımı ve ölçüm günü.
Kalan onu, ait olduğu adımdan sonra ortaya çıkıyor.

Mesafe sütunu dönüşlerin eşit olmadığını yazıyor. Kapalı sözleşmelerden okuma gelmesi bir adım
geriye götürür; raporu kimin okuyacağının iletişim adımında fark edilmesi dört adım geriye
götürür. İkincisinin görülme yeri sorunun ne olduğuyla değil, akışın hangi adımında birinin ilk kez
"bu kimin için" diye sormasıyla ilgilidir.

Son iki adımda görülen beş karar da dikkat çekicidir. Bulgu ve iletişim adımları hiçbir karar
üretmiyor — tablonun `ait adim` sütununda 4 ve 5 hiç geçmiyor. Ama beş karar orada **görülüyor**.
Karar tüketen adımlar, üretmedikleri kararların eksikliğini fark eden adımlardır.

#### Üç Çalışma Biçimi

Aynı akış, aynı 12 karar, tek fark: kararların ne zaman yazıldığı. Birinci biçimde her karar
görüldüğü anda yazılır. İkinci biçimde her adımda, o adıma ait olan ve önceden yazılabilen kararlar
adımdan çıkmadan yazılır. Üçüncü biçim ikinciye bir şey ekler: soru adımından çıkmadan önce ham
veriye bir kez bakılır. Bu bakış bir adım ziyareti maliyetindedir ve bir çözümleme değildir —
yalnız alanların dolu olup olmadığını, hangi değerlerin geçtiğini gösterir.

```js
// dongu.mjs — ayni akis, iki calisma bicimi: geri donus ve adim ziyareti yan yana.
import { ADIM, KARARLAR, VERIDEN, donus, bedel, politika } from "./akis.mjs";

const A = politika(false), B = politika(true), C = politika(true, true);
const gen = (C) => (h) => h.map((v, j) => (j ? String(v).padStart(C[j])
  : String(v).padEnd(C[0]))).join("");

const y = gen([34, 11, 11, 13, 11]);
console.log(y(["calisma bicimi", "geri donus", "ziyaret", "adim basina", "en uzak"]));
for (const [ad, p] of [["kararlar gorulunce yazilir", A], ["kararlar adiminda yazilir", B],
  ["adiminda yazilir + on bakis", C]]) {
  console.log(y([ad, p.donus, p.ziyaret, (p.ziyaret / ADIM.length).toFixed(1),
    Math.max(...p.liste.map(donus))]));
}

const z = gen([13, 10, 10, 10]);
console.log("\n" + z(["donulen adim", "bicim 1", "bicim 2", "bicim 3"]));
for (let a = 1; a <= ADIM.length; a++) {
  const s = (p) => p.liste.filter((k) => k.ait === a).length;
  console.log(z([`${a} ${ADIM[a - 1]}`, s(A), s(B), s(C)]));
}

console.log(`\ntoplam ziyaret ${A.ziyaret} -> ${B.ziyaret}, geri donus ${A.donus} -> ${B.donus}`);
const uzun = A.liste.filter((k) => donus(k) >= 3);
console.log(`bicim 1'de mesafesi 3 ve uzeri ${uzun.length} donus, ` +
  `${A.ziyaret - ADIM.length} fazla ziyaretin ${uzun.reduce((s, k) => s + bedel(k), 0)} tanesini yiyor`);
console.log(`ikinci bicimde kalan ${B.donus} donus: ${B.liste.map((k) => k.ad).join("; ")}`);
console.log(`bu ${B.donus} karar ${KARARLAR.filter((k) => !k.onceden).length} onceden ` +
  `yazilamayan kararin tamamidir; yazarak degil ancak bakarak ogrenilir`);
console.log(`\non bakis ${VERIDEN.size} karari one cekiyor, bedeli 1 ziyaret: ` +
  `${B.donus} donus ${C.donus} donuse, ${B.ziyaret} ziyaret ${C.ziyaret} ziyarete iniyor`);
console.log(`ucuncu bicimde kalan tek donus: ${C.liste.map((k) => k.ad).join("; ")} ` +
  `— icerigi ham veride degil, cozumlemenin ciktisinda`);

// Ikinci bir muhasebe karari: geri donus arayi degil yalniz ait oldugu adimi yeniden kosturur.
const ucuz = (p) => ADIM.length + p.donus;
console.log(`\nmuhasebe karari degisirse (yalniz ait adim yeniden kosar): ` +
  `bicim 1 ${ucuz(A)} ziyaret, bicim 2 ${ucuz(B)} ziyaret`);
console.log(`bicim 1 ucuz muhasebeyle ${ucuz(A)}, bicim 2 tam muhasebeyle ${B.ziyaret}: ` +
  `ayni sayi, ayri akis`);
```

```
calisma bicimi                     geri donus    ziyaret  adim basina    en uzak
kararlar gorulunce yazilir                 10         33          6.6          4
kararlar adiminda yazilir                   5         15          3.0          1
adiminda yazilir + on bakis                 1          8          1.6          1

donulen adim    bicim 1   bicim 2   bicim 3
1 soru                5         2         0
2 veri                3         2         0
3 cozumleme           2         1         1
4 bulgu               0         0         0
5 iletisim            0         0         0

toplam ziyaret 33 -> 15, geri donus 10 -> 5
bicim 1'de mesafesi 3 ve uzeri 3 donus, 28 fazla ziyaretin 14 tanesini yiyor
ikinci bicimde kalan 5 donus: okuma penceresi 30 gun; kapali sozlesmeden gelen okuma; bolgesi bos satirlar; yinelenen abone kaydi; esik yakininda siralama oynak
bu 5 karar 5 onceden yazilamayan kararin tamamidir; yazarak degil ancak bakarak ogrenilir

on bakis 4 karari one cekiyor, bedeli 1 ziyaret: 5 donus 1 donuse, 15 ziyaret 8 ziyarete iniyor
ucuncu bicimde kalan tek donus: esik yakininda siralama oynak — icerigi ham veride degil, cozumlemenin ciktisinda

muhasebe karari degisirse (yalniz ait adim yeniden kosar): bicim 1 15 ziyaret, bicim 2 10 ziyaret
bicim 1 ucuz muhasebeyle 15, bicim 2 tam muhasebeyle 15: ayni sayi, ayri akis
```

Beş adımlık akış, birinci biçimde 33 kez koşuyor. Adım başına 6,6 ziyaret demek, akışı "beş adımlı
bir süreç" diye anlatmanın şemayı tarif ettiği, işi tarif etmediği anlamına gelir. İkinci biçimde
sayı 15'e, adım başına 3,0'a iniyor. Aradaki 18 ziyaret farkı, hiçbir ek veri toplamadan, yalnız
kararların ne zaman yazıldığı değiştirilerek kazanılıyor.

Kazancın nerede toplandığı üçüncü satır grubunda yazılı. Mesafesi üç ve üzeri olan üç dönüş,
birinci biçimdeki 28 fazla ziyaretin 14'ünü yiyor: dönüşlerin üçte biri bedelin yarısını taşıyor.
Üçü de aynı çeşit karardır — bölge kırılımı istenecek mi, raporu kim okuyacak, hangi dönemle
karşılaştırılacak. Hiçbiri veri hakkında bir şey sormaz; üçü de sorunun kime ve ne için sorulduğunu
sorar ve üçü de ilk adımda, hiçbir tabloya bakmadan yazılabilir.

#### Sıfıra İnmeyen Dönüş

İkinci biçimde geri dönüş beşte duruyor ve beşi de kümenin bir özelliğidir: okuma penceresi, kapalı
sözleşmeden gelen okuma, bölgesi boş satırlar, yinelenen abone kaydı, eşik yakınında sıralamanın
oynak olması. Hiçbiri masa başında yazılamaz; okuma döngüsünün aylık olduğu birinci dersin çapraz
tablosu basıldığında görüldü, sıralamanın 0,0005 farkla döndüğü bölge tablosu basıldığında görüldü.

Üçüncü biçim bu beşin dördünü öne çekiyor. Ön bakış bir ziyaret ödüyor ve karşılığında 15 ziyareti
8'e, beş dönüşü **bire** indiriyor. İlk iki adıma hiç dönülmüyor. Kazanç dört kararın tümünün ham
veride görünür olmasından geliyor: boş bir alan, yinelenmiş bir kimlik ya da bir tarih dağılımı,
hiçbir hesap yapmadan bakınca görülür.

Kalan tek dönüş kapanmıyor ve kapanamaz. Sıralamanın eşik yakınında oynak olması ham veride
durmaz; çözümleme koşup bölge oranları hesaplandıktan sonra ortaya çıkar. **Bir kararın hangi
adımda öğrenilebileceği, o kararın içeriğine bağlıdır ve çalışma düzeniyle değiştirilemez.** Akış
doğrusal değildir; düzensizlikten değil, **bilginin sırasından** dolayı doğrusal değildir. Bu
yüzden "önce soruyu doğru tanımla" öğüdü yarım bir öğüttür — tanımın bir bölümü ancak veri
görüldükten, bir bölümü ancak hesap koştuktan sonra yazılabilir. Yapılabilecek şey, her kararı
öğrenilebildiği en erken adıma çekmek ve geri kalanının döneceğini bilerek yer açmaktır.

Son iki satır dersin kendi sayısına aynı testi uyguluyor. AK14 bir muhasebe kararıydı: dönüş
aradaki bütün adımları yeniden koşturur. İkinci bir muhasebe kararı da savunulabilir — yalnız
kararın ait olduğu adım yeniden koşar, aradakiler bozulmamışsa dokunulmaz. Bu karar altında birinci
biçim 15, ikinci biçim 10 ziyaret üretir. Yani **birinci biçim ucuz muhasebeyle 15, ikinci biçim
tam muhasebeyle 15 çıkar.** İki ayrı çalışma biçimi, iki ayrı muhasebe kararıyla aynı sayıyı verir.
Hangi 15 olduğu yazılmadıkça bu sayı hiçbir şey söylemez — dersin kendi ölçüsü de kursun kuralına
tabidir.

#### Özet

- Analiz akışı beş adımdır: soru, veri, çözümleme, bulgu, iletişim. Bulgu ve iletişim adımları
  karar üretmez, tüketir; ama eksik kararı fark eden adımlar da onlardır.
- Bu koşumda 12 kararın 10'u ait olduğu adımdan sonra görülür; yalnız ikisi doğduğu yerde görülür.
- Kararlar görüldükçe yazıldığında akış 10 geri dönüş ve 33 adım ziyareti üretir, adım başına 6,6.
  Her karar ait olduğu adımda yazıldığında 5 dönüş ve 15 ziyarete, ham veriye bir ön bakış
  eklendiğinde 1 dönüş ve 8 ziyarete iner.
- Kazanç uzun dönüşlerde toplanır: mesafesi üç ve üzeri üç dönüş, fazla ziyaretin 14'ünü yer ve
  üçü de sorunun kime sorulduğuyla ilgilidir, veriyle değil.
- Kapanmayan tek dönüşün içeriği ham veride değil çözümlemenin çıktısındadır; bir kararın hangi
  adımda öğrenilebileceği çalışma düzeniyle değiştirilemez.
- Ziyaret sayısı da bir muhasebe kararına bağlıdır: birinci biçim ucuz muhasebeyle 15, ikinci biçim
  tam muhasebeyle 15 verir; hangi 15 olduğu yazılmadan sayı okunamaz.

#### Sonraki Adım

Bu ders akışı tek bir kişinin koşturduğunu varsaydı. Gerçekte akışın adımları çoğu zaman farklı
işleri olan kişiler arasında bölünür ve bölünme yeri sonucun ne olacağını değiştirir. Aynı soru —
etkin abone sayısı düşüyor mu — ölçmekle görevli birinin elinde bir sayıya, kararı bağlamakla
görevli birinin elinde bir eşiğe, geleceğe genellemekle görevli birinin elinde bir tahmin
aralığına dönüşür. Üçü de aynı tabloyu okur ve üçü de farklı bir çıktı teslim eder. Sonraki ders
bu üç iş tanımını ayırır ve aynı sorunun üç elde nasıl üç ayrı sayıya döndüğünü yan yana basar.

### Analist Rolleri

Source: https://academia.sh/tr/kurslar/veri-analitigine-giris/analist-rolleri

Tek cümlelik bir soru üç iş tanımına veriliyor ve aynı tablodan üç ayrı çıktı çıkıyor: ölçen rol 90 günde -228 abone (yüzde -5,14), kararı bağlayan rol ücret ölçütüyle yüzde -3,34 ve yüzde -5 eşiğinin altında kaldığı için eylem yok, genelleyen rol bir yıl sonrası için 2 191 ile 3 286 arasında iki tahmin. Abone başına ücret aynı satırlardan yüzde 1,89 artmıştır; üç doğru sayının ikisi düşüş, biri yükseliş gösterir. Bir cümlelik sorunun arkasında 10 yazılı karar durur.

Önceki ders akışı tek bir kişinin koşturduğunu varsaydı. Gerçekte akışın adımları çoğu zaman farklı
işleri olan kişiler arasında bölünür ve bölünme yeri sonucun ne olacağını değiştirir. Aynı soru bir
elde bir sayıya, başka bir elde bir eşiğe, üçüncü bir elde bir tahmin aralığına dönüşür.

Bu ders üç iş tanımını ayırır ve üçüne aynı soruyu verir: **ağ genelinde abone sayısı düşüyor mu,
ne yapmalı.** Ölçülen şey, aynı tablodan çıkan üç çıktının ne kadar farklı olduğudur. Rol adları
burada unvan değil, **iş tanımı** olarak ele alınır: bir rolü belirleyen şey adı değil, işinin ne
zaman bittiğini söyleyen kabul ölçütüdür.

- **AK17.** Kayıtlar birinci dersin kayıtlarıdır: aynı tohum, aynı 4 800 satır, aynı sayılar. Küme
  **kurgudur**.
- **AK18.** Rol adları iş tanımıdır. Aynı ad başka bir yerde başka bir işi anlatabilir; ölçülen şey
  ad değil, **kabul ölçütüdür** — çıktı ne olduğunda iş bitmiş sayılır.
- **AK19.** Soru üçüne de tek cümleyle verilir ve üçü de aynı tabloyu okur. Kimseye ek veri
  verilmez.
- **AK20.** Ücret alanı bir **ücret birimidir**; ölçek modelin ölçeğidir, herhangi bir para birimi
  değildir.
- **AK21.** Karşılaştırma dönemi 90 gün, eylem eşiği yüzde -5'tir. İkisi de karardır ve ikisi de
  sayı hesaplanmadan **önce** yazılmıştır.

#### Üç İş Tanımı

**Ölçen iş tanımı** (veri analisti), sorulan sayıyı tanımı ve kararlarıyla birlikte teslim
ettiğinde biter. Soruyu değiştirmez. Sorulan şeyin doğru soru olup olmadığı bu tanımın dışındadır;
bu rolün ürünü bir sayı ve o sayının nasıl üretildiğidir.

**Kararı bağlayan iş tanımı** (iş analisti), sayı bir eyleme bağlandığında biter. Bunun için sayının
bir eşiği ve eşik aşıldığında yapılacak bir şeyi olmalıdır. Bu tanım sorunun **ölçütünü değiştirme
yetkisini** içerir: sorulan büyüklük bir eyleme bağlanamıyorsa, bağlanabilen bir büyüklükle
değiştirilir.

**Genelleyen iş tanımı** (veri bilimci), bulgu gözlenen dönemden görülmemiş bir döneme ya da
görülmemiş satırlara taşındığında biter. Taşıma bir varsayım ister ve varsayım çıktının bir parçası
olarak teslim edilir; varsayımsız bir genelleme bu tanımda eksik iştir.

Üç tanım da aynı işi yapmıyor ve hiçbiri diğerinin daha gelişmiş bir sürümü değil. Aralarındaki
fark yetkinlik farkı değil, **işin nerede bittiği** farkıdır.

#### Üçünün Okuduğu Tek Tablo

```js
// seri.mjs — ilk dersin abone kayitlari, ayni tohum ve ayni sayilar; MODELDIR.
// Olcum gunu 0'dir; "gun" ile biten alanlar o gunden geriye sayilan gun sayisidir.
export const TOHUM = 20260601, ABONE = 4800, BOLGE = ["kuzey", "guney", "dogu", "bati", "merkez"];
const uretec = (t) => { let s = t >>> 0;
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; };
const r = uretec(TOHUM);
const sec = (u, d) => { let t = 0; for (const [a, p] of d) { t += p; if (u < t) return a; }
  return d.at(-1)[0]; };

export const KAYITLAR = Array.from({ length: ABONE }, (_, i) => {
  const bolge = BOLGE[Math.floor(r() * 5)];
  const basamak = sec(r(), [[1, 0.46], [2, 0.34], [3, 0.20]]);
  const baglantiGun = 30 + Math.floor(r() * 2900);
  // Kapanis olasiligi en dusuk tarife basamaginda yuksektir ve kapanislar son aylara yigilir.
  const kapanmaP = [0.16, 0.09, 0.05][basamak - 1];
  const kapanisGun = r() < kapanmaP
    ? Math.min(baglantiGun - 1, Math.floor(r() * r() * 420)) : null;
  const askida = kapanisGun === null && r() < 0.085;
  const sozlesme = kapanisGun !== null ? "kapali" : askida ? "askida" : "etkin";
  // Sayacin son okumasindan bu yana gecen gun. Kapali ve askidaki abonelerin bir bolumu
  // hala okuma gonderir; etkin abonelerin bir bolumu (arizali sayac, bos konut) gondermez.
  const g = sozlesme === "etkin" ? (r() < 0.13 ? 31 + Math.floor(r() * 300) : Math.floor(r() * 29))
    : sozlesme === "askida" ? (r() < 0.34 ? Math.floor(r() * 29) : 31 + Math.floor(r() * 250))
    : (r() < 0.11 ? Math.floor(r() * 29) : 31 + Math.floor(r() * 500));
  const tuketim = Math.round((2 + basamak * 4 + r() * 9) * 10) / 10;
  const ucret = Math.round((6 + basamak * basamak * 7) * (0.85 + r() * 0.3));
  return { i, bolge, basamak, baglantiGun, kapanisGun, sozlesme, sonOkumaGun: g,
    tuketim, ucret, destek: r() < 0.22 ? 1 + Math.floor(r() * 3) : 0 };
});

// d gun once sozlesmesi acik olan abone: o tarihte baglanmis ve henuz kapanmamis.
export const acik = (d) => KAYITLAR.filter((k) =>
  k.baglantiGun >= d && (k.kapanisGun === null || k.kapanisGun < d));
export const nokta = (d) => {
  const l = acik(d), u = l.reduce((s, k) => s + k.ucret, 0);
  return { d, n: l.length, u, basina: u / l.length };
};

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(`tohum ${TOHUM}: ${ABONE} abone kaydi; asagidaki seri tek tablodan okunuyor\n`);
  const y = gen([11, 9, 15, 15]);
  console.log(y(["gun once", "abone", "toplam ucret", "abone basina"]));
  for (const d of [90, 60, 30, 0]) {
    const p = nokta(d);
    console.log(y([d, p.n, p.u, p.basina.toFixed(2)]));
  }
}
```

```
tohum 20260601: 4800 abone kaydi; asagidaki seri tek tablodan okunuyor

gun once       abone   toplam ucret   abone basina
90              4439         139508          31.43
60              4426         139657          31.55
30              4377         138739          31.70
0               4211         134843          32.02
```

Dört satır, üç sütun. Sözleşmesi açık abone sayısı 90 günde 4 439'dan 4 211'e iniyor ve düşüş
hızlanıyor: ilk 30 günde 13, son 30 günde 166. Toplam ücret uçlar arasında aynı yönde ama daha
yavaş iniyor; ilk 30 günde ise tek başına yükseliyor. Üçüncü sütun ters yöne gidiyor: abone başına
ücret her adımda yükseliyor.

Üç sütun da aynı satırlardan çıktı ve üçü de doğru. Hangisinin "abone sayısı düşüyor mu" sorusunun
cevabı olduğu tabloda yazmıyor.

#### Aynı Sorudan Üç Çıktı

```js
// roller.mjs — ayni soru, ayni tablo, uc is tanimi: uc ayri cikti yan yana.
// Soru: "ag genelinde abone sayisi dusuyor mu, ne yapmali."
import { nokta } from "./seri.mjs";

const P0 = nokta(0), P30 = nokta(30), P90 = nokta(90);
const yuzde = (yeni, eski) => ((100 * (yeni - eski)) / eski).toFixed(2);
const ESIK = -5.0, UFUK = 365;

console.log("rol 1 olcen — soruyu degistirmez; sayiyi ve kararlarini teslim eder");
console.log(`  90 gunde abone ${P90.n} -> ${P0.n}: ${P0.n - P90.n} abone, %${yuzde(P0.n, P90.n)}`);
console.log("  karar: acik sozlesme tanimi, karsilastirma donemi 90 gun, kirilim yok (3)");

console.log("\nrol 2 karari baglayan — olcutu ucrete cevirir ve bir esige baglar");
console.log(`  90 gunde ucret ${P90.u} -> ${P0.u}: ${P0.u - P90.u}, %${yuzde(P0.u, P90.u)}`);
const d = Number(yuzde(P0.u, P90.u));
console.log(`  esik %${ESIK.toFixed(2)}: ${d <= ESIK ? "asildi, eylem gerekir" : "asilmadi, eylem yok"}`);
console.log(`  abone basina ucret ${P90.basina.toFixed(2)} -> ${P0.basina.toFixed(2)}: ` +
  `%${yuzde(P0.basina, P90.basina)}`);
console.log("  karar: olcut ucret, esik yuzde -5, donem 90 gun, kirilim yok (4)");

console.log("\nrol 3 genelleyen — soruyu gelecege tasir; tek sayi teslim etmez");
const surdur = (p) => Math.round(P0.n + ((P0.n - p.n) / p.d) * UFUK);
const a = surdur(P30), b = surdur(P90);
console.log(`  son 30 gunun hiziyla ${UFUK} gun sonra: ${a} abone`);
console.log(`  son 90 gunun hiziyla ${UFUK} gun sonra: ${b} abone`);
console.log(`  iki savunulabilir pencere arasi fark: ${Math.abs(a - b)} abone`);
console.log("  karar: tahmin penceresi, dogrusal surme varsayimi, mevsim verisi yok (3)");

console.log(`\nayni tablodan uc dogru sayi: abone %${yuzde(P0.n, P90.n)}, ` +
  `ucret %${yuzde(P0.u, P90.u)}, abone basina ucret %${yuzde(P0.basina, P90.basina)}`);
console.log("ucu de ayni satirlardan cikiyor; ikisi dususu, biri yukselisi gosteriyor");
```

```
rol 1 olcen — soruyu degistirmez; sayiyi ve kararlarini teslim eder
  90 gunde abone 4439 -> 4211: -228 abone, %-5.14
  karar: acik sozlesme tanimi, karsilastirma donemi 90 gun, kirilim yok (3)

rol 2 karari baglayan — olcutu ucrete cevirir ve bir esige baglar
  90 gunde ucret 139508 -> 134843: -4665, %-3.34
  esik %-5.00: asilmadi, eylem yok
  abone basina ucret 31.43 -> 32.02: %1.89
  karar: olcut ucret, esik yuzde -5, donem 90 gun, kirilim yok (4)

rol 3 genelleyen — soruyu gelecege tasir; tek sayi teslim etmez
  son 30 gunun hiziyla 365 gun sonra: 2191 abone
  son 90 gunun hiziyla 365 gun sonra: 3286 abone
  iki savunulabilir pencere arasi fark: 1095 abone
  karar: tahmin penceresi, dogrusal surme varsayimi, mevsim verisi yok (3)

ayni tablodan uc dogru sayi: abone %-5.14, ucret %-3.34, abone basina ucret %1.89
ucu de ayni satirlardan cikiyor; ikisi dususu, biri yukselisi gosteriyor
```

Birinci rol soruyu olduğu gibi cevaplıyor: 90 günde 228 abone eksildi, yüzde 5,14. Yanında üç karar
var. Bu çıktının içinde bir yargı yok — yüzde 5,14'ün kötü olup olmadığını söylemiyor, çünkü söylemek
için yazılı bir eşik gerekir ve eşik bu iş tanımının dışındadır.

İkinci rol ölçütü değiştiriyor ve gerekçesini yazıyor: abone sayısı bir eyleme bağlanamaz, çünkü
kaybedilen abonelerin ne taşıdığı sayıda görünmez. Ücret ölçütüyle düşüş yüzde 3,34 ve yüzde -5
eşiğinin altında kalıyor; karar "eylem yok". Üçüncü satır aynı hareketi ters işaretle yazıyor:
abone başına ücret yüzde 1,89 **yükselmiş**. Üç sayının aynı satırlardan çıkıp ayrı yöne gitmesinin
nedeni bir sonraki bölümde basılacak.

Burada bir tehlike var ve adı konmalı. Ölçütü değiştirip eşiğin altında kalmak, sayıyı beğenmeyip
başka bir sayı aramaktan ancak tek bir şeyle ayrılır: **eşik sayıdan önce yazılmışsa bir karardır,
sonra yazılmışsa bir gerekçedir.** AK21 eşiği hesaptan önce yazdı; bu yüzden ikinci rolün çıktısı
savunulabilir. Aynı eşik sonuç görüldükten sonra yüzde -3'e çekilseydi hesap aynı kalır, çıktı bir
karar olmaktan çıkardı.

Üçüncü rol tek bir sayı teslim etmiyor ve bu eksiklik değil, iş tanımının gereğidir. Aynı seriden
iki savunulabilir tahmin çıkıyor: son 30 günün hızıyla 2 191 abone, son 90 günün hızıyla 3 286.
Aradaki fark 1 095 abone — bugünkü sayının dörtte biri. İkisi arasında seçim yapmak için düşüşün
mevsimsel mi yoksa süregiden mi olduğunu bilmek gerekir ve elde bunu ayıracak geçmiş yok. İkinci
dersin derinlik şartı burada bir soru olarak geri geliyor: dört dönemlik geçmiş bir yıllık dalgayı
göstermez. Üçüncü rolün asıl çıktısı bu yüzden bir sayı değil, bir **veri isteğidir**.

#### Üç Rolün de Yazmadığı Kırılım

Üç rolün karar listesinde ortak bir satır var: **kırılım yok.** Üçü de ağ toplamı üzerinden
çalıştı, çünkü üçünün de kabul ölçütü toplamla karşılanıyordu. Oysa üç sayının birbirinden neden
ayrıldığı tek bir kırılımda yazılı.

```js
// kirilim.mjs — uc rolun de "kirilim yok" yazdigi yer: kaybin tarife basamagina dagilimi.
import { acik } from "./seri.mjs";

const T0 = acik(0), T90 = acik(90);
const say = (l, b) => l.filter((k) => k.basamak === b).length;
const ucr = (l, b) => l.filter((k) => k.basamak === b).reduce((s, k) => s + k.ucret, 0);
const gen = (B) => (h) => h.map((v, j) => (j ? String(v).padStart(B[j])
  : String(v).padEnd(B[0]))).join("");

const y = gen([10, 10, 10, 9, 12, 12, 10]);
console.log(y(["basamak", "90 gun", "bugun", "fark", "ucret 90", "ucret bugun", "ucret f."]));
for (const b of [1, 2, 3]) {
  console.log(y([b, say(T90, b), say(T0, b), say(T0, b) - say(T90, b),
    ucr(T90, b), ucr(T0, b), ucr(T0, b) - ucr(T90, b)]));
}
const dn = T0.length - T90.length;
const d1 = say(T0, 1) - say(T90, 1);
console.log(`\n${dn} abonelik kaybin ${d1} tanesi birinci basamakta: ` +
  `%${((100 * d1) / dn).toFixed(1)}`);
console.log(`birinci basamak abone basina ${(ucr(T90, 1) / say(T90, 1)).toFixed(2)} ucret tasiyor, ` +
  `ucuncu basamak ${(ucr(T90, 3) / say(T90, 3)).toFixed(2)}`);
```

```
basamak       90 gun     bugun     fark    ucret 90 ucret bugun  ucret f.
1               2058      1899     -159       26758       24706     -2052
2               1482      1420      -62       50512       48430     -2082
3                899       892       -7       62238       61707      -531

-228 abonelik kaybin -159 tanesi birinci basamakta: %69.7
birinci basamak abone basina 13.00 ucret tasiyor, ucuncu basamak 69.23
```

Kaybın yüzde 69,7'si birinci tarife basamağında. Birinci basamaktaki bir abone 13,00 ücret birimi
taşıyor, üçüncü basamaktaki 69,23 — beş katından fazla. Bu iki sayı üçünü birden açıklıyor: abone
sayısı sert düşüyor çünkü kayıp en kalabalık basamakta, toplam ücret daha yavaş düşüyor çünkü o
basamak en az ücret taşıyor, abone başına ücret yükseliyor çünkü ortalamadan aşağı çeken satırlar
gidiyor.

Kırılımın kendisi de bir karardır ve tarife basamağıyla kırmak tek seçenek değildi; bölgeyle,
abone yaşıyla ya da tüketim düzeyiyle kırılsaydı başka bir tablo çıkardı. Ama üç rolün hiçbiri
herhangi bir kırılım yazmadı. **Bir kabul ölçütü neyi teslim etmeyi zorunlu kılıyorsa o üretilir;
zorunlu kılmadığı şey, gerekli olsa bile üretilmez.** Üç doğru sayıyı birlikte okunabilir kılan
satır, hiçbirinin iş tanımının içinde değildi.

#### Çıktı Yanlış Rolde Okununca

Üç çıktı da doğru, ama biri diğerinin yerine okunduğunda ortaya yanlış bir cümle çıkar.

Birinci rolün "-228 abone" çıktısı bir karar gibi okunursa, okuyan taraf eksik olan eşiği kendi
kafasından tamamlar ve kimsenin yazmadığı bir sınır rapora girmiş olur. İkinci rolün "eşik
aşılmadı" çıktısı bir ölçüm gibi okunursa, 228 abonenin gittiği bilgisi kaybolur — o cümle
ölçmüyor, bir eşikle karşılaştırıyor. Üçüncü rolün "3 286" sayısı bir ölçüm gibi okunursa,
doğrusal sürme varsayımı bir olgu olarak yolculuk etmeye başlar; oysa aynı seri başka bir pencereyle
2 191 verir.

Toplam sayı da bir şey söylüyor. Tek cümlelik bir sorunun arkasında üç rolün yazdığı **10 karar**
duruyor. Hiçbiri veriyi değiştirmiyor, hepsi sonucu değiştiriyor. Bir raporda üç çıktıdan biri
duruyorsa, yanında hangi iş tanımının ürettiği ve hangi kararların yazıldığı da durmalıdır. Aksi
halde kursun kuralı işler: kararı yazılmayan sayı ölçülmemiş sayılır.

#### Özet

- Üç iş tanımı kabul ölçütleriyle ayrılır: ölçen rol sayıyı ve kararlarını, kararı bağlayan rol
  sayının bağlandığı eşiği, genelleyen rol varsayımıyla birlikte bir genellemeyi teslim eder.
- Aynı tablodan üç doğru sayı çıkar: abone yüzde -5,14, toplam ücret yüzde -3,34, abone başına
  ücret yüzde 1,89. İkisi düşüş, biri yükseliş gösterir.
- Ölçütü değiştirmek eşik hesaptan önce yazıldıysa bir karardır, sonra yazıldıysa bir gerekçedir;
  ayrımı yapan tek şey sıradır.
- Genelleyen rolün iki savunulabilir tahmini 2 191 ile 3 286 arasında, 1 095 abone açıktır; seçimi
  yapacak geçmiş elde olmadığı için çıktı bir sayı değil bir veri isteğidir.
- Üç sayının ayrı yöne gitmesinin nedeni tek bir kırılımda yazılıdır: kaybın yüzde 69,7'si en
  düşük tarife basamağındadır ve üç rolün hiçbirinin kabul ölçütü kırılımı zorunlu kılmaz.
- Tek cümlelik sorunun arkasında 10 yazılı karar durur; bir çıktı hangi iş tanımından geldiği
  yazılmadan raporlanamaz.

#### Sonraki Adım

Bu konu boyunca dört ders aynı şeyi yaptı: soruyu ölçülebilir duruma getirdi, tanımı değiştirip
sayının ne kadar oynadığını yazdı. Tablonun kendisi hep verilmiş kabul edildi. Alınan bütün
kararlar sorunun tarafındaydı — hangi sütun ölçüt, hangi pencere, hangi eşik, hangi dönem.

Bu dersin son bloğunda bir işlem yapıldı ve hiç sorgulanmadı: ücret alanının ortalaması alındı ve
"abone başına ücret" diye raporlandı. Aynı hesap tarife basamağı alanına da uygulanabilirdi ve bir
sayı verirdi — basamakların ortalaması. O sayı da hesaplanabilir, yazılabilir, tabloya konabilir ve
hiçbir anlamı olmaz. İkisi arasındaki farkı belirleyen şey hesap değil, alanın **ne tür bir şey**
olduğudur. Sözleşme durumu bir sınıf adıdır, tarife basamağı sıralı bir kademedir, ücret ölçülmüş
bir niceliktir, abone kimliği sayı gibi görünen bir etikettir. Sonraki konu bu ayrımı kurar ve bir
alanın türü yanlış atandığında ortaya çıkan sayıyı gösterir.

## Verinin Yapısı

Üzerinde çalışılan verinin ne tür bir şey olduğunun ve bunun hangi özetleri meşru kıldığının sayılması: kesikli bir alanın sürekli sayılmasının ürettiği anlamsız ortalama, sınıflayıcı, sıralayıcı, aralık ve oran ölçeklerinin izin verdiği özetler, birincil ve ikincil kaynağın aynı büyüklük için farklı sayı vermesi, doğruluk, eksiksizlik, tutarlılık ve güncellik eşiklerinin elediği satır sayısı, veriyle cevaplanabilir olduğu halde sorulmaması gereken soru ve tekil kişiye inen kırılım.

### Veri Türleri

Source: https://academia.sh/tr/kurslar/veri-analitigine-giris/veri-turleri

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.

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

```js
// 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.

```js
// 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.

### Ölçüm Ölçekleri

Source: https://academia.sh/tr/kurslar/veri-analitigine-giris/olcum-olcekleri

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.

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) ve `okuma_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

```js
// 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 beş kez geçen bir okumadır ve aynı beş kezle onunla başa baş giden ikinci bir değer
daha vardır. Tepe değer 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.

```js
// 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.
`kuzey` bölgesinin 408 kaydı ortada toplanmıştır ve sırası iki kodlamada da değişmez.

**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_m3` alanının tepe değeri oran ölçeğinde meşrudur
  ama 1.099 farklı değer arasında beş kez geçen bir okumadır ve başka bir değerle başa baştı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.

### Veri Kaynakları

Source: https://academia.sh/tr/kurslar/veri-analitigine-giris/veri-kaynaklari

Aynı büyüklük — ortalama aylık tüketim — üç kaynaktan üç farklı sayı verir: saha anketi 22,42 m³, faturalama özetinden yeniden kurulan değer 21,59 m³, sayaç telemetrisi 17,01 m³, modelin doğrusu ise 21,31 m³. Abone sayısı bile kaynağa göre 1.400, 886 ve 1.041 çıkar. Her kaynakta tek bir karar değiştirildiğinde altı sayı 14,11 ile 22,42 m³ arasına yayılır ve hiçbirinde hesap hatası yoktur; yanlılığın kaynağı kapsam tablosunda görülür.

Önceki iki ders alanların türünü ve ölçeğini sordu, ama ikisi de 1.400 satırı hazır kabul etti.
Bu ders satırların nereden geldiğini sorar ve tek bir büyüklüğü — bir aylık ortalama tüketimi —
üç ayrı kaynaktan ölçer. Üç sayı da doğru toplanmıştır ve üçü de farklıdır.

Fark bir hesap hatasından çıkmaz. Her kaynak, kimin kayda girdiğine dair bir karar taşır ve o
karar veriyle birlikte gelmez; kaynağın kurulma biçiminde saklıdır. Bir anket yalnız yanıt
verenleri, bir telemetri akışı yalnız iletebilen cihazları, bir özet raporu yalnız yayımlanmış
kırılımı içerir. Ölçü bu dersin sonunda **kaynağın taşıdığı yanlılıktır**: kaynağın verdiği sayı
ile gerçeğin arasındaki fark ve o farkın hangi kayıtların dışarıda kalmasından geldiği.

- **VY10.** Küme, önceki derslerin 1.400 satırlık abone kaydıdır. Küme **kurgudur** ve bu
  dersin ayrıcalığı şudur: modelin doğrusu bilinir. Gerçek ortalama tüketim 21,31 m³'tür ve hiçbir
  kaynak bu sayıyı görmez.
- **VY11. Birincil veri** (primary data), çözümlemeyi yapan tarafın kendi topladığı veridir: saha
  ziyaretinde doldurulan hane anketi. Kapsamı iki kararla belirlenir — kim ziyaret edildi ve kim
  yanıt verdi.
- **VY12. İkincil veri** (secondary data), başkasının başka bir amaçla toplayıp yayımladığı
  veridir: faturalama sisteminin tarife basamağı özeti. Ham satırlar yoktur, yalnız basamak
  sayıları vardır.
- **VY13. Üretilen veri** (generated data), bir düzeneğin işleyişi sırasında kendiliğinden
  biriken veridir: sayaçların gönderdiği telemetri. Kimse doldurmaz, ama cihazın iletememesi de
  bir kayıt kararıdır.
- **VY14.** Modelde yanıt verme olasılığı tüketimle **artar**, iletim olasılığı tüketimle
  **azalır**, telemetri her ay 20 ile 30 gün arası veri gönderir. Bu üç eğilim modele girdi olarak
  verilmiştir; kaynağın yapısını temsil ederler.

#### Üç Kaynak, Üç Sayı

```js
// kaynaklar.mjs — ayni buyuklugu uc kaynaktan olcen model.
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 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);
  // Kaynak cizimleri taban alanlardan SONRA yapilir; taban kume degismez.
  const yanit = r() < 0.30 + 0.014 * tuketim;   // yuksek tuketen daha cok yanit verir
  const iletim = r() < 0.95 - 0.010 * tuketim;  // yuksek debide iletim daha cok kesilir
  const kapsananGun = 30 - Math.floor(r() * 11); // cihazin ay icinde raporladigi gun
  return { abone_no: 10001 + i, bolge: b.ad, tuketim_m3: tuketim, sayac_sayisi: sayac,
    ziyaret_sayisi: ziyaret, memnuniyet, sicaklik_c: sicaklik, gecen_gun: gecen,
    yanit, iletim, kapsananGun,
    basamak: tuketim < TARIFE[0] ? 1 : tuketim < TARIFE[1] ? 2 : tuketim < TARIFE[2] ? 3 : 4 };
});
export const ort = (a) => a.reduce((x, y) => x + y, 0) / a.length;
const GERCEK = ort(KAYITLAR.map((k) => k.tuketim_m3));

// Birincil: saha ziyaretinde toplanan hane anketi (ziyaret alan ve yanit veren).
export const birincil = KAYITLAR.filter((k) => k.ziyaret_sayisi >= 1 && k.yanit);
// Ikincil: faturalama ozetinden basamak sayilariyla yeniden kurulan ortalama.
export const ORTA = [5, 17.5, 32.5, 50];
export const ikincilOrt = (temsil) => {
  let t = 0;
  for (let b = 1; b <= 4; b++) t += KAYITLAR.filter((k) => k.basamak === b).length * temsil[b - 1];
  return t / KAYIT;
};
// Uretilen: sayac telemetrisi; yalnizca ileten cihazlar, eksik gunler oldugu gibi.
export const uretilen = KAYITLAR.filter((k) => k.iletim);
const telemetriHam = (k) => k.tuketim_m3 * k.kapsananGun / 30;

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; modelin dogrusu ` +
    `ortalama ${GERCEK.toFixed(2)} m3`);
  const y = gen([28, 9, 9, 12, 10]);
  console.log("\n" + y(["kaynak", "kayit", "kapsam", "ortalama", "sapma"]));
  const satirlar = [
    ["birincil: saha anketi", birincil.length, ort(birincil.map((k) => k.tuketim_m3))],
    ["ikincil: faturalama ozeti", KAYIT, ikincilOrt(ORTA)],
    ["uretilen: sayac telemetrisi", uretilen.length, ort(uretilen.map(telemetriHam))],
  ];
  for (const [ad, n, o] of satirlar) {
    console.log(y([ad, n, `%${(100 * n / KAYIT).toFixed(1)}`, o.toFixed(2),
      (o - GERCEK >= 0 ? "+" : "") + (o - GERCEK).toFixed(2)]));
  }
  console.log(`\nabone sayisi da kaynaga gore degisir: kayit sisteminde ${KAYIT}, ` +
    `saha listesinde ${KAYITLAR.filter((k) => k.ziyaret_sayisi >= 1).length}, ` +
    `telemetride ${uretilen.length} cihaz`);
  const uc = satirlar.map((s) => s[2]);
  console.log(`uc kaynagin en buyuk farki ${(Math.max(...uc) - Math.min(...uc)).toFixed(2)} m3`);
}
```

```
model (tohum 20260218): 1400 abone; modelin dogrusu ortalama 21.31 m3

kaynak                          kayit   kapsam    ortalama     sapma
birincil: saha anketi             544    %38.9       22.42     +1.11
ikincil: faturalama ozeti        1400   %100.0       21.59     +0.28
uretilen: sayac telemetrisi      1041    %74.4       17.01     -4.30

abone sayisi da kaynaga gore degisir: kayit sisteminde 1400, saha listesinde 886, telemetride 1041 cihaz
uc kaynagin en buyuk farki 5.41 m3
```

Üç kaynak aynı 1.400 aboneyi kapsamak üzere kurulmuştur ve hiçbiri kapsamaz. Saha anketi 544
kayda, telemetri 1.041 cihaza ulaşır; faturalama özeti sayı olarak hepsini kapsar ama ham satırı
göstermez. Sapma sütunu üç farklı yön gösteriyor: anket 1,11 m³ yukarı, özet 0,28 m³ yukarı,
telemetri 4,30 m³ aşağı. En büyük fark 5,41 m³'tür ve bu, gerçek değerin dörtte birine yakındır.

Son satır daha rahatsız edicidir. **Abone sayısı bile kaynağa göre değişir**: kayıt sisteminde
1.400, saha listesinde 886, telemetride 1.041. "Kaç abonemiz var" sorusunun tek bir cevabı yoktur;
her sayı bir kapsam tanımının cevabıdır. Bir raporda abone sayısı yazılırken hangi kaynağın
sayıldığı belirtilmiyorsa, o sayı üç farklı büyüklükten biridir ve hangisi olduğu okunamaz.

Telemetrinin 4,30 m³'lük sapması iki ayrı nedenden gelir ve ikisi de kaynağın yapısına aittir.
Cihazlar ayın tamamını değil 20 ile 30 gün arasını raporlar, bu yüzden ham toplam bir aylık
tüketimin altında kalır. Ayrıca iletim olasılığı yüksek tüketimde düşer, yani eksik kalan
cihazlar rastgele seçilmiş değildir. Bir kaynak **eksik veri** verdiğinde asıl soru ne kadarının
eksik olduğu değil, **eksik olanların hangileri** olduğudur.

#### Kararı Değiştirince

Kapsam kaynağın kararıdır. Bir de çözümlemeyi yapanın kararı vardır: eldeki kayıtlardan sayıyı
nasıl çıkaracağı. Aşağıdaki blok her kaynakta tek bir kararı değiştirir.

```js
// karar.mjs — her kaynakta tek bir karar degistirilir, iki sayi yan yana basilir.
import { KAYITLAR, KAYIT, ort, birincil, uretilen, ikincilOrt, ORTA } from "./kaynaklar.mjs";
const GERCEK = ort(KAYITLAR.map((k) => k.tuketim_m3));
const pay = (b) => KAYITLAR.filter((k) => k.basamak === b).length / KAYIT;
// Basamak paylari faturalama ozetinden bilinir; ornek bu paylara geri agirliklanir.
const agirlikli = (l) => { let t = 0;
  for (let b = 1; b <= 4; b++) { const alt = l.filter((k) => k.basamak === b);
    if (alt.length) t += pay(b) * ort(alt.map((k) => k.tuketim_m3)); }
  return t; };
const satir = [
  ["birincil", "A: yanit verenlerin ham ortalamasi", ort(birincil.map((k) => k.tuketim_m3))],
  ["birincil", "B: basamak paylarina geri agirliklama", agirlikli(birincil)],
  ["ikincil", "A: her basamak orta noktasiyla", ikincilOrt(ORTA)],
  ["ikincil", "B: her basamak alt siniriyla", ikincilOrt([0, 10, 25, 40])],
  ["uretilen", "A: eksik gunler oldugu gibi toplanir",
    ort(uretilen.map((k) => k.tuketim_m3 * k.kapsananGun / 30))],
  ["uretilen", "B: kapsanan gune gore aya olceklenir", ort(uretilen.map((k) => k.tuketim_m3))],
];
const y = (h) => String(h[0]).padEnd(11) + String(h[1]).padEnd(39)
  + String(h[2]).padStart(9) + String(h[3]).padStart(9);
console.log(y(["kaynak", "karar", "sayi", "sapma"]));
for (const [k, a, s] of satir) {
  console.log(y([k, a, s.toFixed(2), (s - GERCEK >= 0 ? "+" : "") + (s - GERCEK).toFixed(2)]));
}
const s = satir.map((x) => x[2]);
console.log(`\nmodelin dogrusu ${GERCEK.toFixed(2)} m3; alti sayinin hicbirinde hesap ` +
  `hatasi yok`);
console.log(`kaynak ici en buyuk fark ${Math.max(...[0, 2, 4].map((i) =>
  Math.abs(s[i + 1] - s[i]))).toFixed(2)} m3, alti sayinin araligi ` +
  `${Math.min(...s).toFixed(2)} - ${Math.max(...s).toFixed(2)} m3`);
console.log(`uc kaynagin A kararlarinin ortalamasi ` +
  `${ort([s[0], s[2], s[4]]).toFixed(2)} m3 — ardinda tek bir karar yoktur`);

// Yanliligin kaynagi: hangi kayitlarin kapsam disinda kaldigi.
console.log(`\nkapsam basamak basamak`);
const y2 = (h) => String(h[0]).padEnd(10) + h.slice(1).map((v) => String(v).padStart(12)).join("");
console.log(y2(["basamak", "tum kume", "ankette", "ankette %", "telemetride", "telemetri %"]));
for (const b of [1, 2, 3, 4]) {
  const t = KAYITLAR.filter((k) => k.basamak === b).length;
  const a = birincil.filter((k) => k.basamak === b).length;
  const u = uretilen.filter((k) => k.basamak === b).length;
  console.log(y2([b, t, a, `%${(100 * a / t).toFixed(1)}`, u, `%${(100 * u / t).toFixed(1)}`]));
}
```

```
kaynak     karar                                       sayi    sapma
birincil   A: yanit verenlerin ham ortalamasi         22.42    +1.11
birincil   B: basamak paylarina geri agirliklama      21.52    +0.21
ikincil    A: her basamak orta noktasiyla             21.59    +0.28
ikincil    B: her basamak alt siniriyla               14.11    -7.19
uretilen   A: eksik gunler oldugu gibi toplanir       17.01    -4.30
uretilen   B: kapsanan gune gore aya olceklenir       20.48    -0.83

modelin dogrusu 21.31 m3; alti sayinin hicbirinde hesap hatasi yok
kaynak ici en buyuk fark 7.48 m3, alti sayinin araligi 14.11 - 22.42 m3
uc kaynagin A kararlarinin ortalamasi 20.34 m3 — ardinda tek bir karar yoktur

kapsam basamak basamak
basamak       tum kume     ankette   ankette % telemetride telemetri %
1                   48          15       %31.3          43       %89.6
2                  970         351       %36.2         754       %77.7
3                  348         159       %45.7         224       %64.4
4                   34          19       %55.9          20       %58.8
```

Altı sayı 14,11 ile 22,42 m³ arasına yayılıyor ve hepsi aynı aboneleri, aynı ayı, aynı büyüklüğü
anlatıyor. Kaynak içinde en büyük fark 7,48 m³'tür — kaynaklar arası farktan büyüktür. Bu, dersin
en önemli sayısıdır: **hangi kaynağı seçtiğin kadar, o kaynağı nasıl işlediğin de sayıyı
oynatır**.

İkincil kaynağın iki kararı aynı soruya cevap vermiyor ve bu ayrım yazılmadıkça iki sayı
karşılaştırılamaz. Basamak orta noktası kullanmak bir **tahmindir**; basamak alt sınırı kullanmak
bir **alt sınırdır** ve "abonelerin en az ne kadar tükettiğini" cevaplar. Rapor edilen 14,11 m³
yanlış değildir, ama 21,59 ile yan yana konduğunda okuyucu iki tahmin gördüğünü sanır. Bir sayının
tahmin mi sınır mı olduğu, o sayının kendisinden okunamaz.

Birincil kaynakta geri ağırlıklama sapmayı 1,11'den 0,21 m³'e indiriyor. Düzeltmenin bedeli şudur:
ağırlıklar başka bir kaynaktan, faturalama özetinden gelir. Yanlılığı gidermek için ikinci bir
kaynağa gerek duyuldu ve o kaynağın da kendi kararları var. Telemetride kapsanan güne göre
ölçekleme sapmayı 4,30'dan 0,83 m³'e indiriyor; kalan 0,83 m³ ikinci nedenden, yüksek tüketen
cihazların iletmemesinden gelir ve gün ölçeklemesi ona dokunmaz. **Bir kararı düzeltmek yanlılığın
tamamını gidermez**; her kararın kapattığı boşluk ayrıdır.

Son tablo yanlılığın nereden geldiğini yazıyor. Ankette birinci basamaktaki abonelerin yüzde
31,3'ü, dördüncü basamaktakilerin yüzde 55,9'u var: yüksek tüketenler örnekte fazla temsil
ediliyor, bu yüzden ortalama yukarı kayıyor. Telemetride yön tersine dönüyor — birinci basamağın
yüzde 89,6'sı iletirken dördüncü basamağın yalnız yüzde 58,8'i iletiyor. İki kaynak da aynı ağdan,
aynı ayda, aynı abonelerden beslenir ve **zıt yönde yanlıdır**. Yanlılık verinin bir özelliği
değil, kaynağın kapsam kararının bir sonucudur; kapsam tablosu yazılmadan hiçbir sapma
açıklanamaz.

Üç kaynağın ortalamasını almak — 20,34 m³ — bu tabloyu yok saymaktır. O sayının ardında tek bir
karar yoktur; üç ayrı kapsam kararının aritmetik ortalamasıdır ve hangi soruyu cevapladığı
belirsizdir.

#### Özet

- Aynı büyüklük üç kaynakta üç sayı verir: saha anketi 22,42, faturalama özeti 21,59, telemetri
  17,01 m³; modelin doğrusu 21,31 m³'tür ve hiçbir kaynak onu görmez.
- Abone sayısı da kaynağa göre değişir — 1.400, 886, 1.041 — ve hangisinin sayıldığı yazılmadan
  bu sayı okunamaz.
- Kaynak içinde işleme kararının açtığı fark 7,48 m³'e çıkar ve kaynaklar arası farktan büyüktür.
- Bir tahmin ile bir alt sınır aynı biçimde yazılır ve ayırt edilemez: 21,59 bir tahmindir, 14,11
  bir alt sınırdır ve ikisi de aynı özetten çıkar.
- Yanlılık kapsam kararından gelir: ankette dördüncü basamağın yüzde 55,9'u, telemetride yüzde
  58,8'i vardır ve iki kaynak zıt yönde yanlıdır.

#### Sonraki Adım

Bu ders kaynağın hangi kayıtları dışarıda bıraktığını ölçtü, ama içeri alınan kayıtları sorgusuz
kabul etti: 544 anket satırının hepsi doğru doldurulmuş, 1.041 telemetri kaydının hepsi tutarlı
sayıldı. Gerçek bir kümede bu geçerli değildir. 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.
Sonraki ders bu dört soruyu dört ölçülebilir boyuta çevirir ve her biri için bir sayı üretir; sonra
eşikleri sıkılaştırıp kaç satırın elendiğini ve elenen satırların rapor edilen sayıyı hangi yöne
ittiğini gösterir.

### Veri Kalitesi Boyutları

Source: https://academia.sh/tr/kurslar/veri-analitigine-giris/veri-kalitesi-boyutlari

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.

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ı

```js
// 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

```js
// 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 ancak beşte birini kapatır. 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'dan 1,41 m³'e
  çekerken 482 eski kayıt onu yalnız 2,70'e çeker.
- 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.

### Veri Etiği ve Mahremiyet

Source: https://academia.sh/tr/kurslar/veri-analitigine-giris/veri-etigi-ve-mahremiyet

Aynı abone kümesine sorulan 18 sorunun 14'ü eldeki alanlarla cevaplanabilir, 4'ü için alan yoktur; sınır kuralı değişince cevaplanabilir olduğu halde sorulmaması gerekenlerin sayısı 3'ten 8'e çıkar ve raporlanabilir soru 11'den 6'ya iner. Kırılım derinleştikçe grup küçülür: bölge kırılımında en küçük grup 209 kayıt, dört alanlık kırılımda 1 kayıttır ve 45 abone tek başına bir hücrededir. En küçük grup eşiği 5'ten 10'a çıkarıldığında bastırılan hücre 117'den 146'ya, raporun dışında kalan kayıt 245'ten 431'e çıkar.

Bir önceki ders kalite eşiğini sıkılaştırdı ve 1.400 satırdan 422 satır bıraktı. O 422 satırın her
biri bir haneye aittir. Kurs boyunca satırlar birer gözlem olarak ele alındı; bir kırılım
yeterince inceltildiğinde satır artık bir gözlem değil, tek bir kişidir.

Bu ders iki şeyi sayar. Birincisi, aynı kümeye sorulabilecek sorulardan kaçının **cevaplanabilir
olduğu halde sorulmaması gerektiğidir**. İkincisi, bir kırılımın kaç kişilik gruba düştüğüdür.
İkisinin ortak noktası şudur: hiçbiri veriden okunmaz, çünkü bir hesabın yapılabilir olması
yapılması gerektiğini söylemez.

Tespit, Müdahale ve Uyumluluk kursunda denetim kaydının **ne kaydettiği** ölçülmüştü. Buradaki
soru başkadır: kayıt zaten alınmıştır; ölçülen şey **analizin nerede duracağıdır**.

- **VY19.** Küme yine 1.400 satırlık abone kaydıdır ve **kurgudur**. Sayılan şey kümenin içeriği
  değil, ona sorulabilecek sorulardır.
- **VY20. Kişisel veri**, tür olarak, bir kişiye bağlanabilen kayıttır. Sınırlar burada **analiz
  kararı** olarak ele alınır ve kararın sayıyı ne kadar oynattığı ölçülür.
- **VY21.** Üç sınır kuralı **birikimlidir**: tekil kişiye inen çıkarım yapılmaz, veri toplandığı
  amacın dışında kullanılmaz, hassas türde bir nitelik çıkarımla üretilmez.
- **VY22. En küçük grup eşiği** $k$, bir kırılım hücresinin raporlanabilmesi için içinde bulunması
  gereken en az kayıt sayısıdır. $k$ modele girdi olarak verilir.

#### Cevaplanabilir Ama Sorulmayacak

```js
// sorular.mjs — ayni abone kumesine sorulan 18 soru iki eksende siniflanir:
// veriyle cevaplanabilir mi, ve sinir kurali sorulmasina izin veriyor mu. MODELDIR.
// [soru, alan var mi, kisiye iner mi, amac disi mi, hassas cikarim mi]
export const SORULAR = [
  ["bolge basina ortalama tuketim", 1, 0, 0, 0],
  ["tarife basamagi dagilimi", 1, 0, 0, 0],
  ["saha ziyareti alan abone orani", 1, 0, 0, 0],
  ["memnuniyetin bolgeye gore farki", 1, 0, 0, 0],
  ["sayac basina aylik ortalama okuma", 1, 0, 0, 0],
  ["okuma gecikmesi en yuksek bolge", 1, 0, 0, 0],
  ["abone tarife degisikligini neden istedi", 0, 0, 0, 0],
  ["gelir duzeyi tuketimi nasil etkiliyor", 0, 0, 0, 0],
  ["sikayet eden abone hizmeti birakti mi", 0, 0, 0, 0],
  ["tanitim goren daha az mi tuketti", 0, 0, 0, 0],
  ["hangi hane su an bos", 1, 1, 0, 0],
  ["bir abonenin gunluk yasam duzeni", 1, 1, 0, 0],
  ["en dusuk tuketimli aboneler listesi", 1, 1, 0, 0],
  ["abone listesi tarife tanitimina verilsin", 1, 0, 1, 0],
  ["gecikmis abone baska hizmete yonlensin", 1, 0, 1, 0],
  ["saha ekibi memnuniyetle degerlendirilsin", 1, 0, 1, 0],
  ["tuketimden hanedeki kisi sayisi ve yas", 1, 0, 0, 1],
  ["gece tuketiminden bakim ihtiyaci", 1, 0, 0, 1],
].map(([s, alan, kisi, amac, hassas]) => ({ s, alan, kisi, amac, hassas }));
// Sinir kurallari birikimlidir; her biri bir onceki kumeye eklenir.
export const KURAL = [
  ["K0 kural yok", () => false],
  ["K1 kimlige inme yasak", (q) => q.kisi === 1],
  ["K2 + amac bagi", (q) => q.kisi === 1 || q.amac === 1],
  ["K3 + hassas cikarim", (q) => q.kisi === 1 || q.amac === 1 || q.hassas === 1],
];
if (import.meta.url === `file://${process.argv[1]}`) {
  const N = SORULAR.length, cevaplanabilir = SORULAR.filter((q) => q.alan === 1).length;
  console.log(`${N} soru, ayni abone kumesi; ${cevaplanabilir} tanesi elde bulunan ` +
    `alanlarla cevaplanabilir, ${N - cevaplanabilir} tanesi icin alan yok`);
  const y = (h) => String(h[0]).padEnd(24) + h.slice(1).map((v) => String(v).padStart(15)).join("");
  console.log("\n" + y(["sinir kurali", "sorulamaz", "raporlanabilir", "kapanan pay"]));
  for (const [ad, engel] of KURAL) {
    const yasak = SORULAR.filter((q) => q.alan === 1 && engel(q)).length;
    console.log(y([ad, yasak, cevaplanabilir - yasak,
      `%${(100 * yasak / cevaplanabilir).toFixed(1)}`]));
  }
  const [, k1] = KURAL[1], [, k3] = KURAL[3];
  console.log(`\nK1'de sorulamayan ${SORULAR.filter((q) => q.alan === 1 && k1(q)).length}, ` +
    `K3'te ${SORULAR.filter((q) => q.alan === 1 && k3(q)).length}; ` +
    `veri hic degismedi, yalnizca sinir kurali degisti`);
  console.log(`\niki ayri sinir: alan yok ${N - cevaplanabilir} soru (veri siniri), ` +
    `K3'te ${SORULAR.filter((q) => q.alan === 1 && k3(q)).length} soru (analiz siniri)`);
  const y2 = (h) => String(h[0]).padEnd(42) + h.slice(1).map((v) => String(v).padStart(14)).join("");
  console.log("\n" + y2(["analiz sinirina takilan soru", "cevaplanabilir", "engel"]));
  for (const q of SORULAR.filter((q) => q.alan === 1 && k3(q))) {
    console.log(y2([q.s, "evet", q.kisi ? "kimlik" : q.amac ? "amac" : "hassas tur"]));
  }
}
```

```
18 soru, ayni abone kumesi; 14 tanesi elde bulunan alanlarla cevaplanabilir, 4 tanesi icin alan yok

sinir kurali                  sorulamaz raporlanabilir    kapanan pay
K0 kural yok                          0             14           %0.0
K1 kimlige inme yasak                 3             11          %21.4
K2 + amac bagi                        6              8          %42.9
K3 + hassas cikarim                   8              6          %57.1

K1'de sorulamayan 3, K3'te 8; veri hic degismedi, yalnizca sinir kurali degisti

iki ayri sinir: alan yok 4 soru (veri siniri), K3'te 8 soru (analiz siniri)

analiz sinirina takilan soru              cevaplanabilir         engel
hangi hane su an bos                                evet        kimlik
bir abonenin gunluk yasam duzeni                    evet        kimlik
en dusuk tuketimli aboneler listesi                 evet        kimlik
abone listesi tarife tanitimina verilsin            evet          amac
gecikmis abone baska hizmete yonlensin              evet          amac
saha ekibi memnuniyetle degerlendirilsin            evet          amac
tuketimden hanedeki kisi sayisi ve yas              evet    hassas tur
gece tuketiminden bakim ihtiyaci                    evet    hassas tur
```

Tablo iki ayrı sınırı yan yana koyuyor. Dört soru **veri sınırına** takılır: kümede gelir, müdahale
ya da ayrılma kaydı yoktur ve bu sınır alan eklenerek kaldırılabilir. Sekiz soru **analiz
sınırına** takılır ve son sütun hepsi için "evet" yazar: cevaplanabilirler. Bu sınır alan
ekleyerek kaldırılmaz, çünkü engel eksik veri değil, sorunun kendisidir.

Sorulamayacak soru sayısı bir sabit de değildir. Yalnız kimliğe inme kuralı geçerliyken 3, üç
kural birlikteyken 8 çıkar; raporlanabilir soru 11'den 6'ya iner ve kümede tek bir kayıt değişmez.
Bir çözümleme "veri kişisel bilgi içeriyor mu" sorusuna evet ya da hayır cevabıyla yetinemez;
hangi kuralların uygulandığı yazılmadıkça kaç sorunun kapatıldığı bilinmez.

Kapatılan sekiz sorunun engelleri birbirinden farklıdır. Üçü kimliğe iner: "hangi hane şu an boş"
sorusu tüketim düşüşünden cevaplanabilir ve cevabı tek bir haneyi işaret eder. Üçü amaç bağını
kırar: kayıtlar ölçüm ve faturalama için toplanmıştır. İkisi hassas türde bir niteliği
**çıkarımla** üretir; kümede yaş ya da bakım ihtiyacı alanı yoktur, ama gece tüketimi deseninden
bir tahmin üretilebilir. Bu üçüncü grup en sessizidir, çünkü toplanmış bir hassas alan yoktur —
hassas nitelik analizin kendisinde doğar.

#### Kırılım Derinleştikçe Grup Küçülür

Kimliğe inme kuralı bir niyet beyanı olarak kaldığı sürece ölçülemez; ölçülebilmesi için bir
sayıya bağlanması gerekir: bir kırılım hücresinde kaç kişi var.

```js
// kirilim.mjs — kirilim derinlestikce grup buyuklugu; ayni 1.400 satirlik
// abone kaydi. MODELDIR, kume kurgudur.
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; };
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] },
];
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;
  return { bolge: b.ad, 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,
    basamak: tuketim < TARIFE[0] ? 1 : tuketim < TARIFE[1] ? 2 : tuketim < TARIFE[2] ? 3 : 4 };
});
const ALAN = [
  ["bolge", (k) => k.bolge, 5], ["basamak", (k) => k.basamak, 4],
  ["sayac", (k) => k.sayac_sayisi, 4], ["memnuniyet", (k) => k.memnuniyet, 5],
  ["ziyaret", (k) => k.ziyaret_sayisi, 6],
];
const hucreler = (d) => {
  const m = new Map();
  for (const k of KAYITLAR) {
    const anahtar = ALAN.slice(0, d).map(([, f]) => f(k)).join("|");
    m.set(anahtar, (m.get(anahtar) ?? 0) + 1);
  }
  return [...m.values()];
};
const y = (h) => String(h[0]).padEnd(48) + h.slice(1).map((v) => String(v).padStart(10)).join("");
console.log(`${KAYIT} abone kaydi; kirilim her adimda bir alan derinlesir`);
console.log("\n" + y(["kirilim", "olasi", "dolu", "en kucuk", "tekil", "k<5 kayit"]));
for (let d = 1; d <= ALAN.length; d++) {
  const h = hucreler(d), olasi = ALAN.slice(0, d).reduce((a, [, , n]) => a * n, 1);
  console.log(y([ALAN.slice(0, d).map(([a]) => a).join(" x "), olasi, h.length,
    Math.min(...h), h.filter((n) => n === 1).length,
    h.filter((n) => n < 5).reduce((a, n) => a + n, 0)]));
}
// Esik karari: en kucuk grup buyuklugu k. k altindaki hucreler bastirilir.
const bastir = (d, k) => {
  const h = hucreler(d);
  const kapali = h.filter((n) => n < k);
  return { hucre: h.length, kapali: kapali.length, kayit: kapali.reduce((a, n) => a + n, 0) };
};
console.log("\nen kucuk grup esigi degisince (kirilim: bolge x basamak x sayac x memnuniyet)");
const y2 = (h) => String(h[0]).padEnd(10) + h.slice(1).map((v) => String(v).padStart(16)).join("");
console.log(y2(["esik", "dolu hucre", "bastirilan", "disarida kayit", "kapsam"]));
for (const k of [5, 10, 20]) {
  const o = bastir(4, k);
  console.log(y2([`k = ${k}`, o.hucre, o.kapali, o.kayit,
    `%${(100 * (KAYIT - o.kayit) / KAYIT).toFixed(1)}`]));
}
const a = bastir(4, 5), b = bastir(4, 10);
console.log(`\nk 5'ten 10'a cikinca bastirilan hucre ${a.kapali} yerine ${b.kapali}, ` +
  `raporun disinda kalan kayit ${a.kayit} yerine ${b.kayit}`);
const derin = hucreler(5);
console.log(`en ince kirilimda ${derin.filter((n) => n === 1).length} abone tek basina ` +
  `bir hucrede; o hucrenin her sayisi bir kisinin kaydidir`);
```

```
1400 abone kaydi; kirilim her adimda bir alan derinlesir

kirilim                                              olasi      dolu  en kucuk     tekil k<5 kayit
bolge                                                    5         5       209         0         0
bolge x basamak                                         20        16         2         0         2
bolge x basamak x sayac                                 80        54         1         4        49
bolge x basamak x sayac x memnuniyet                   400       190         1        45       245
bolge x basamak x sayac x memnuniyet x ziyaret        2400       502         1       251       694

en kucuk grup esigi degisince (kirilim: bolge x basamak x sayac x memnuniyet)
esik            dolu hucre      bastirilan  disarida kayit          kapsam
k = 5                  190             117             245           %82.5
k = 10                 190             146             431           %69.2
k = 20                 190             172             770           %45.0

k 5'ten 10'a cikinca bastirilan hucre 117 yerine 146, raporun disinda kalan kayit 245 yerine 431
en ince kirilimda 251 abone tek basina bir hucrede; o hucrenin her sayisi bir kisinin kaydidir
```

Tek alanlık kırılımda en küçük grup 209 kayıttır ve tekil hücre yoktur. İkinci alanla en küçük
grup 2'ye iner, üçüncüde ilk tekil hücreler görünür, dördüncüde 45, beşincide 251 abone tek başına
bir hücrededir. **Kırılım derinleştikçe hücre sayısı çarpımla artar, kayıt sayısı sabit kalır**;
ikisinin oranı grup büyüklüğüdür ve hızla 1'e düşer.

Bunun anlamı şudur: dört alanlık kırılımda "kuzey bölgesinde, üçüncü tarife basamağında, iki
sayaçlı, memnuniyet notu 1 olan abonelerin ortalama tüketimi" satırı bir özet gibi görünür ve
gerçekte tek bir kişinin okumasıdır. Rapor hiçbir kimlik alanı taşımaz; yine de o dört niteliği
bilen biri için satır o kişiye aittir. **Kimliğe inmek için kimlik alanına gerek yoktur.**

Son tablo bunun karşısına ölçülebilir bir karar koyuyor. $k = 5$ seçildiğinde 190 hücrenin 117'si
bastırılır, 245 kayıt raporun dışında kalır ve kapsam yüzde 82,5'e iner; $k = 10$ seçildiğinde 146
hücre bastırılır, 431 kayıt dışarıda kalır, kapsam yüzde 69,2 olur. Eşiği ikiye katlamak
bastırılan hücreyi yüzde 25 artırır ama **dışarıda kalan kaydı yüzde 76 artırır**, çünkü eşik
yükseldikçe daha kalabalık hücreler de sınırın altına düşer. $k$ bir teknik ayar değil, bir takası
yazan karardır ve iki savunulabilir eşik iki farklı rapor üretir. Bir kırılım tablosunun yanında
hangi $k$ ile bastırıldığı yazılmazsa okuyucu bastırılmış hücrelerin var olmadığını sanır.

#### Özet

- İki ayrı sınır vardır: dört soru veri sınırına takılır ve alan eklenerek açılabilir, sekiz soru
  analiz sınırına takılır ve hepsi cevaplanabilirdir.
- Sorulamayacak soru sayısı da bir karara bağlıdır: tek kuralla 3, üç kural birlikteyken 8 çıkar.
- Hassas nitelik her zaman toplanmış bir alan değildir; iki soruda kümede yoktur, çıkarımla
  üretilir.
- Kırılım derinleştikçe grup küçülür: en küçük grup bir alanda 209, dört alanda 1 kayıttır ve 45
  abone tek başına bir hücrededir.
- En küçük grup eşiği bir takas kararıdır: $k$ 5'ten 10'a çıkınca bastırılan hücre 117'den 146'ya,
  dışarıda kalan kayıt 245'ten 431'e çıkar.

#### Kurs Kapanışı

Dokuz ders aynı işi yaptı: bir sayı üretti, kararı yazdı, kararı değiştirip farkı bastı.

| Ders | Rapor edilen sayı | Değişen karar | Fark |
|---|---|---|---|
| Veri Analitiği Nedir | 3 849 etkin abone | etkin tanımı değişir | 3 548, 645 kayıtta ayrışma |
| Analitik Türleri | 7 cevaplanabilir soru | türetilmiş alan yok sayılır | 2 soru, 5'i kapanır |
| Analiz İş Akışı | 33 adım ziyareti | karar doğduğu adımda yazılır, ön bakış eklenir | 8 ziyaret, 1 dönüş |
| Analist Rolleri | yüzde -5,14 abone | ölçüt abone başına ücret | yüzde +1,89 |
| Veri Türleri | ortalama 1,20 ziyaret | kesikli alan dağılımla okunur | eşit kayıt 0, yüzde 68,3 altında |
| Ölçüm Ölçekleri | dogu 3,71 ile birinci | basamak kodlaması değişir | dogu 5,88 ile beşinci |
| Veri Kaynakları | 22,42 m³ saha anketi | kaynak telemetriye geçer | 17,01 m³, 5,41 m³ açık |
| Veri Kalitesi | 24,70 m³, 1.400 satır | kalite eşiği sıkılaşır | 20,83 m³, 422 satır |
| Veri Etiği | 3 soru sorulamaz | sınır kuralı genişler | 8 soru, 6'sı raporlanabilir |

Dokuz satırın hiçbirinde hesap hatası yoktur. Her satırın sol sütunu da sağ sütunu da
savunulabilir bir sayıdır ve aralarındaki farkı üreten tek şey orta sütundur. Kursun kuralı budur
ve dokuz kez ölçülmüştür: **bir sayının yanında hangi kararla üretildiği yazılmıyorsa o sayı bir
bulgu değil, bir seçimdir.** Kararı yazılmayan sayı ölçülmemiş sayılır.

Tablonun kendisi bir sorun gösteriyor. Dokuz derste sayılan bütün kararlar **elle** alındı: hangi
tanım seçildi, hangi kodlama kullanıldı, hangi kaynak okundu, hangi eşik uygulandı. Hiçbiri yazılı
bir yerde durmuyor; kararların gövdesi bu derslerin metnindedir, hesabın kendisinde değil. Aynı
kümeyi alan ikinci bir kişi aynı sayıyı bulacak mı sorusunun cevabı yok, çünkü onun elinde
kararların listesi değil yalnız sonuç var. Sonraki kurs olan **Elektronik Tablolarla Analiz** işi
buradan alır: hesabın bir yerde durduğu, bir girdiyi değiştirmenin bütün sonuçları yeniden
hesapladığı bir düzenekte aynı kararların ne kadarının görünür kaldığını ölçer.

