İçeriğe geç
academia.sh

Ders 15 / 17

Türetilmiş Değişkenler

3.199 satırlık kümeye iki türetilmiş değişken eklenir ve ikisi de satır sayısını değiştirmez; çıkan yine 3.199 satırdır. Kişi başı tüketim 328 satırda tanımsız kalır — 216 satırda hane sıfır, 112 satırda hane bilgisi hiç yok — ve iki sebep aynı sonuçta birleştiği için çıktıdan ayırt edilemez. Aynı soruya dört savunulabilir yol dört cevap verir: sayı olmayan değer, 9,972, 8,604 ve 7,735 m³. Tanımsız satırları süzen yol 6.372,0 m³'ü, yani toplam tüketimin yüzde 10,1'ini hesabın dışında bırakır ve süzgeç bölgelere eşit inmez: pay yüzde 5,4 ile yüzde 21,2 arasında değişir. Dönem değişim oranı uzun biçimde 1.334 satırda tanımsızdır, beklenen göz kümesinde ise 581 göz hiç sayılamaz.

İçindekiler

Toplulaştırma satır sayısını düşürdü ama sütun kümesine dokunmadı; elde yalnız ölçülmüş alanlar var. Çözümlemenin soruları ise çoğunlukla ölçülen değeri değil ondan türetilen bir büyüklüğü ister: “hangi bölge daha çok tüketiyor” sorusunun karşılığı ham metre küptür, “hangi bölgede kişi başına daha çok tüketiliyor” sorusunun karşılığı kümede bulunmaz.

Türetme, önceki üç adımın aksine satır sayısını hiç değiştirmez ve bu yüzden zararsız görünür. Dersin ölçüsü oradadır: satır sayısı sabit kalırken kaç satırda türetilmiş değerin tanımsız kaldığı. Tanımsız bir değer satırı düşürmez, yalnız onu sonraki adımda düşürülmeye hazır hale getirir; kayıp türetmede değil, ondan sonra yazılan ilk süzgeçte olur.

  • VD16. Türetilmiş değişken (derived variable), var olan alanlardan hesaplanan yeni bir alandır: satır sayısını değiştirmez, sütun ekler. Küme önceki dersten devralınır, kurgudur.
  • VD17. Bir türetme, girdilerinden biri eksik ya da sıfır olduğunda o satırda tanımsız kalır. Üç sebep ayrı sayılır: sıfıra bölme, eksik girdi ve tanım gereği tanımsızlık.
  • VD18. Eksik girdi aritmetikte sessizce sıfıra dönüşür; eksik girdi ile gerçek sıfır aynı sonucu üretir ve sebep yalnız girdiden okunur.
  • VD19. Tanımsız değer taşıyan satır düşmez, sonraki adımda süzülür; süzgeç türetmeden ayrı bir karardır ve raporunda görünmez.
  • VD20. Süzgeç rastgele elemez: tanımsızlığın sebebi bir gruba yığılıyorsa o grup orantısız elenir ve gruplar arası karşılaştırma bozulur.

Türetme Kaç Satırda Tanımsız Kalıyor

// turet.mjs — MODELDIR: onceki dersin 3.199 satirlik uzun bicimli kumesi ve iki
// turetilmis degisken. Veri kumesi kurgudur; hicbir arayuz taklit edilmez.
export const TOHUM = 20260218, HAM = 1400, DONEM = ["2026-01", "2026-02", "2026-03"];
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 = [["kuzey", 0.28, 21], ["guney", 0.22, 17], ["dogu", 0.18, 26],
  ["bati", 0.14, 14], ["merkez", 0.18, 23]];
// Hane buyuklugu bolgeye gore degisir; sifir kisi "hane yok" demektir (ticari
// abonelik) ve merkezde payi yuksektir. Cekim sayisi degismedigi icin onceki
// derslerin satir sayilari ve tuketim degerleri aynen korunur.
const HANE = { kuzey: [0.05, 0.22, 0.30, 0.25, 0.13, 0.05],
  guney: [0.04, 0.18, 0.26, 0.28, 0.16, 0.08], dogu: [0.02, 0.05, 0.12, 0.26, 0.33, 0.22],
  bati: [0.05, 0.42, 0.32, 0.14, 0.05, 0.02], merkez: [0.19, 0.26, 0.28, 0.17, 0.07, 0.03] };
