İçeriğe geç
academia.sh

Ders 08 / 11

Eksik Veriyle Baş Etme

Aynı 1.877 satırlık sayfanın okuma sütununda 116 hücre boş, 112 hücre sıfırdır ve sıfırların 55'i gerçek sıfır tüketim değil, okunmamış bir ziyarettir; boş hücrelerin karşılığı olan 2.719,2 m³ raporlanan toplamın içindedir. Aynı sütunun ortalaması dört kararla 19,23, 18,04, 20,54 ve yine 19,23 m³ verir: en düşükle en yüksek arasında 2,49 m³, doldurma ise ortalamayı hiç oynatmadan toplamı 33.866,8'den 36.097,6 m³'e çıkarır. Boş hücre oranı bölgeler arasında yüzde 2,0 ile yüzde 17,3 arasında değişir ve boşlar sıfır sayılınca bir bölgenin ortalaması 3,94 m³ düşer. İşlem bitince dört karardan doldurulmuş sayfada sıfırı, not düşülmüş sayfada biri iki adımda, izli sayfada dördü bir adımda geri okunur.

İçindekiler

Bir önceki ders sayfayı 1.877 satıra indirdi ve kalan satırların hepsinin dolu olduğunu varsaydı. Varsayım tutmuyor. Okuma sütununda bir bölüm hücre boştur, bir bölümünde sıfır yazar ve elektronik tablo bu ikisini her işlemde aynı saymaz: toplama işlevi boş hücreyi atlar, sıfırı toplar; ortalama işlevi boş hücreyi hem bölünenden hem bölenden düşürür, sıfırı yalnız bölünenden.

Bu ders o sütunun ortalamasını hesaplar. Hesap tek satırlıktır, önünde en az üç karar durur: boş hücre dışlanacak mı sıfır mı sayılacak mı doldurulacak mı, sıfır yazan hücreler gerçek sıfır tüketim mi, doldurma hangi değerle yapılacak. Üçü de ortalamayı oynatır ve üçü de işlem bitince sayfadan okunamaz. Dersin iki sayısı budur: kararın verdiği ortalama ve kaç kararın geri okunabildiği.

  • TO5. Sayfa bir önceki dersin tekilleştirilmiş 1.877 satırıdır, ama okuma sütunu bu kez saha formundaki haliyle durur. Elektronik tablo yine node ile modellenir, veri kümesi kurgudur.
  • TO6. Eksiklik üç biçimde görünür: ziyaret okuma üretmemiştir ve hücre boştur; sayaç mühürlüdür ve tüketim gerçekten sıfırdır; okuma alınamamıştır ama forma sıfır yazılmıştır.
  • TO7. Toplama ve ortalama işlevleri boş hücreyi atlar; dışlama kararı bu yüzden toplamı oynatmaz, ortalamayı oynatır.
  • TO8. Kararın kurtarılabilirliği ölçüsü sürer: karar bir hücre formülünde yazılıysa bir adımda, ayrı bir not hücresinde iki adımda okunur, hiçbir hücrede yoksa okunamaz.

Aynı Sütun, Dört Ortalama

// eksik.mjs — elektronik tablo MODELIDIR: hucre bir eslemede durur, bos hucre
// hicbir deger tasimaz, formul kendi metnini tasir. Hicbir uygulama taklit
// edilmez. Veri kumesi kurgudur: onceki dersin tekillestirilmis 1877 satirlik
// sayfasi, bu kez okuma sutunu saha formundaki haliyle.
export const TOHUM = 20260218, ABONE = 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; };
// Son alan: ziyaretin okuma uretmeme orani. Bolgeler bu oranda ayrisir.
export const BOLGE = [["kuzey", 0.28, 21, 0.06], ["guney", 0.22, 17, 0.03],
  ["dogu", 0.18, 26, 0.27], ["bati", 0.14, 14, 0.03], ["merkez", 0.18, 23, 0.08]]
  .map(([ad, pay, taban, eksik]) => ({ ad, pay, taban, eksik }));

