Ders 10 / 17
Kategorik Değerlerin Düzeltilmesi
Devralınan 1.816 satırın tarife alanında 15 ayrı yazım geçer. Normalleştirme merdiveni kategori sayısını 15'ten sırayla 14, 9, 8 ve 6'ya, tarife cetvelinden gelen anlam eşlemesi 5'e indirir; dile duyarsız küçültme yalnız beş yazımı birleştirir ve iki yazımda görünmez bir iz bırakır. Satır sayısı hiç değişmez, ama sınıfların içi değişir: işyeri ile ticari birleştirilirse kategori 4'e iner ve 368 satır yanlış tarife basamağına taşınır, ticari sınıfı 389'dan 757'ye çıkar. Dile duyarsız küçültmeye göre yazılmış yedi girdilik bir eşleme tablosu 216 satırı sınıfsız bırakır, hiçbir hata üretmez ve tarife sınıfına göre gruplamada grupların toplamı 1.816 yerine 1.600 olur.
İçindekiler
Önceki dört ders sayısal alanları temizledi ve kümede hiç bakılmamış bir alan kaldı: tarife sınıfı. O alan bir sayı değil, saha formuna elle yazılmış bir metindir ve aynı sınıf birden çok biçimde yazılmıştır.
Bu ders o alanı düzeltir ve düzeltirken iki ayrı işin karıştığını gösterir. Yazım düzeltmesi metinden çıkar: aynı sözcüğün baştaki boşluğu, büyük harfi, iç boşluğu farklı yazılmıştır ve bunlar aynı kategoridir. Anlam kararı ise metinden çıkmaz: iki farklı sözcüğün aynı sınıfı gösterip göstermediğini ancak tarife cetveli söyler. Birincisi bir sayaç işidir, ikincisi bir yargıdır ve yanlış olduğunda satır sayısını hiç oynatmadan satırları yanlış kutuya koyar.
- VZ17. Küme önceki dört dersten devralınır ve 1.816 satırdır. Küme
nodeile modellenir ve kurgudur; tarife sınıfları ve cetvel de kurgudur. - VZ18. Küçük harfe çevirme dile bağlıdır. Dile duyarsız çevirim bazı harfleri gözle görünmeyen bir işaretle bırakır ve iki metin aynı görünüp farklı kalır; bu yüzden merdivende iki ayrı basamak sayılır.
- VZ19. Kategori birleştirme yazım farklarını kaldırır. Anlam eşlemesi ayrı bir adımdır ve kaynağı tarife cetvelidir.
- VZ20. Bir eşleme tablosunda karşılığı olmayan yazım hata üretmez: satır sınıfsız kalır ve sınıfa göre gruplayan ilk işlemde sessizce dışarıda kalır.
Kaç Kategori Kalıyor
// kategori.mjs — ayni ham kume MODELIDIR. Kume kurgudur: bolgesel olcum aginin // 1400 abonesi ve saha ziyaret kayitlari; ayni tohum, ayni satirlar. Onceki dort // dersin karari uygulanir ve bu adima 1816 satir girer. 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 dort dersin karari: eksik doldurma, tekillestirme, bicim farkinda // donusum ve ceyrekler acikligiyla isaretlenen 64 satirin ayrilmasi. 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()]; }; 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(",", ".")) })); 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]); }; const dd = OKUMA.map((s) => s.okuma_m3); const q1 = ceyrek(dd, 0.25), q3 = ceyrek(dd, 0.75), ca = q3 - q1; export const GIREN4 = OKUMA.filter((s) => s.okuma_m3 >= q1 - 1.5 * ca && s.okuma_m3 <= q3 + 1.5 * ca); // Normallestirme merdiveni. Her adim bir oncekinin uzerine biner; her adimdan // sonra kac ayri kategori kaldigi sayilir. export const N = [ ["N0 ham metin", (t) => t], ["N1 kirpma", (t) => t.trim()], ["N2 kucuk harf (dile duyarsiz)", (t) => t.trim().toLowerCase()], ["N3 kucuk harf (dile duyarli)", (t) => t.trim().toLocaleLowerCase("tr")], ["N4 isaret ve bosluk sadelestirme", (t) => t.trim().toLocaleLowerCase("tr") .replace(/\u0307/g, "").replace(/ş/g, "s").replace(/ı/g, "i").replace(/\s+/g, "")], ]; // Anlam eslemesi metinden cikmaz; tarife cetvelinden gelir. export const ESLEME = { mesken: "mesken", konut: "mesken", ticari: "ticari", isyeri: "isyeri", sanayi: "sanayi", tarimsal: "tarimsal" }; export const anahtar = N[4][1]; if (import.meta.url === `file://${process.argv[1]}`) { console.log(`model (tohum ${TOHUM}): onceki adimdan devralinan kume ${GIREN4.length} satir; ` + `tarife alaninda ${new Set(GIREN4.map((s) => s.tarife_metni)).size} ayri yazim geciyor`); const y1 = y([36, 11, 11]); console.log("\n" + y1(["normallestirme adimi", "kategori", "birlesen"])); let onceki = null; for (const [ad, f] of N) { const k = new Set(GIREN4.map((s) => f(s.tarife_metni))).size; console.log(y1([ad, k, onceki === null ? 0 : onceki - k])); onceki = k; } const sinif = new Set(GIREN4.map((s) => ESLEME[anahtar(s.tarife_metni)])); console.log(y1(["N5 anlam eslemesi (tarife cetveli)", sinif.size, onceki - sinif.size])); const y2 = y([12, 14, 14, 14]); console.log("\n" + y2(["yazim", "N2", "N3", "N4"])); for (const yz of [" Mesken ", "TİCARİ", "Ticari", "İş Yeri", "Is yeri", "isyeri"]) console.log(y2([JSON.stringify(yz), ...N.slice(2).map(([, f]) => JSON.stringify(f(yz)))])); }
model (tohum 20260305): onceki adimdan devralinan kume 1816 satir; tarife alaninda 15 ayri yazim geciyor normallestirme adimi kategori birlesen N0 ham metin 15 0 N1 kirpma 14 1 N2 kucuk harf (dile duyarsiz) 9 5 N3 kucuk harf (dile duyarli) 8 1 N4 isaret ve bosluk sadelestirme 6 2 N5 anlam eslemesi (tarife cetveli) 5 1 yazim N2 N3 N4 " Mesken " "mesken" "mesken" "mesken" "TİCARİ" "ti̇cari̇" "ticari" "ticari" "Ticari" "ticari" "ticari" "ticari" "İş Yeri" "i̇ş yeri" "iş yeri" "isyeri" "Is yeri" "is yeri" "ıs yeri" "isyeri" "isyeri" "isyeri" "isyeri" "isyeri"
Merdiven altı basamakta 15 yazımı 5 sınıfa indiriyor ve her basamağın kaç yazım birleştirdiği ayrı yazılıyor. Asıl işi küçük harfe çevirme yapar: beş yazım birleşir. Sonraki basamak bir yazım daha birleştirir, yani dile duyarsız çevirim bir yazımı çözememiştir.
İkinci tablo bunu gösteriyor. "TİCARİ" dile duyarsız çevrildiğinde ortaya çıkan metin ekranda
"ticari" gibi görünür ama değildir: harfin üstündeki nokta ayrı bir işaret olarak kalır ve iki
metin karşılaştırıldığında farklı çıkar. "Is yeri" ile "İş Yeri" çifti aynı sorunun tersidir —
dile duyarlı çevirim ikisini "ıs yeri" ve "iş yeri" yapar ve hâlâ ayrıdır; ancak işaretleri
ve boşlukları sadeleştiren basamak ikisini "isyeri" altında birleştirir.
Son basamak metinle ilgili değildir: "konut" ile "mesken" iki ayrı sözcüktür ve hiçbir
normalleştirme onları birleştirmez; tarife cetveli aynı basamağa baktıklarını söylediği için
birleşirler. Merdivenin tek yargı basamağı budur.
Yanlış Birleştirme
// birlestirme.mjs — ayni kume, iki soru: iki kategoriyi birlestirmek kac satiri // yanlis sinifa tasiyor ve eksik bir esleme tablosu kac satiri sinifsiz birakiyor. import { GIREN4, ESLEME, anahtar, N, y } from "./kategori.mjs"; const dagit = (esleme, anh) => { const m = new Map(); for (const s of GIREN4) { const k = esleme[anh(s.tarife_metni)]; m.set(k, (m.get(k) ?? 0) + 1); } return m; }; const dogru = dagit(ESLEME, anahtar); // Tarife cetvelinde isyeri ve ticari ayri basamaklardir; ikisini birlestirmek // bir yazim duzeltmesi degil, bir anlam kararidir. const YANLIS = { ...ESLEME, isyeri: "ticari" }; const yanlis = dagit(YANLIS, anahtar); const y1 = y([12, 12, 14, 12]); console.log(y1(["sinif", "dogru esleme", "isyeri>ticari", "fark"])); for (const k of [...dogru.keys()].sort()) console.log(y1([k, dogru.get(k), yanlis.get(k) ?? 0, (yanlis.get(k) ?? 0) - dogru.get(k)])); console.log(`toplam ${[...dogru.values()].reduce((a, b) => a + b, 0)} satir her iki eslemede de ` + `yerinde duruyor; kategori sayisi ${dogru.size}'ten ${yanlis.size}'e iniyor ve ` + `${dogru.get("isyeri")} satir yanlis sinifa tasiniyor`); // Yaygin esleme tablosu: dile duyarsiz kucultmeden gecen yazimlarla yazilmis. // Tabloda karsiligi olmayan yazim bir hata uretmez, sinifsiz kalir. const YAYGIN = { mesken: "mesken", konut: "mesken", ticari: "ticari", "is yeri": "isyeri", isyeri: "isyeri", sanayi: "sanayi", tarimsal: "tarimsal" }; const kaba = N[2][1]; const sinifsiz = GIREN4.filter((s) => YAYGIN[kaba(s.tarife_metni)] === undefined); const y2 = y([26, 8, 16]); console.log("\n" + y2(["esleme tablosu", "girdi", "sinifsiz satir"])); console.log(y2(["yaygin (N2 anahtarlari)", Object.keys(YAYGIN).length, sinifsiz.length])); console.log(y2(["N4 anahtarlari", Object.keys(ESLEME).length, GIREN4.filter((s) => ESLEME[anahtar(s.tarife_metni)] === undefined).length])); console.log(`sinifsiz kalan ${sinifsiz.length} satirin tarife yazimlari: ` + [...new Set(sinifsiz.map((s) => s.tarife_metni))].map((v) => JSON.stringify(v)).join(", ")); console.log(`tarife sinifina gore gruplama bu ${sinifsiz.length} satiri sessizce disarida ` + `birakir: gruplarin toplami ${GIREN4.length - sinifsiz.length}, kume ise ${GIREN4.length} satir`); console.log(`\nsatir hesabi: giren ${GIREN4.length}, cikan ${GIREN4.length}; ` + `0 satir elendi, 0 satir sessizce dustu. 15 yazim ${dogru.size} sinifta birlesti; ` + `isyeri ile ticari birlestirilseydi ${dogru.get("isyeri")} satir yanlis sinifa gider, ` + `yaygin esleme tablosu kullanilsaydi ${sinifsiz.length} satir sessizce duserdi`);
sinif dogru esleme isyeri>ticari fark isyeri 368 0 -368 mesken 713 713 0 sanayi 215 215 0 tarimsal 131 131 0 ticari 389 757 368 toplam 1816 satir her iki eslemede de yerinde duruyor; kategori sayisi 5'ten 4'e iniyor ve 368 satir yanlis sinifa tasiniyor esleme tablosu girdi sinifsiz satir yaygin (N2 anahtarlari) 7 216 N4 anahtarlari 6 0 sinifsiz kalan 216 satirin tarife yazimlari: "TİCARİ", "İş Yeri" tarife sinifina gore gruplama bu 216 satiri sessizce disarida birakir: gruplarin toplami 1600, kume ise 1816 satir satir hesabi: giren 1816, cikan 1816; 0 satir elendi, 0 satir sessizce dustu. 15 yazim 5 sinifta birlesti; isyeri ile ticari birlestirilseydi 368 satir yanlis sinifa gider, yaygin esleme tablosu kullanilsaydi 216 satir sessizce duserdi
İlk tablo yanlış bir yargının bedelini gösteriyor. İşyeri ile ticari abonelik cetvelde ayrı basamaklardır, ama iki sözcük gündelik dilde birbirinin yerine kullanıldığı için birleştirmek akla yatkın görünür. Uygulandığında kategori sayısı 5’ten 4’e iner, satır sayısı hiç değişmez ve 368 satır ticariye taşınır: 389 olan ticari 757’ye çıkar, işyeri sınıfı kaybolur. Kümede hiçbir şey eksilmez; yalnız her tarife kırılımı bundan sonra yanlış çıkar.
İkinci tablo sessiz kaybı ölçüyor. Yaygın eşleme tablosu dile duyarsız küçültmeden geçmiş
yazımlarla yazılmıştır ve yedi girdi taşır. İki yazımın — "TİCARİ" ve "İş Yeri" — o tabloda
karşılığı yoktur; bu yazımları taşıyan 216 satır sınıfsız kalır. Hiçbir hata üretilmez, hiçbir
işlem durmaz. Tarife sınıfına göre gruplandığında grupların toplamı 1.600’dür, oysa küme 1.816
satırdır. Aradaki 216 satır tabloda hiçbir yerde görünmez.
Aynı eşleme tablosu, sadeleştirilmiş anahtarlarla yazıldığında altı girdiyle sıfır satır sınıfsız bırakır. Fark tablonun büyüklüğünde değil, hangi normalleştirmeden sonra yazıldığında.
Adımın hesabı şudur: giren 1.816 satır, çıkan 1.816 satır. Hiçbir satır elenmedi, hiçbir satır sessizce düşmedi; 15 yazım 5 sınıfta birleşti. Bu adımın bedeli yine yapılmadığında ortaya çıkar: işyeri ile ticari birleştirilseydi 368 satır yanlış sınıfa gider, yaygın eşleme tablosu kullanılsaydı 216 satır sessizce düşerdi. Satır sayısı bir denetim ölçüsü değildir; bu adımda giren ile çıkan eşittir ve kümenin içi yine de baştan aşağı değişmiştir.
Özet
- Tarife alanında 15 ayrı yazım geçer; normalleştirme merdiveni kategori sayısını 15, 14, 9, 8, 6 ve anlam eşlemesiyle 5’e indirir.
- Dile duyarsız küçültme beş yazım birleştirir ama iki yazımda görünmeyen bir işaret bırakır. Yazım düzeltmesi metinden, anlam eşlemesi tarife cetvelinden gelir.
- İşyeri ile ticariyi birleştirmek kategori sayısını 4’e indirir, satır sayısını hiç oynatmaz ve 368 satırı yanlış sınıfa taşır: ticari 389’dan 757’ye çıkar.
- Dile duyarsız anahtarlarla yazılmış yedi girdilik eşleme tablosu 216 satırı sınıfsız bırakır ve gruplamada toplam 1.816 yerine 1.600 çıkar; sadeleştirilmiş anahtarlarla yazılan altı girdilik tablo sıfır satır düşürür.
- Adımın hesabı: giren 1.816, çıkan 1.816; 0 elendi, 0 sessizce düştü, 15 yazım 5 sınıfta birleşti.
Sonraki Adım
Tarife alanı düzeldi, ama aynı iş kümenin bütün metin alanları için yapılmadı. Sayaç kodu iki derste kırpıldı ve harf birliğine getirildi; adres alanına hiç dokunulmadı ve kümedeki her adres, abone kütüğündeki karşılığından farklı yazılmıştır. Sonraki ders normalleştirme merdivenini adres alanına uygular, her basamağın kütükle eşleşmeyi kaç kayıtta kurtardığını sayar ve bir basamak daha ileri gitmenin kaç kaydı ayırt edilemez hale getirdiğini ölçer.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.