const ABONE = [], ELENEN = [];
for (let i = 0; i < HAM; i++) {
  const r = uretec(TOHUM + i), b = BOLGE[ayrik(r(), BOLGE.map((x) => x[1]))];
  const k = { abone_no: 10001 + i, bolge: b[0], taban: b[2], hane_kisi: ayrik(r(), HANE[b[0]]),
    memnuniyet: ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17]) + 1 };
  (r() < 0.046 ? ELENEN : ABONE).push(k);
  if (r() < 0.031) k.hane_kisi = null; // hane bilgisi hic girilmemis kayit
}
// Onceki derslerin cikardigi kume: eslesmeyen okumalar disarida, ayni abone+donem
// cifti bir satir. Elenen abonelerin ve tekillestirilen ikinci kaydin cekimleri
// korunuyor ki tuketim degerleri onceki derslerle ayni kalsin.
const anahtar = new Set(ABONE.map((a) => a.abone_no));
const HANE_KISI = new Map(ABONE.map((a) => [a.abone_no, a.hane_kisi]));
export const UZUN = [];
for (const k of [...ABONE, ...ELENEN]) {
  const r = uretec(TOHUM + 7000 + k.abone_no), adet = ayrik(r(), [0.05, 0.12, 0.21, 0.62]);
  for (let d = 0; d < adet; d++) {
    const t = r() < 0.038 ? 0 : Math.round(k.taban * Math.exp((r() + r() + r() - 1.5) * 0.62)
      * (1 - d * 0.05) * 100) / 100;
    if (!anahtar.has(k.abone_no)) { r(); continue; }
    UZUN.push({ abone_no: k.abone_no, bolge: k.bolge, donem: DONEM[d], tuketim_m3: t,
      hane_kisi: HANE_KISI.get(k.abone_no) });
    r();
  }
}

const deger = new Map(UZUN.map((o) => [`${o.abone_no}|${o.donem}`, o.tuketim_m3]));
const onceki = (o) => { const j = DONEM.indexOf(o.donem);
  return j === 0 ? undefined : deger.get(`${o.abone_no}|${DONEM[j - 1]}`); };
// Iki turetme, her biri bir deger ve bir tanimsizlik sebebi verir. Sebep ciktidan
// degil girdiden okunur; ayni tanimsiz deger farkli sebeplerden gelebilir.
export const TURETME = [
  ["T1 kisi basi tuketim", (o) => o.tuketim_m3 / o.hane_kisi,
    (o) => o.hane_kisi === null ? "eksik" : o.hane_kisi === 0 ? "sifir" : "-"],
  ["T2 donem degisim orani", (o) => (o.tuketim_m3 - onceki(o)) / onceki(o),
    (o) => DONEM.indexOf(o.donem) === 0 ? "tanim" : onceki(o) === undefined ? "eksik"
      : onceki(o) === 0 ? "sifir" : "-"],
];
export const ort = (a) => a.reduce((x, y) => x + y, 0) / a.length;
export const gen = (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) => UZUN.filter(f).length, T = UZUN.reduce((a, o) => a + o.tuketim_m3, 0);
  console.log(`model (tohum ${TOHUM}): giren ${UZUN.length} satir, ${T.toFixed(1)} m3, ` +
    `ortalama ${(T / UZUN.length).toFixed(3)} m3 — onceki ders ile ayni`);
  const y = gen([25, 8, 8, 11, 13, 13, 14]);
  console.log("\n" + y(["turetme", "giren", "cikan", "tanimsiz", "sifira bolme",
    "eksik girdi", "tanim geregi"]));
  for (const [ad, f, neden] of TURETME) {
    const n = UZUN.map(neden);
    console.log(y([ad, UZUN.length, UZUN.length, say((o) => !Number.isFinite(f(o))),
      n.filter((x) => x === "sifir").length, n.filter((x) => x === "eksik").length,
      n.filter((x) => x === "tanim").length]));
  }
  const t1 = UZUN.map(TURETME[0][1]);
  console.log(`\niki turetme de cikan satiri degistirmedi ve hata uretmedi; T1'in eksik girdisi ` +
    `ile sifir hanesi ayni sonucta birlesti: ${t1.filter((x) => x === Infinity).length} sonsuz, ` +
    `${t1.filter((x) => Number.isNaN(x)).length} sayi olmayan deger`);
  // T2'nin "eksik girdi" sutunu sifir cikti; beklenen goz kumesi kurulunca degisiyor.
  const goz = new Set(UZUN.map((o) => o.abone_no)).size * (DONEM.length - 1);
  const tanimli = say((o) => Number.isFinite(TURETME[1][1](o)));
  const bol = say((o) => TURETME[1][2](o) === "sifir");
  console.log(`\nT2 beklenen goz kumesinde: ${goz} goz, ${tanimli} tanimli, ${bol} sifira ` +
    `bolme, ${goz - tanimli - bol} goz hic okunmamis donem yuzunden — uzun bicimde o gozler ` +
    `hic satir olmadigi icin tanimsiz da sayilmadi`);
}
model (tohum 20260218): giren 3199 satir, 63060.6 m3, ortalama 19.713 m3 — onceki ders ile ayni

