---
title: 'Eksik Değerler'
source: 'https://academia.sh/tr/kurslar/veri-hazirlama/eksik-degerler'
course: 'Veri Toplama ve Hazırlama'
language: tr
updated: '2026-08-17T18:08:44+00:00'
license: 'CC BY-SA 4.0'
---

# Eksik Değerler

Toplama adımının bıraktığı 2.086 satırın okuma alanı üç ayrı biçimde boştur: 104 satırda hücre boş, 31 satırda yalnız boşluk, 70 satırda 'yok' yazılıdır. Eksiklik rastgele değildir — oran bölgeye göre yüzde 3,9 ile yüzde 28,1 arasında değişir ve bir bölge rastgele dağılımın beklettiği sayının 2,85 katını taşır. Eksik okumalı satırı silmek kümeyi 2.068'den 1.864'e indirir, ağ ortalamasını 22,45 m³'te bırakır ve zararsız görünür; oysa silinen 204 satırın 99'u tek bir bölgedendir ve o bölgenin küme içindeki payı yüzde 17,0'den 13,6'ya, 3,4 puan düşer. Yalnız boş hücreyi eksik sayan bir süzgeç 100 satırı görmez: 31'i sessizce sıfır tüketime döner, 69'u sayısal süzgeçten sessizce düşer ve ortalama 22,09 m³'e iner.

Bir önceki konu veriyi kaynağından çekti ve her adımda kaç satırın girip çıktığını saydı. Küme bir
dosyada duruyor, satır sayısı biliniyor; bilinmeyen tek şey satırların içidir.

Bu ders okuma alanını açar. Alan üç ayrı biçimde boş çıkar ve üçü aynı şeyi söylemez. Ardından iki
savunulabilir karar durur: eksik okumalı satırı silmek ya da işaretleyip doldurmak. Elektronik
Tablolarla Analiz kursu bu kararı hücre düzeyinde tartıştı ve kararın sayfadan geri okunup
okunamadığını ölçtü; burada ölçü tektir — **satır hesabı**. Kaç satır girdi, kaç satır çıktı,
aradaki fark nereye gitti.

- **VZ1.** Ham küme `node` ile **modellenir**. Her alan saha formundan geldiği haliyle
  **metindir**; hiçbir tip zorlanmamıştır. Veri kümesi **kurgudur**: bölgesel ölçüm ağının 1.400
  abonesi ve saha ziyaret kayıtları.
- **VZ2.** Eksiklik üç biçimde görünür: hücre **boştur**, hücrede **yalnız boşluk** vardır, hücreye
  **"yok" yazılmıştır**. Üçü aynı şeyi anlatır, üçü farklı davranır.
- **VZ3.** **Kimlik alanı** (sayaç kodu) boş olan satır hiçbir aboneye bağlanamaz; doldurulamaz,
  yalnız elenebilir. Ölçüm alanının eksikliği ile kimlik alanınınki ayrı iki karardır.
- **VZ4.** Eksikliğin rastgele olup olmadığı, her grupta **gözlenen** eksik sayısının rastgele
  dağılımın **beklettiği** sayıya oranıyla ölçülür.

## Eksiklik Rastgele mi