const HARF = (j) => String.fromCharCode(65 + j);
export const formul = (yazi, f) => ({ tur: "formul", yazi, f });
export class Tablo {
  constructor(baslik, satirlar) {
    this.baslik = baslik; this.h = new Map(); this.n = satirlar.length;
    baslik.forEach((b, j) => this.h.set(`${HARF(j)}1`, b));
    satirlar.forEach((s, i) => baslik.forEach((b, j) =>
      this.h.set(`${HARF(j)}${i + 2}`, s[b])));
  }
  oku(ad) { const v = this.h.get(ad); return v && v.tur === "formul" ? v.f(this) : v; }
  yaz(ad, v) { this.h.set(ad, v); return this; }
  sutun(b) { const j = this.baslik.indexOf(b);
    return Array.from({ length: this.n }, (_, i) => this.oku(`${HARF(j)}${i + 2}`)); }
}
// Toplama ve ortalama islevleri bos hucreyi atlar: ortalama hem boluneni hem
// boleni yalnizca dolu hucrelerden alir. Sifir dolu bir hucredir.
export const sayilar = (a) => a.filter((v) => typeof v === "number");
export const topla = (a) => sayilar(a).reduce((x, y) => x + y, 0);
export const ortala = (a) => { const d = sayilar(a); return d.length ? topla(d) / d.length : 0; };

// Onceki dersin tekil sayfasi: abone basina bir ya da iki donem, abone+donem
// olcutuyle zaten tekillestirilmis. Ziyaret sonucu ayri bir uretec akisindan
// gelir; okumalar degismez. erisilemedi -> hucre bos. kapali -> gercek sifir
// tuketim. form_sifir -> okuma alinamamis ama forma sifir yazilmis.
export const SATIR = [];
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));
  for (const d of r() < 0.34 ? ["2026-01", "2026-02"] : ["2026-01"]) {
    const q = uretec(TOHUM + 7000 + SATIR.length), u = q();
    const durum = u < b.eksik ? (q() < 0.72 ? "erisilemedi" : "form_sifir")
      : u < b.eksik + 0.035 ? "kapali" : "okundu";
    const gercek = Math.round(taban * (d === "2026-02" ? 0.94 : 1) * 100) / 100;
    SATIR.push({ abone_no: 10001 + i, bolge: b.ad, donem: d, ziyaret_sonucu: durum,
      okuma_m3: durum === "erisilemedi" ? null : durum === "okundu" ? gercek : 0,
      gercek_m3: gercek });
  }
}
// Ayni sutun, dort dislama ve doldurma karari. Her karar hesaba giren satir
// kumesini ve bolen'i degistirir.
export const sutunOrt = ortala(SATIR.map((s) => s.okuma_m3));
export const KARAR = [
  ["D1 bos dislanir, sifir sayilir", (l) => sayilar(l.map((s) => s.okuma_m3))],
  ["D2 bos sifir sayilir", (l) => l.map((s) => s.okuma_m3 ?? 0)],
  ["D3 bos ve sifir dislanir", (l) => sayilar(l.map((s) => s.okuma_m3)).filter((v) => v > 0)],
  ["D4 bos sutun ortalamasiyla dolar", (l) => l.map((s) => s.okuma_m3 ?? sutunOrt)],
];
export const ESIK = 0.005; // raporlanan iki ondalik basamagin yarisi
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 = (d) => SATIR.filter((s) => s.ziyaret_sonucu === d);
  console.log(`model (tohum ${TOHUM}): ${SATIR.length} satir, raporlanan toplam ` +
    `${topla(SATIR.map((s) => s.gercek_m3)).toFixed(1)} m3; ${say("erisilemedi").length} hucre ` +
    `bos, ${say("kapali").length + say("form_sifir").length} hucre sifir yaziyor`);
  console.log(`sifirlarin ${say("kapali").length} tanesi gercek sifir tuketim, ` +
    `${say("form_sifir").length} tanesi okunmamis ziyaret; bos hucrelerin tasidigi ` +
    `${topla(say("erisilemedi").map((s) => s.gercek_m3)).toFixed(1)} m3 toplamin icinde ` +
    `ama hicbir okumaya dayanmiyor`);
  const y1 = y([34, 9, 11, 12]);
  console.log("\n" + y1(["ayni sutun, ayni soru, dort karar", "satir", "ortalama", "toplam m3"]));
  const o = {};
  for (const [ad, f] of KARAR) { const v = f(SATIR); o[ad.slice(0, 2)] = ortala(v);
    console.log(y1([ad, v.length, ortala(v).toFixed(2), topla(v).toFixed(1)])); }
  const [az, cok] = [Math.min(...Object.values(o)), Math.max(...Object.values(o))];
  console.log(`\nen dusuk ${az.toFixed(2)}, en yuksek ${cok.toFixed(2)}, aradaki fark ` +
    `${(cok - az).toFixed(2)} m3; D1 ile D4 ` +
    `${Math.abs(o.D1 - o.D4) < ESIK ? "ayni" : "farkli"} ortalamayi veriyor ` +
    `(esik ${ESIK} m3, raporlanan iki ondalik basamagin yarisi)`);
}
model (tohum 20260218): 1877 satir, raporlanan toplam 39147.7 m3; 116 hucre bos, 112 hucre sifir yaziyor
sifirlarin 57 tanesi gercek sifir tuketim, 55 tanesi okunmamis ziyaret; bos hucrelerin tasidigi 2719.2 m3 toplamin icinde ama hicbir okumaya dayanmiyor