turetme                     giren   cikan   tanimsiz sifira bolme  eksik girdi  tanim geregi
T1 kisi basi tuketim         3199    3199        328          216          112             0
T2 donem degisim orani       3199    3199       1334           74            0          1260

iki turetme de cikan satiri degistirmedi ve hata uretmedi; T1'in eksik girdisi ile sifir hanesi ayni sonucta birlesti: 315 sonsuz, 13 sayi olmayan deger

T2 beklenen goz kumesinde: 2520 goz, 1865 tanimli, 74 sifira bolme, 581 goz hic okunmamis donem yuzunden — uzun bicimde o gozler hic satir olmadigi icin tanimsiz da sayilmadi

Giren ve çıkan sütunları iki satırda da aynı: 3.199. Birleştirme satır düşürüp çoğaltmış, şekillendirme satırı hücreye çevirmiş, toplulaştırma 3.199 satırı beşe indirmişti; türetme hiçbirini yapmaz. Yine de tanımsız sütununda iki ayrı sayı var.

T1 satırında 3.199 satırın 328’inde kişi başı tüketim tanımsızdır ve sebep iki kalemdir. 216 satırda hane kişi sayısı sıfırdır; bu bir veri hatası değildir, çünkü hane olmayan bir abonelik için kişi başı tüketim diye bir büyüklük yoktur. 112 satırda hane bilgisi hiç girilmemiştir; bu bir eksikliktir ve doldurulabilir. İki kalem farklı kararlar gerektirir ama çıktıda aynı görünür: eksik girdi sessizce sıfıra çevrilir, sıfıra bölme sonsuz verir ve ikisi de aynı 315 sonsuz değerin içinde erir; kalan 13 tanımsız, tüketimi de sıfır olan satırlardan gelir. Bir tanımsız değerin türü sebebini vermez, bu yüzden tanımsızlık sayısı sebebiyle birlikte raporlanır.

T2 başka bir kalemi gösteriyor. Tanımsız sayısı 1.334 ile daha büyüktür ama bunun 1.260’ı tanım gereğidir: ilk dönemin bir öncesi yoktur, dolayısıyla değişim oranı da yoktur. Bu bir kayıp değil, tanımın sonucudur. Kalan 74 satır bir sıfıra bölmedir.

Asıl uyarı T2 satırının eksik girdi sütunundaki sıfırdır. O sıfır, veride boşluk olmadığını değil, uzun biçimde sorulan sorunun boşluğu göremediğini söyler. Beklenen göz kümesinde 1.260 abone için iki geçiş, toplam 2.520 göz vardır ve yalnız 1.865’i tanımlıdır. 581 göz hiç okunmamış bir dönem yüzünden tanımsızdır; bu, önceki dersteki 581 boş hücredir ve uzun biçimde ortada satır olmadığından tanımsız bile sayılamaz. Var olmayan satırın türetilmiş değeri de var olmaz.

Tanımsızın Bedelini Sonraki Adım Ödüyor

// etki.mjs — tanimsiz satirlarin sonuca etkisi: ayni soru dort yolla cevaplanir ve
// suzgecin kac satiri hangi bolgeden sessizce dusurdugu bolge bolge sayilir.
import { UZUN, ort, gen } from "./turet.mjs";

const kisiBasi = (o) => o.tuketim_m3 / o.hane_kisi;
const sonlu = UZUN.filter((o) => Number.isFinite(kisiBasi(o)));
const T = (a, f) => a.reduce((x, o) => x + f(o), 0);
const oranT = (a, p) => T(a, (o) => o.tuketim_m3) / T(a, p);
const YOL = [
  ["Y1 satir oranlari ortalanir", UZUN, (a) => ort(a.map(kisiBasi))],
  ["Y2 sonlu satirlar suzulur", sonlu, (a) => ort(a.map(kisiBasi))],
  ["Y3 toplam m3 / toplam kisi", UZUN, (a) => oranT(a, (o) => o.hane_kisi ?? 0)],
  ["Y4 suzulmus toplam / toplam", sonlu, (a) => oranT(a, (o) => o.hane_kisi)],
];
const y = gen([37, 9, 10, 11, 11]);
console.log(`soru: bir kisi bir donemde ortalama kac m3 tuketiyor`);
console.log("\n" + y(["cevap yolu", "giren", "sayilan", "tanimsiz", "sonuc"]));
for (const [ad, a, f] of YOL) console.log(y([ad, UZUN.length, a.length,
  a.filter((o) => !Number.isFinite(kisiBasi(o))).length, f(a).toFixed(3)]));