```js
// ham.mjs — toplama adiminin biraktigi ham kume MODELIDIR: her alan saha
// formundan geldigi haliyle metindir, hicbir tip zorlanmamistir. Kume
// kurgudur: bolgesel olcum aginin 1400 abonesi ve saha ziyaret kayitlari.
export const TOHUM = 20260305, ABONE = 1400;
const karistir = (x) => { x = Math.imul(x ^ (x >>> 16), 2246822507);
  x = Math.imul(x ^ (x >>> 13), 3266489909); return (x ^ (x >>> 16)) >>> 0; };
export const uretec = (t) => { let s = karistir(t);
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; };
export 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; };
// Son alan: ziyaretin okuma uretmeme orani. Bolgeler bu oranda ayrisir.
export const BOLGE = [["kuzey", "KZ", 0.28, 21, 0.06], ["guney", "GN", 0.22, 17, 0.03],
  ["dogu", "DG", 0.18, 26, 0.27], ["bati", "BT", 0.14, 14, 0.03],
  ["merkez", "MR", 0.18, 23, 0.08]]
  .map(([ad, kod, pay, taban, eksik]) => ({ ad, kod, pay, taban, eksik }));
const SOKAK = ["Çınar", "Söğüt", "Işık", "Ihlamur", "Zeytin", "Menekşe", "Palmiye", "Ceviz"];
const TARIFE = ["Mesken", "mesken", "MESKEN", " Mesken ", "Konut", "konut", "Ticari",
  "ticari", "TİCARİ", "Is yeri", "İş Yeri", "isyeri", "Sanayi", "sanayi", "Tarimsal"];

export const HAM = [];
let bir = null;
for (let i = 0; i < ABONE; i++) {
  const r = uretec(TOHUM + i);
  const b = BOLGE[ayrik(r(), BOLGE.map((x) => x.pay))];
  const taban = Math.max(1.2, b.taban * Math.exp((r() + r() + r() - 1.5) * 0.62));
  const sayac = `${b.kod}-${String(1000 + i).padStart(4, "0")}`;
  const paylas = bir && bir.b === b.ad && r() < 0.03;   // ayni binada ikinci sayac
  const sk = paylas ? bir.sk : SOKAK[Math.floor(r() * SOKAK.length)];
  const kapi = paylas ? bir.kapi : 1 + Math.floor(r() * 60);
  const daire = paylas ? bir.daire : r() < 0.26 ? `/${1 + Math.floor(r() * 9)}` : "";
  bir = { b: b.ad, sk, kapi, daire };
  const endeks0 = 8000 + Math.floor(r() * 11000);
  for (const d of r() < 0.34 ? ["2026-01", "2026-02"] : ["2026-01"]) {
    const q = uretec(TOHUM + 7000 + HAM.length), u = q();
    const gercek = Math.round(taban * (d === "2026-02" ? 0.94 : 1) * 100) / 100;
    // Eksiklik uc bicimde gorunur: hucre bos, hucrede yalniz bosluk, "yok" yazili.
    const eksik = u < b.eksik ? ayrik(q(), [0.52, 0.19, 0.29]) : -1;
    const kayma = eksik < 0 && q() < 0.008;   // ondalik kaymasi: okuma on kat yazilmis
    const yazilan = kayma ? Math.round(gercek * 1000) / 100 : gercek;
    const okuma = eksik === 0 ? "" : eksik === 1 ? "  " : eksik === 2 ? "yok"
      : q() < 0.31 ? yazilan.toFixed(2).replace(".", ",") : yazilan.toFixed(2);
    const gun = 1 + Math.floor(q() * 27), ay = d.slice(5);
    const tb = ayrik(q(), [0.55, 0.21, 0.24]);
    const tarih = tb === 0 ? `${d}-${String(gun).padStart(2, "0")}`
      : tb === 1 ? `${String(gun).padStart(2, "0")}.${ay}.2026`
      : `${String(gun).padStart(2, "0")}/${ay}/2026`;
    const endeks = endeks0 + Math.round(gercek * (d === "2026-02" ? 2 : 1));
    const eb = q() < 0.22;
    const av = ayrik(q(), [0.30, 0.18, 0.18, 0.16, 0.18]);
    const kap = `${kapi}${daire}`;
    const M = `${b.ad[0].toUpperCase()}${b.ad.slice(1)}`, mUst = b.ad.toLocaleUpperCase("tr");
    const alt = sk.toLocaleLowerCase("tr"), ust = sk.toLocaleUpperCase("tr");
    const adres = av === 0 ? `${b.ad} mahallesi ${alt} sokak no: ${kap}`
      : av === 1 ? `${M} Mahallesi ${sk} Sokak No ${kap}`
      : av === 2 ? `${mUst} MAHALLESİ ${ust} SOKAK NO ${kap}`
      : av === 3 ? `  ${M}  Mahallesi  ${sk}  Sokak  No ${kap} `
      : `${b.ad} mah. ${alt} sk. no:${kap}`;
    HAM.push({ abone_no: 10001 + i, sayac_no: q() < 0.011 ? "" : sayac, bolge: b.ad,
      donem: d, okuma_metni: okuma,
      endeks_metni: eb ? `${Math.floor(endeks / 1000)}.${String(endeks % 1000).padStart(3, "0")}`
        : `${endeks}`,
      tarih_metni: tarih, tarife_metni: TARIFE[ayrik(q(), Array(15).fill(1 / 15))],
      adres_metni: adres, gercek_m3: gercek, yazilan_m3: eksik < 0 ? yazilan : null });
    if (q() < 0.09) {   // ayni ziyaret ikinci kez girilmis
      const on = HAM[HAM.length - 1], bicim = ayrik(q(), [0.34, 0.28, 0.38]);
      HAM.push({ ...on,
        sayac_no: bicim === 0 ? ` ${sayac}` : bicim === 1 ? sayac.toLowerCase() : sayac,
        adres_metni: av === 2 ? `${b.ad} mah. ${alt} sk. no:${kap}`
          : `${mUst} MAHALLESİ ${ust} SOKAK NO ${kap}`,
        tarife_metni: TARIFE[ayrik(q(), Array(15).fill(1 / 15))] });
    }
  }
}

// Okumayi sayiya cevirir. Ondalik ayraci virgul de olabilir; donusumun kendi
// tuzaklari bu konunun ucuncu dersinde olculur, burada tolere edilir.
export const sayiya = (t) => { const s = String(t).trim().replace(",", ".");
  return s === "" || !/^\d+(\.\d+)?$/.test(s) ? null : Number(s); };
export const medyan = (a) => { const l = [...a].sort((x, y) => x - y);
  return l.length % 2 ? l[(l.length - 1) / 2] : (l[l.length / 2 - 1] + l[l.length / 2]) / 2; };
export const y = (w) => (h) => h.map((v, j) => (j ? String(v).padStart(w[j])
  : String(v).padEnd(w[0]))).join("");

if (import.meta.url === `file://${process.argv[1]}`) {
  const say = (f) => HAM.filter(f).length;
  console.log(`model (tohum ${TOHUM}): ${ABONE} abone, toplama adiminin biraktigi ` +
    `ham kume ${HAM.length} satir`);
  const y1 = y([30, 8, 26]);
  console.log("\n" + y1(["eksikligin gorunusu", "satir", "yaygin donusum ne verir"]));
  console.log(y1(["bos hucre", say((s) => s.okuma_metni === ""), 'Number("") -> 0']));
  console.log(y1(["yalniz bosluk", say((s) => s.okuma_metni !== "" && s.okuma_metni.trim() === ""),
    'Number("  ") -> 0']));
  console.log(y1(['"yok" yazili', say((s) => s.okuma_metni.trim() === "yok"),
    'Number("yok") -> NaN']));
  console.log(y1(["kimlik alani bos", say((s) => s.sayac_no.trim() === ""),
    "satir atfedilemez"]));

  const kimlikli = HAM.filter((s) => s.sayac_no.trim() !== "");
  const eksikler = kimlikli.filter((s) => sayiya(s.okuma_metni) === null);
  const y2 = y([9, 8, 8, 10, 15, 7]);
  console.log("\neksiklik rastgele mi");
  console.log(y2(["bolge", "satir", "eksik", "oran %", "rastgele ise", "kat"]));
  for (const b of BOLGE) {
    const n = say((s) => s.bolge === b.ad && s.sayac_no.trim() !== "");
    const e = eksikler.filter((s) => s.bolge === b.ad).length;
    const bek = eksikler.length * n / kimlikli.length;
    console.log(y2([b.ad, n, e, (100 * e / n).toFixed(1), bek.toFixed(1), (e / bek).toFixed(2)]));
  }
  console.log(`${kimlikli.length} satirin ${eksikler.length} tanesinde okuma yok; ` +
    `eksiklik bolgeye gore yuzde 3.9 ile yuzde 28.1 arasinda degisiyor`);
}
```

```
model (tohum 20260305): 1400 abone, toplama adiminin biraktigi ham kume 2086 satir