ayni sutun, ayni soru, dort karar     satir   ortalama   toplam m3
D1 bos dislanir, sifir sayilir         1761      19.23     33866.8
D2 bos sifir sayilir                   1877      18.04     33866.8
D3 bos ve sifir dislanir               1649      20.54     33866.8
D4 bos sutun ortalamasiyla dolar       1877      19.23     36097.6

en dusuk 18.04, en yuksek 20.54, aradaki fark 2.49 m3; D1 ile D4 ayni ortalamayi veriyor (esik 0.005 m3, raporlanan iki ondalik basamagin yarisi)

Sayfa 1.877 satır, raporlanan toplam 39.147,7 m³; ikisi de bir önceki dersten. Yeni olan şu: 116 hücrede hiç okuma yoktur ve karşılıkları olan 2.719,2 m³ o toplamın içindedir. Sütunda 112 hücre sıfır yazar, ama yalnız 57’si gerçek sıfır tüketimdir; kalan 55’i okuma alınamamış bir ziyarettir. Sayfada ikisi arasında hiçbir fark yoktur: boş hücre kendini belli eder, sıfır yazılmış eksiklik kendini bir ölçüm gibi gösterir.

Dört kararın sayıları bunu doğruluyor. Ortalama 18,04 ile 20,54 arasında gider; aradaki 2,49 m³ düşük değerin yaklaşık yüzde 14’üdür. D1 sıfırları birer ölçüm sayar ve boşları dışlar; D2 boşları da sıfır sayar, bölen 1.761’den 1.877’ye çıkar, ortalama düşer; D3 hiçbir sıfıra güvenmez ve 1.649 satırla en yükseği verir. Toplam ilk üç kararda 33.866,8 m³’te sabittir: dışlama toplamı hiç oynatmaz, çünkü toplama işlevi boş hücreyi zaten atlıyordu.

Dördüncü satır bir önceki dersin beklediğini vermiyor: sütun ortalamasıyla doldurmak üçüncü bir ortalama üretmez, D1’in aynısını verir — ortalamaya eşit değer eklemek ortalamayı değiştirmez. Karşılaştırma 0,005 m³ eşiğiyle yapılır — sayı iki ondalık basamakla raporlanır ve kayan noktalı değerler eşitlik işleciyle karşılaştırılmaz. Asıl uyarı buradadır: doldurma ortalamayı korurken toplamı 36.097,6 m³’e çıkarır ve sayfaya 116 uydurma ölçüm ekler. Ortalamanın değişmemesi doldurmanın zararsız olduğunu değil, ortalamanın doldurmayı göstermediğini kanıtlar.

Doldurma Bittikten Sonra Ne Kalıyor

// doldurma.mjs — ayni sayfa, uc soru: doldurma karari bolge kirilimini ne kadar
// oynatiyor, doldurma sayfada iz birakiyor mu, karar sayfadan geri okunuyor mu.
import { SATIR, BOLGE, Tablo, formul, sayilar, ortala, sutunOrt, ESIK, y } from "./eksik.mjs";

// Eksiklik bolgelere esit dagilmadigi icin ayni karar her bolgeyi ayni kadar
// oynatmaz: en cok bos hucre tasiyan bolge en cok oynar.
const bolge = BOLGE.map((b) => {
  const l = SATIR.filter((s) => s.bolge === b.ad);
  return { ad: b.ad, d1: ortala(l.map((s) => s.okuma_m3)),
    d2: ortala(l.map((s) => s.okuma_m3 ?? 0)),
    oran: 100 * l.filter((s) => s.okuma_m3 === null).length / l.length };
}).sort((a, b) => b.oran - a.oran);
const [ust, alt] = [bolge[0], bolge[bolge.length - 1]];
console.log(`bos hucre orani ${alt.ad} bolgesinde yuzde ${alt.oran.toFixed(1)}, ${ust.ad} ` +
  `bolgesinde yuzde ${ust.oran.toFixed(1)}; bos hucreler sifir sayilirsa ${ust.ad} ` +
  `bolgesinin ortalamasi ${ust.d1.toFixed(2)} m3'ten ${ust.d2.toFixed(2)} m3'e iner, ` +
  `${alt.ad} bolgesininki ${alt.d1.toFixed(2)} m3'ten ${alt.d2.toFixed(2)} m3'e`);

