Ders 09 / 17
Aykırı Değerler
Devralınan 1.880 okumada çeyrekler açıklığı 64 satır, standart puan 14 satır işaretler; ikinci küme birincinin alt kümesidir ve örtüşmeyen kısım 50 satırdır. Fark yöntemlerin duyarlılığından değil, standart puanın kendi aykırısını gizlemesinden gelir: 1.880 satırda standart sapma 19,68 m³'tür, işaretli 64 satır ayrıldığında 6,35 m³'e iner ve aynı üç sigma ölçütü bu kez sıfır satır işaretler. Modelde ondalık noktası kaymış 15 okumanın 15'ini çeyrekler açıklığı, 14'ünü standart puan yakalar. İşaretlileri ayırmak ortalamayı 22,22 m³'ten 20,14 m³'e (2,08 m³, yüzde 9,4), medyanı 20,31'den 19,85'e, toplamı 41.774,8 m³'ten 36.578,3 m³'e çeker. Adım 1.880 satırla girip 1.816 satırla çıkar.
İçindekiler
Bir önceki ders bütün alanları doğru tipe çevirdi ve 1.880 okumanın hepsi artık bir sayıdır. Sayı olmak doğru olmak değildir: bir bölüm okuma forma ondalık noktası kayarak on kat büyük yazılmıştır ve dönüşüm bunları sadakatle çevirmiştir. Bu değerler kümede uç noktalarda durur, hiçbir kural ihlal etmez ve yalnız komşularına göre tuhaftır.
Bu ders o uçları iki yöntemle tarar. Çeyrekler açıklığı sıralamaya dayanır ve açıklığın bir katsayısı kadar dışarıya çit çeker; standart puan ortalamaya ve standart sapmaya dayanır. İkisi de aynı soruyu sorar ve farklı sayılar verir. Dersin sayısı bu iki kümenin örtüşmeyen kısmı ve işaretlenenleri ayırmanın raporlanan sayıyı ne kadar oynattığıdır.
- VZ13. Küme önceki iki dersten devralınır: 188 satır birleşmiş, biçim farkında dönüşümle
okuma alanı sıfır kayıpla sayıya çevrilmiştir. Küme
nodeile modellenir ve kurgudur. - VZ14. Çeyrekler açıklığı ’dir; çitler ve noktalarında durur. Katsayı bir karardır, veriden çıkmaz.
- VZ15. Standart puan ’dır. İki girdisi de — ortalama ve standart sapma — işaretlenecek değerlerden hesaplanır; ölçüt kendi aradığı şeyden etkilenir.
- VZ16. Aykırı işareti bir silme kararı değildir. Bu derste işaretlenen satırlar ayrı bir deftere geçer; kümeden çıkarlar ama yok olmazlar ve sayıları yazılır.
İki Yöntem, İki Küme
// aykiri.mjs — ayni ham kume MODELIDIR. Kume kurgudur: bolgesel olcum aginin // 1400 abonesi ve saha ziyaret kayitlari; ayni tohum, ayni satirlar. Onceki // dersin dogru donusumu uygulanir ve okuma alani sayiya cevrilir. 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 }; // adres alanlari ders 06'da kullanilir 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; // Adres alani bu derste kullanilmiyor; yalniz yazim bicimi saklanir. const av = ayrik(q(), [0.30, 0.18, 0.18, 0.16, 0.18]); 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_bicim: av, 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_bicim: av === 2 ? 4 : 2, 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(""); // Onceki dersin karari: kimlik alani bos olan satirlar elendi, eksik okumali // satirlar isaretlenip bolge ortancasiyla dolduruldu. Bu adima 2068 satir girer. const kimlikli = HAM.filter((s) => s.sayac_no.trim() !== ""); 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)))])); export const GIREN = kimlikli.map((s) => sayiya(s.okuma_metni) === null ? { ...s, okuma_metni: bolgeMed.get(s.bolge).toFixed(2) } : s); // Onceki iki dersin karari: tekillestirme (188 satir birlesti) ve bicim // farkinda donusum (0 kayip, 0 bozuk kayit). Bu adima 1880 satir girer. const tekille = (l, k) => { const m = new Map(); for (const s of l) if (!m.has(k(s))) m.set(k(s), s); return [...m.values()]; }; export const OKUMA = tekille(GIREN, (s) => `${s.abone_no}|${s.donem}|${s.sayac_no.trim().toUpperCase()}`) .map((s) => ({ ...s, okuma_m3: Number(s.okuma_metni.trim().replace(",", ".")) })); export const ESIK = 0.005; // raporlanan iki ondalik basamagin yarisi export const topla = (a) => a.reduce((x, z) => x + z, 0); export const ortalama = (a) => topla(a) / a.length; // Ceyrek, siralanmis dizide dogrusal ara deger ile hesaplanir. export const ceyrek = (a, p) => { const l = [...a].sort((x, z) => x - z); const h = (l.length - 1) * p, i = Math.floor(h); return l[i] + (h - i) * (l[Math.min(i + 1, l.length - 1)] - l[i]); }; export const sapma = (a) => { const m = ortalama(a); return Math.sqrt(ortalama(a.map((v) => (v - m) ** 2))); }; if (import.meta.url === `file://${process.argv[1]}`) { const d = OKUMA.map((s) => s.okuma_m3); const q1 = ceyrek(d, 0.25), q3 = ceyrek(d, 0.75), ca = q3 - q1; const alt = q1 - 1.5 * ca, ust = q3 + 1.5 * ca; const m = ortalama(d), sd = sapma(d); console.log(`model (tohum ${TOHUM}): onceki adimdan devralinan kume ${OKUMA.length} satir; ` + `ortalama ${m.toFixed(2)} m3, standart sapma ${sd.toFixed(2)} m3`); console.log(`ceyrekler: Q1 ${q1.toFixed(2)}, Q3 ${q3.toFixed(2)}, ` + `ceyrekler acikligi ${ca.toFixed(2)}; citler ${alt.toFixed(2)} ve ${ust.toFixed(2)} m3`); // Iki yontem, iki isaretli kume. A: ceyrekler acikligi. B: standart puan. const A = new Set(), B = new Set(); d.forEach((v, i) => { if (v < alt || v > ust) A.add(i); if (Math.abs((v - m) / sd) > 3) B.add(i); }); const kesisim = [...A].filter((i) => B.has(i)).length; const y1 = y([34, 11, 10, 12]); console.log("\n" + y1(["yontem", "isaretli", "kesisim", "yalniz bu"])); console.log(y1(["A ceyrekler acikligi (1.5 kat)", A.size, kesisim, A.size - kesisim])); console.log(y1(["B standart puan (3 sigma)", B.size, kesisim, B.size - kesisim])); console.log(`iki kumenin ortusmeyen kismi ${A.size + B.size - 2 * kesisim} satir; ` + `B kumesi A'nin alt kumesidir`); // Modelde ondalik noktasi kayarak on kat buyuk yazilan okumalar isaretli. const kayan = OKUMA.map((s, i) => [s, i]) .filter(([s]) => s.yazilan_m3 !== null && Math.abs(s.yazilan_m3 - s.gercek_m3) > ESIK); console.log(`\nmodelde ondalik kaymasi olan ${kayan.length} okuma var; ` + `A ${kayan.filter(([, i]) => A.has(i)).length} tanesini, ` + `B ${kayan.filter(([, i]) => B.has(i)).length} tanesini isaretliyor`); }
model (tohum 20260305): onceki adimdan devralinan kume 1880 satir; ortalama 22.22 m3, standart sapma 19.68 m3 ceyrekler: Q1 15.38, Q3 24.59, ceyrekler acikligi 9.21; citler 1.55 ve 38.41 m3 yontem isaretli kesisim yalniz bu A ceyrekler acikligi (1.5 kat) 64 14 50 B standart puan (3 sigma) 14 14 0 iki kumenin ortusmeyen kismi 50 satir; B kumesi A'nin alt kumesidir modelde ondalik kaymasi olan 15 okuma var; A 15 tanesini, B 14 tanesini isaretliyor
Aynı kümede iki yöntem 64 ve 14 satır işaretledi. İkinci küme birincinin alt kümesidir: kesişim 14, örtüşmeyen kısım 50 satırdır ve bu 50 satırın hepsi yalnız çeyrekler açıklığı tarafından görülür. Ölçütlerden biri diğerinin gördüğünün beşte birini görüyor.
Fark duyarlılık ayarından gelmiyor. Aykırı değerler çeyrekleri neredeyse hiç oynatmaz, çünkü sıralamada bir uçtan bir uca gitseler bile çeyreğin yerini değiştirmezler. Standart puanın iki girdisi ise doğrudan o değerlerden hesaplanır — 19,68 m³’lük standart sapmanın kendisi, on kat büyük yazılmış okumaların ürünüdür. Ölçüt aradığı şeyi kendi tabanına katmıştır. Son satır bunu ölçüyor: ondalık noktası kaymış 15 okumanın 15’ini çeyrekler açıklığı, 14’ünü standart puan yakalar.
Eşik Değişince
// esik.mjs — ayni kume, iki soru: esik degisince her yontem kac satir // isaretliyor ve isaretlenenleri ayirmak raporlanan sayiyi ne kadar oynatiyor. import { OKUMA, ceyrek, ortalama, sapma, topla, y } from "./aykiri.mjs"; const d = OKUMA.map((s) => s.okuma_m3); const medyan = (a) => ceyrek(a, 0.5); const caIsaret = (a, k) => { const q1 = ceyrek(a, 0.25), q3 = ceyrek(a, 0.75); const g = q3 - q1; return a.map((v, i) => [v, i]) .filter(([v]) => v < q1 - k * g || v > q3 + k * g).map(([, i]) => i); }; const spIsaret = (a, k) => { const m = ortalama(a), s = sapma(a); return a.map((v, i) => [v, i]).filter(([v]) => Math.abs((v - m) / s) > k).map(([, i]) => i); }; const y1 = y([24, 8, 11, 12, 13, 11]); console.log(y1(["yontem", "esik", "isaretli", "kalan satir", "ortalama m3", "medyan m3"])); for (const [ad, f, k] of [["ceyrekler acikligi", caIsaret, 1.5], ["ceyrekler acikligi", caIsaret, 3.0], ["standart puan", spIsaret, 2.0], ["standart puan", spIsaret, 2.5], ["standart puan", spIsaret, 3.0]]) { const isaret = new Set(f(d, k)), kalan = d.filter((_, i) => !isaret.has(i)); console.log(y1([ad, k.toFixed(1), isaret.size, kalan.length, ortalama(kalan).toFixed(2), medyan(kalan).toFixed(2)])); } console.log(`\nham kumede ortalama ${ortalama(d).toFixed(2)} m3, medyan ` + `${medyan(d).toFixed(2)} m3; iki yontemin en genis ve en dar isaretlemesi arasinda ` + `${caIsaret(d, 1.5).length - spIsaret(d, 3.0).length} satir fark var`); // Standart puan kendi aykirisini gizler: sapma isaretlenecek degerlerden hesaplanir. const A = new Set(caIsaret(d, 1.5)), temiz = d.filter((_, i) => !A.has(i)); console.log(`\naykirilar sapmayi kendileri buyutuyor: ${d.length} satirda standart sapma ` + `${sapma(d).toFixed(2)} m3; A kumesi ayrilinca ${temiz.length} satirda ` + `${sapma(temiz).toFixed(2)} m3'e iner ve ayni 3 sigma olcutu bu kez ` + `${spIsaret(temiz, 3.0).length} satir isaretler`); // Ayirmanin raporlanan sayiya etkisi. const kalanKayit = OKUMA.filter((_, i) => !A.has(i)); console.log(`ayirma ortalamayi ${ortalama(d).toFixed(2)} m3'ten ` + `${ortalama(temiz).toFixed(2)} m3'e cekiyor (${(ortalama(d) - ortalama(temiz)).toFixed(2)} m3, ` + `yuzde ${(100 * (ortalama(d) - ortalama(temiz)) / ortalama(d)).toFixed(1)}), medyani ` + `${medyan(d).toFixed(2)}'den ${medyan(temiz).toFixed(2)}'e; toplam ` + `${topla(d).toFixed(1)} m3'ten ${topla(temiz).toFixed(1)} m3'e iniyor`); console.log(`\nsatir hesabi: giren ${OKUMA.length}, cikan ${kalanKayit.length}; ` + `${A.size} satir incelenecekler kumesine ayrildi (silinmedi, ayri bir defterde durur), ` + `0 satir sessizce dustu`);
yontem esik isaretli kalan satir ortalama m3 medyan m3 ceyrekler acikligi 1.5 64 1816 20.14 19.85 ceyrekler acikligi 3.0 18 1862 20.71 20.30 standart puan 2.0 15 1865 20.76 20.31 standart puan 2.5 14 1866 20.78 20.31 standart puan 3.0 14 1866 20.78 20.31 ham kumede ortalama 22.22 m3, medyan 20.31 m3; iki yontemin en genis ve en dar isaretlemesi arasinda 50 satir fark var aykirilar sapmayi kendileri buyutuyor: 1880 satirda standart sapma 19.68 m3; A kumesi ayrilinca 1816 satirda 6.35 m3'e iner ve ayni 3 sigma olcutu bu kez 0 satir isaretler ayirma ortalamayi 22.22 m3'ten 20.14 m3'e cekiyor (2.08 m3, yuzde 9.4), medyani 20.31'den 19.85'e; toplam 41774.8 m3'ten 36578.3 m3'e iniyor satir hesabi: giren 1880, cikan 1816; 64 satir incelenecekler kumesine ayrildi (silinmedi, ayri bir defterde durur), 0 satir sessizce dustu
Tablo eşiğin bir karar olduğunu ve iki yöntemin buna farklı tepki verdiğini gösteriyor. Çeyrekler açıklığında katsayıyı 1,5’ten 3,0’a çıkarmak işaretli satırı 64’ten 18’e indirir. Standart puanda eşiği 2,0’dan 3,0’a çekmek 15’ten 14’e indirir: bir satır. Ölçüt eşiğe tepki vermiyor, çünkü paydası o kadar büyümüştür ki hiçbir makul eşik onu bölemez.
İkinci blok bunu doğrudan ölçüyor. Standart sapma ham kümede 19,68 m³, işaretli 64 satır ayrıldığında 6,35 m³’tür ve aynı üç sigma ölçütü bu kez sıfır satır işaretler. Ölçüt kendi işini yaptıktan sonra kendini gereksiz kılar; standart puan tek geçişte kullanıldığı her yerde eksik sayar.
Ayırmanın bedeli son satırdadır. Ortalama 22,22 m³’ten 20,14 m³‘e iner: 2,08 m³, yüzde 9,4. Medyan yalnız 0,46 m³ oynar — 20,31’den 19,85’e — çünkü medyan zaten sıralamaya dayanır. Toplam ise 41.774,8’den 36.578,3 m³’e, yüzde 12,4 iner. Aynı 64 satır medyanı yüzde 2,3, ortalamayı yüzde 9,4, toplamı yüzde 12,4 oynatır; hangi sayının raporlandığı da bir karardır.
Adımın hesabı şudur: giren 1.880 satır, çıkan 1.816 satır. Aradaki 64 satır incelenecekler defterine ayrıldı — silinmedi, sayıldı ve yazıldı — sessizce düşen satır yoktur. Ayrılanların hepsi hatalı değildir; bir bölümü gerçekten yüksek tüketimdir ve ayrı deftere geçmeleri bunu soruşturulabilir kılar.
Özet
- Aynı 1.880 satırlık kümede çeyrekler açıklığı 64, standart puan 14 satır işaretler; ikinci küme birincinin alt kümesidir ve örtüşmeyen kısım 50 satırdır.
- Standart puanın iki girdisi de işaretlenecek değerlerden hesaplanır ve ölçüt kendi aradığı şeyle körelir: standart sapma ham kümede 19,68 m³, işaretliler ayrıldıktan sonra 6,35 m³’tür ve aynı üç sigma ölçütü bu kez sıfır satır işaretler.
- Modelde ondalık noktası kaymış 15 okumanın 15’ini çeyrekler açıklığı, 14’ünü standart puan yakalar.
- Ayırma ortalamayı 22,22’den 20,14 m³’e (yüzde 9,4), medyanı 20,31’den 19,85’e, toplamı 41.774,8’den 36.578,3 m³’e çeker.
- Adımın hesabı: giren 1.880, çıkan 1.816; 64 satır incelenecekler defterine ayrıldı, 0 sessizce düştü.
Sonraki Adım
Sayısal alanlar artık tarandı ve uçları yazılı. Kümede hiç bakılmamış bir alan daha var: tarife sınıfı. O alan bir sayı değil, elle yazılmış bir metindir ve aynı sınıf birden çok biçimde yazılmıştır. Sonraki ders yazımları sayar, birleştirme adımlarını sırayla uygular, her adımdan sonra kaç kategori kaldığını yazar ve iki kategoriyi birleştirmenin kaç satırı yanlış sınıfa taşıdığını ölçer.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.