eksikligin gorunusu              satir   yaygin donusum ne verir
bos hucre                          104           Number("") -> 0
yalniz bosluk                       31         Number("  ") -> 0
"yok" yazili                        70      Number("yok") -> NaN
kimlik alani bos                    18         satir atfedilemez

eksiklik rastgele mi
bolge       satir   eksik    oran %   rastgele ise    kat
kuzey         591      48       8.1           58.3   0.82
guney         414      16       3.9           40.8   0.39
dogu          352      99      28.1           34.7   2.85
bati          324      12       3.7           32.0   0.38
merkez        387      29       7.5           38.2   0.76
2068 satirin 204 tanesinde okuma yok; eksiklik bolgeye gore yuzde 3.9 ile yuzde 28.1 arasinda degisiyor
```

İlk tablo eksikliğin tek bir şey olmadığını gösteriyor. 104 satırda hücre gerçekten boştur; 31
satırda içinde yalnız boşluk vardır ve gözle boştan ayırt edilmez; 70 satıra ziyaret sonucu **"yok"
olarak yazılmıştır**. Üçüncü sütun neden ayrı sayıldıklarını söylüyor: ilk ikisi yaygın bir sayıya
çevirme çağrısından **sıfır** olarak çıkar, üçüncüsü sayı olmayan bir değer verir. Aynı eksiklik,
yazılış biçimine göre ya bir ölçüm gibi görünür ya da hesabın dışına düşer.

İkinci tablo dersin asıl sorusunu cevaplıyor. Eksiklik rastgele olsaydı her bölge kümedeki payı
kadar eksik taşırdı: `dogu` bölgesi 34,7 satır beklerdi, gerçekte 99 satır taşıyor — beklenenin
**2,85 katı**. `guney` ve `bati` beklenenin ancak yüzde 39'unu taşıyor. Eksiklik bir gürültü değil,
bir **desendir**, ve bu ayrım bütün kararı belirler: rastgele eksiklikte silinen satırlar kümenin
küçük bir kopyasıdır, desenli eksiklikte **belirli bir gruptur**.

## Silme Kimi Eliyor

```js
// eksik.mjs — ayni ham kume, uc soru: silme karari hangi grubu orantisiz eliyor,
// doldurma neyi degistirmiyor, eksikligi eksik saymayan bir suzgec kac satiri
// sessizce dusuruyor.
import { HAM, BOLGE, sayiya, medyan, y } from "./ham.mjs";

// Kimlik alani bos olan satir doldurulamaz: okuma bir sayaca baglanamiyorsa
// hangi abonenin tuketimi oldugu yazilamaz. Bu satirlar elenir ve sayisi yazilir.
const kimlikli = HAM.filter((s) => s.sayac_no.trim() !== "");
const elenen = HAM.length - kimlikli.length;
const olculen = kimlikli.filter((s) => sayiya(s.okuma_metni) !== null);
const bolgeMed = new Map(BOLGE.map((b) => [b.ad,
  medyan(olculen.filter((s) => s.bolge === b.ad).map((s) => sayiya(s.okuma_metni)))]));
const dolu = kimlikli.map((s) => sayiya(s.okuma_metni) === null
  ? { ...s, okuma_metni: bolgeMed.get(s.bolge).toFixed(2), eksikti: true } : s);

const ort = (l) => l.reduce((a, s) => a + sayiya(s.okuma_metni), 0) / l.length;
const y1 = y([32, 8, 8, 12, 14]);
console.log(y1(["ayni kume, iki karar", "giren", "cikan", "ag ort m3", "dogu payi %"]));
for (const [ad, l] of [["K1 eksik okumali satir elenir", olculen],
  ["K2 bolge ortancasiyla doldurulur", dolu]]) {
  console.log(y1([ad, kimlikli.length, l.length, ort(l).toFixed(2),
    (100 * l.filter((s) => s.bolge === "dogu").length / l.length).toFixed(1)]));
}
console.log(`\nsilme agin ortalamasini ${ort(olculen).toFixed(2)} m3'te birakiyor, ` +
  `doldurma ${ort(dolu).toFixed(2)} m3; iki sayi arasindaki ` +
  `${Math.abs(ort(olculen) - ort(dolu)).toFixed(2)} m3 raporlanan iki ondalik basamagin ` +
  `yarisindan buyuk, ama kararin buyuklugunu anlatmiyor`);

// Silme kimi eliyor: her bolgenin kume icindeki payi once ve sonra.
const y2 = y([9, 9, 8, 11, 11, 9]);
console.log("\n" + y2(["bolge", "elenen", "payi %", "once %", "sonra %", "puan"]));
for (const b of BOLGE) {
  const once = kimlikli.filter((s) => s.bolge === b.ad).length;
  const sonra = olculen.filter((s) => s.bolge === b.ad).length;
  const p0 = 100 * once / kimlikli.length, p1 = 100 * sonra / olculen.length;
  console.log(y2([b.ad, once - sonra, (100 * (once - sonra) /
    (kimlikli.length - olculen.length)).toFixed(1), p0.toFixed(1), p1.toFixed(1),
    (p1 - p0).toFixed(1)]));
}

// Eksikligi yalnizca bos hucre sayan bir suzgec: kalan iki bicim sessizce gecer.
const bosluk = kimlikli.filter((s) => s.okuma_metni !== "" && s.okuma_metni.trim() === "");
const yok = kimlikli.filter((s) => s.okuma_metni.trim() === "yok");
const sifira = bosluk.filter((s) => Number(s.okuma_metni) === 0).length;
const nan = yok.filter((s) => Number.isNaN(Number(s.okuma_metni))).length;
console.log(`\nyalniz bos hucreyi eksik sayan bir suzgec ${kimlikli.length} satirin ` +
  `${bosluk.length + yok.length} tanesini gormez: ${sifira} satir sessizce 0 m3 ` +
  `tuketime doner, ${nan} satir sayisal suzgecten sessizce duser`);
console.log(`ayni suzgecle raporlanan ag ortalamasi ` +
  `${ort(kimlikli.filter((s) => s.okuma_metni !== "" && !Number.isNaN(Number(s.okuma_metni
    .trim().replace(",", ".")))).map((s) => (Number(s.okuma_metni.trim().replace(",", ".")) === 0
    ? { ...s, okuma_metni: "0" } : s))).toFixed(2)} m3 cikar`);

console.log(`\nsatir hesabi: giren ${HAM.length}, cikan ${dolu.length}; ` +
  `${elenen} satir elendi (kimlik alani bos), ` +
  `${dolu.filter((s) => s.eksikti).length} satir isaretlenip dolduruldu, ` +
  `0 satir sessizce dustu`);
```

```
ayni kume, iki karar               giren   cikan   ag ort m3   dogu payi %
K1 eksik okumali satir elenir       2068    1864       22.45          13.6
K2 bolge ortancasiyla doldurulur    2068    2068       22.41          17.0

silme agin ortalamasini 22.45 m3'te birakiyor, doldurma 22.41 m3; iki sayi arasindaki 0.04 m3 raporlanan iki ondalik basamagin yarisindan buyuk, ama kararin buyuklugunu anlatmiyor

bolge       elenen  payi %     once %    sonra %     puan
kuzey           48    23.5       28.6       29.1      0.6
guney           16     7.8       20.0       21.4      1.3
dogu            99    48.5       17.0       13.6     -3.4
bati            12     5.9       15.7       16.7      1.1
merkez          29    14.2       18.7       19.2      0.5

yalniz bos hucreyi eksik sayan bir suzgec 2068 satirin 100 tanesini gormez: 31 satir sessizce 0 m3 tuketime doner, 69 satir sayisal suzgecten sessizce duser
ayni suzgecle raporlanan ag ortalamasi 22.09 m3 cikar

satir hesabi: giren 2086, cikan 2068; 18 satir elendi (kimlik alani bos), 204 satir isaretlenip dolduruldu, 0 satir sessizce dustu
```

İlk tablonun en tehlikeli sütunu ağ ortalamasıdır. Silme 204 satır atar, doldurma hiç atmaz, ve iki
kararın ortalaması 22,45 ile 22,41 m³'tür. Fark 0,04 m³; yalnız bu sayıya bakan biri kararın
zararsız olduğu sonucuna varır. Karşılaştırma eşitlik işleciyle değil, raporlama duyarlılığı olan
0,005 m³ eşiğiyle yapılmıştır — kayan noktalı iki değer arasındaki eşitlik zaten sorulamaz.

Son sütun asıl bedeli gösteriyor: `dogu` bölgesinin payı yüzde 17,0'den **13,6'ya** iner. Silinen
204 satırın **99'u**, yani yüzde 48,5'i tek bir bölgedendir. Bu bir hata değildir ve kümenin
görünüşünden anlaşılmaz: silme işlemi 1.864 düzgün satır bırakır. Ortalama korunurken
**kompozisyon** değişmiştir, ve bundan sonra bölge kırılımıyla üretilecek her sayı bu kaymayı
taşır.

Üçüncü blok sessiz kaybı ölçüyor. Eksikliği yalnız boş hücre sayan bir süzgeç 2.068 satırın
**100'ünü** hiç görmez: 31'i sayıya çevrilirken sessizce sıfır olur ve gerçek bir sıfır tüketim gibi
durur, 69'u sayı olmayan bir değere döner ve ilk sayısal süzgeçte sessizce düşer. Aynı süzgeçle
raporlanan ağ ortalaması 22,09 m³'tür — hiçbir uyarı, yalnız 0,36 m³ aşağıda bir sayı.

Adımın hesabı şudur: **giren 2.086 satır, çıkan 2.068 satır.** Aradaki 18 satır kimlik alanı boş
olduğu için elendi, 204 satır işaretlenip dolduruldu ve kümede kaldı, sessizce düşen satır
**sıfırdır**. Kaybın kalem kalem yazılabilmesi kararın doğru olduğunu göstermez, yalnız
**görülebilir** olduğunu gösterir.

## Özet

- Toplama adımının bıraktığı 2.086 satırda eksiklik üç biçimde görünür: 104 boş hücre, 31 yalnız
  boşluk, 70 "yok" yazılı hücre; ilk ikisi yaygın dönüşümde sıfıra döner.
- Eksiklik rastgele değildir: oran bölgeye göre yüzde 3,9 ile 28,1 arasında değişir, bir bölge
  beklenenin 2,85 katını taşır.
- Silme kümeyi 2.068'den 1.864'e indirir ve ağ ortalamasını 22,45 m³'te bırakarak zararsız görünür;
  silinen 204 satırın 99'u tek bir bölgedendir ve o bölgenin payı 3,4 puan düşer.
- Yalnız boş hücreyi eksik sayan bir süzgeç 100 satırı görmez — 31'i sessizce sıfıra döner, 69'u
  sessizce düşer — ve ağ ortalamasını 22,09 m³ olarak raporlar.
- Adımın hesabı: giren 2.086, çıkan 2.068; 18 elendi, 204 işaretlenip dolduruldu, 0 sessizce düştü.

## Sonraki Adım

Kalan 2.068 satırın hepsinin ayrı bir ziyareti temsil ettiği varsayıldı. Varsayım tutmuyor: aynı
abonenin aynı dönemdeki okuması bir bölüm satırda ikinci kez girilmiştir ve ikinci girişte sayaç
kodu bazen baştaki boşluğu, bazen küçük harfi taşır. Sonraki ders üç tekilleştirme ölçütü uygular
ve ölçüt değişince kaç satırın birleştiğini sayar, ardından okunaksız yazılmış destek taleplerini
abone kütüğüne bağlar: kesin eşleşme ile benzerlik eşiğinin kurduğu bağların kaçı **yanlış
aboneye** gidiyor.