// Doldurma sayfada iz birakir mi: doldurulan degeri tasiyan hucreler sayilir.
// Kayan noktali karsilastirma esikle yapilir; esik iki ondalik basamagin yarisi.
const bos = SATIR.filter((s) => s.okuma_m3 === null).length;
const izOrt = SATIR.filter((s) => Math.abs((s.okuma_m3 ?? sutunOrt) - sutunOrt) < ESIK).length;
const izSifir = SATIR.filter((s) => (s.okuma_m3 ?? 0) === 0).length;
console.log(`sutun ortalamasiyla doldurulan ${bos} hucre sayfada ${izOrt} hucrede goruluyor, ` +
  `tespit yuzde ${(100 * bos / izOrt).toFixed(0)}; ayni hucreler sifirla doldurulsaydi ` +
  `${izSifir} sifir hucre arasinda tespit yuzde ${(100 * bos / izSifir).toFixed(0)} olurdu`);

// Kararin kurtarilabilirligi: karar bir hucre formulunde yaziliysa bir adim,
// ayri bir not hucresinde duruyorsa iki adim, hicbir hucrede yoksa okunamaz.
const KOD = ["E1 hangi hucre bostu", "E2 doldurma yontemi", "E3 sifirin anlami",
  "E4 hesaba giren satir"];
const geriOku = (t) => KOD.map((k) => {
  const v = [...t.h.values()], n = k.slice(0, 2);
  const f = v.some((x) => x && x.tur === "formul" && x.yazi.includes(n));
  const not = v.some((x) => typeof x === "string" && x.startsWith("karar ") && x.includes(n));
  return f ? 1 : not ? 2 : null;
});
const dolgu = Math.round(sutunOrt * 100) / 100;
const BAS = ["abone_no", "bolge", "donem", "okuma_m3"];
const temiz = SATIR.map(({ abone_no, bolge, donem, okuma_m3 }) =>
  ({ abone_no, bolge, donem, okuma_m3: okuma_m3 ?? dolgu }));
const doldurulmus = new Tablo(BAS, temiz);
const notlu = new Tablo(BAS, temiz)
  .yaz("F1", "karar E2: bos hucreler sutun ortalamasiyla dolduruldu");
const izli = new Tablo([...BAS, "ziyaret_sonucu", "hesap_m3"], SATIR.map((s) => ({
  abone_no: s.abone_no, bolge: s.bolge, donem: s.donem, okuma_m3: s.okuma_m3,
  ziyaret_sonucu: s.ziyaret_sonucu,
  hesap_m3: formul("E1 ziyaret_sonucu erisilemedi ise okuma hucresi bostur; E2 bos hucre " +
    "sutun ortalamasiyla doldurulur; E3 sifir kapali sayacta gercek tuketim, form_sifir'da " +
    "okunmamis ziyarettir", () => s.okuma_m3 ?? dolgu) })));
izli.yaz("H2", formul("E4 hesaba giren satir dolu okuma hucrelerinden sayilir",
  (t) => sayilar(t.sutun("okuma_m3")).length));

const y3 = y([24, 18, 13, 11]);
console.log("\nkarar sayfadan geri okunabiliyor mu");
console.log(y3(["karar", "doldurulmus sayfa", "notlu sayfa", "izli sayfa"]));
const sonuc = [doldurulmus, notlu, izli].map(geriOku);
KOD.forEach((k, j) => console.log(y3([k,
  ...sonuc.map((s) => (s[j] ? `${s[j]} adim` : "okunamaz"))])));
console.log(["doldurulmus", "notlu", "izli"].map((ad, j) =>
  `${ad} ${sonuc[j].filter(Boolean).length}/${KOD.length}`).join(", ") +
  " karar geri okunabiliyor");
bos hucre orani bati bolgesinde yuzde 2.0, dogu bolgesinde yuzde 17.3; bos hucreler sifir sayilirsa dogu bolgesinin ortalamasi 22.80 m3'ten 18.86 m3'e iner, bati bolgesininki 13.62 m3'ten 13.35 m3'e
sutun ortalamasiyla doldurulan 116 hucre sayfada 116 hucrede goruluyor, tespit yuzde 100; ayni hucreler sifirla doldurulsaydi 228 sifir hucre arasinda tespit yuzde 51 olurdu