console.log(`\nY3 tanimsiz ${UZUN.length - sonlu.length} satirin tuketimini paya ekledi, ` +
  `paydaya sifir kisi ekledi; hicbir uyari uretmedi`);

// Suzgec rastgele elemez: dusen satirlar bolgelere esit dagilmaz.
const satir = [...new Set(UZUN.map((o) => o.bolge))].map((b) => {
  const l = UZUN.filter((o) => o.bolge === b), s = l.filter((o) => Number.isFinite(kisiBasi(o)));
  return { bolge: b, n: l.length, dusen: l.length - s.length,
    ham: ort(l.map((o) => o.tuketim_m3)), kb: ort(s.map(kisiBasi)) };
}).sort((a, b) => b.ham - a.ham);
const yer = (f) => Object.fromEntries([...satir].sort((a, b) => f(b) - f(a))
  .map((s, j) => [s.bolge, j + 1]));
const sHam = yer((x) => x.ham), sKb = yer((x) => x.kb);
const y2 = gen([9, 8, 9, 9, 10, 10, 9, 9]);
console.log("\n" + y2(["bolge", "okuma", "dusen", "pay %", "ham ort.", "kisi basi",
  "sira ham", "sira kb"]));
for (const s of satir) console.log(y2([s.bolge, s.n, s.dusen, (100 * s.dusen / s.n).toFixed(1),
  s.ham.toFixed(2), s.kb.toFixed(2), sHam[s.bolge], sKb[s.bolge]]));

const m3 = T(UZUN.filter((o) => !Number.isFinite(kisiBasi(o))), (o) => o.tuketim_m3);
const pay = satir.map((s) => 100 * s.dusen / s.n);
console.log(`\ngiren ${UZUN.length} satir -> cikan ${UZUN.length} satir; suzgec ` +
  `${UZUN.length - sonlu.length} satiri ve ${m3.toFixed(1)} m3 dusurdu, yani toplamin yuzde ` +
  `${(100 * m3 / T(UZUN, (o) => o.tuketim_m3)).toFixed(1)}'ini; bolgeye gore pay ` +
  `${Math.min(...pay).toFixed(1)} ile ${Math.max(...pay).toFixed(1)} arasinda degisiyor`);
console.log(`${satir.filter((s) => sHam[s.bolge] !== sKb[s.bolge]).length} bolgenin sirasi ` +
  `degisti; kisi basi tuketimin birincisi ${satir.find((s) => sKb[s.bolge] === 1).bolge}`);
soru: bir kisi bir donemde ortalama kac m3 tuketiyor

cevap yolu                               giren   sayilan   tanimsiz      sonuc
Y1 satir oranlari ortalanir               3199      3199        328        NaN
Y2 sonlu satirlar suzulur                 3199      2871          0      9.972
Y3 toplam m3 / toplam kisi                3199      3199        328      8.604
Y4 suzulmus toplam / toplam               3199      2871          0      7.735

Y3 tanimsiz 328 satirin tuketimini paya ekledi, paydaya sifir kisi ekledi; hicbir uyari uretmedi

bolge       okuma    dusen    pay %  ham ort. kisi basi sira ham  sira kb
dogu          557       30      5.4     24.67      8.43        1        4
merkez        600      127     21.2     22.40     14.00        2        1
kuzey         921       52      5.6     20.21     10.67        3        2
guney         645       61      9.5     16.60      7.50        4        5
bati          476       58     12.2     13.78      9.37        5        3

giren 3199 satir -> cikan 3199 satir; suzgec 328 satiri ve 6372.0 m3 dusurdu, yani toplamin yuzde 10.1'ini; bolgeye gore pay 5.4 ile 21.2 arasinda degisiyor
5 bolgenin sirasi degisti; kisi basi tuketimin birincisi merkez

Dört yol da aynı soruyu soruyor ve dördü de savunulabilir. Y1 hiçbir şey süzmez ve tek görünür işareti üretir: sonuç bir sayı değildir. Tanımsızlığın rapora ulaştığı tek yol budur ama bir cevap değildir, bu yüzden en kısa düzeltme eklenir.

Y2 o düzeltmedir ve 9,972 m³ verir. Süzgeç bir satır bile düşürmüyormuş gibi yazılır, oysa sayılan satır 3.199 değil 2.871’dir ve düşen 328 satır 6.372,0 m³, yani toplam tüketimin yüzde 10,1’ini taşır. Rapor “kişi başına 9,972 m³” der; hangi 328 satırın sayılmadığını yazmaz.

Y3 bu dersin sessiz kaybıdır. Toplam tüketimi toplam hane kişisine bölmek makul bir yoldur, hiçbir tanımsız değer üretmez ve sonuç 8,604 m³ olarak temiz çıkar. Tanımsız 328 satır burada süzülmemiştir: tüketimleri paya girmiş, hane kişileri paydaya sıfır olarak girmiştir. Farkı gösteren tek şey Y4’tür: aynı hesap sonlu satırlarda 7,735 m³ verir ve aradaki 0,869 m³ tamamen o sıfır paydalardan gelir.

Y2 ile Y4 arasındaki fark ise önceki derste kurulmuş bir ağırlık kararıdır: 9,972 m³ oranların ortalaması, 7,735 m³ ortalamaların oranıdır.

Alt tablo süzgecin neden bir hesap kalemi olduğunu gösteriyor. Düşen 328 satır bölgelere eşit dağılmıyor: dogu bölgesinin okumalarının yüzde 5,4’ü düşerken merkez bölgesinin yüzde 21,2’si düşüyor. Sebep verinin kendisidir: hane olmayan abonelikler merkezde yoğunlaşmıştır. Bölgeleri karşılaştıran biri, her bölgenin farklı bir payla temsil edildiğini bilmez. Son satır ise türetmenin gücünü ve riskini birlikte veriyor: beş bölgenin beşi de sıra değiştirdi ve ham tüketimde birinci olan dogu kişi başı tüketimde dördüncü olur. İki sıralama da doğrudur; riskli olan, ikisinin de “tüketim” adını taşımasıdır.

Dersin satır hesabı böyle kapanır: 3.199 satır girdi, 3.199 satır çıktı, türetmede hiçbir satır düşmedi. Buna karşılık 328 satır kişi başı tüketimde, 1.334 satır dönem değişim oranında tanımsız bir değer taşıyor ve sonraki adımın süzgecinde sessizce düşecek. Tanımsız sayısı yazılmadığında bu düşüş görünmez, çünkü türetmenin raporunda giren ile çıkan eşittir.

Özet

  • Türetme satır sayısını değiştirmez: 3.199 satır girdi, 3.199 satır çıktı ve hata üretilmedi. Değişen şey, satırların taşıdığı tanımsız değer sayısıdır.
  • Tanımsızlık sebebine göre ayrılır: kişi başı tüketimde 216 satır sıfıra bölme, 112 satır eksik girdi; dönem değişim oranındaki 1.334 satırın 1.260’ı tanım gereğidir.
  • Eksik girdi aritmetikte sessizce sıfıra dönüşür ve 112 eksik ile 216 sıfır aynı 315 sonsuz değerde erir. Uzun biçim ise 581 gözü hiç göremez.
  • Aynı soru dört savunulabilir yolla dört cevap verir: sayı olmayan değer, 9,972, 8,604 ve 7,735 m³. Süzen yol 6.372,0 m³’ü, yani toplamın yüzde 10,1’ini hesabın dışında bırakır.
  • Süzgeç rastgele elemez: bölgelere göre pay yüzde 5,4 ile yüzde 21,2 arasında değişir ve türetilmiş değişken beş bölgenin de sırasını değiştirir.

Sonraki Adım

Türetme sayısal alanlardan sayısal alanlar üretti. Kümede sayısallaştırılmayı bekleyen alanlar daha var ve orada sayı hiç yok: bölge bir addır, ziyaret sonucu bir etikettir, memnuniyet basamağı bir nottur. Çözümlemenin çoğu aracı sayı ister, bu yüzden kategoriler kodlanır ve kodlama mekanik görünür — her kategoriye bir tam sayı verilir ve iş biter. Bedeli, verilen sayının kendi getirdiği anlamdır: sıralı bir kod, kategoriler arasında sıra ve uzaklık iddia eder ve bölgeye 1’den 5’e kod verildiğinde bu iddia veriye hiç sorulmadan girer. Sonraki ders sıralı ve sırasız kodlamayı ayırır ve sırasız bir kategoriyi sıralı kodlamanın ürettiği yanlış sonucu sayıyla gösterir.

İ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