karar sayfadan geri okunabiliyor mu
karar                    doldurulmus sayfa  notlu sayfa izli sayfa
E1 hangi hucre bostu              okunamaz     okunamaz     1 adim
E2 doldurma yontemi               okunamaz       2 adim     1 adim
E3 sifirin anlami                 okunamaz     okunamaz     1 adim
E4 hesaba giren satir             okunamaz     okunamaz     1 adim
doldurulmus 0/4, notlu 1/4, izli 4/4 karar geri okunabiliyor

İlk satır eksikliğin nereye yığıldığını söylüyor: boş hücre oranı bati bölgesinde yüzde 2,0, dogu bölgesinde yüzde 17,3’tür; ölçüm ağı bir bölgede sistemli olarak çalışmıyor. Aynı karar bu yüzden her bölgeyi aynı kadar oynatmaz: boşlar sıfır sayıldığında dogu bölgesinin ortalaması 22,80’den 18,86’ya iner — 3,94 m³, tek bir ölçüm değişmeden — bati bölgesininki 0,27 m³ düşer. Sütun düzeyinde küçük görünen karar kırılımda büyür.

İkinci satır doldurmanın iz bırakıp bırakmadığını sayıyor. Sütun ortalamasıyla doldurulan 116 hücre tam olarak ayırt edilir, çünkü gerçek okumaların hiçbiri 19,23’e düşmez; aynı hücreler sıfırla doldurulsaydı 228 sıfır arasında tespit yüzde 51’e inerdi. Fark doldurma değerinin veride ne kadar seyrek geçtiğinden gelir, kararın yazılı olup olmadığından değil; bir tahmin, ne kadar isabetli olursa olsun, bir kayıt değildir.

Karar Nerede Duruyor

Son tablo dersin ikinci sayısıdır. Doldurulmuş sayfa 1.877 satırın hepsini dolu gösterir ve dört kararın sıfırını taşır. Bir önceki dersteki silinmiş sayfayla aynı sonuçtur, ama ondan kötüdür: silme satır sayısını düşürür ve bir şeyin eksildiği görülebilir, doldurma satır sayısını hiç oynatmaz.

Not düşülmüş sayfa dört karardan yalnız birini, doldurma yöntemini, iki adımda verir; yöntemi bilmek hangi hücrelere uygulandığını söylemez. Bir önceki derste not iki karar veriyordu, burada biri: elle tutulan not sayfaya bakılarak yazılır ve doldurma bitince sayfada görünmeyen şey tam olarak hangi hücrenin doldurulduğudur.

İzli sayfa ham okuma sütununu 116 boş hücresiyle bırakır, ziyaret sonucunu ayrı bir sütunda taşır ve hesabı bir formül sütununda üretir; dört karar da bir adımda okunur. Sayfa 1.761 dolu okumayı ve 1.877 satırlık hesabı aynı anda tutar; aradaki 116 fark artık bir eksiklik değil, yazılmış bir karardır. Bedeli iki fazladan sütundur: elektronik tablo bir hesap aracıdır, bir kayıt aracı değildir ve kayıt sütunla satın alınır.

Özet

  • Okuma sütununda 116 hücre boştur ve karşılıkları olan 2.719,2 m³ raporlanan 39.147,7 m³’ün içindedir.
  • Sıfır yazan 112 hücrenin 57’si gerçek sıfır tüketim, 55’i okunamamış ziyarettir ve sayfada ikisi ayırt edilemez.
  • Aynı sütunun ortalaması dört kararla 19,23, 18,04, 20,54 ve yine 19,23 m³ verir; toplam ilk üç kararda 33.866,8 m³’te sabit kalır, çünkü toplama işlevi boş hücreyi zaten atlar.
  • Doldurma ortalamayı 0,005 m³ eşiğinin altında değiştirmez ama toplamı 36.097,6 m³’e çıkarır; boş oranı yüzde 17,3 olan bölge sıfır sayımında 3,94 m³ düşer.
  • İşlem bitince dört karardan doldurulmuş sayfada sıfırı, not düşülmüş sayfada biri iki adımda, izli sayfada dördü bir adımda geri okunur.

Sonraki Adım

Bu iki ders sayfanın kendisini düzeltti; ikisinde de tek bir sütuna bakıldı. Rapor tek sütun istemez, kırılım ister. Özet tablo bu işi yapar ve kendi kararlarını taşır: hangi alan kırılım olacak, toplam mı ortalama mı alınacak, filtre özetten önce mi sonra mı uygulanacak, hesaplanan alan hangi düzeyde üretilecek. Sonraki ders aynı veriden üç kırılım kurar, üçünün üç farklı “birinci”yi verdiğini gösterir ve özetin kararlarının kaç adımda okunabildiğini sayar.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat