Ders 08 / 10
Tahmin ve Planlama
Belirsizlik altında iş kalemi süresinin tahmini: üç aşamada üretilen tahminlerin gerçekleşen akış süresiyle karşılaştırılması, hata payı ile yanlılığın ayrılması, belirsizlik konisinin aşama aşama daralması, tahmine göre kurulan planın kaç kalemde tuttuğu ve tek kalem tahmini ile toplam tahmini arasındaki farkın hataların birbirini götürüp götürmemesiyle açıklanması.
İçindekiler
Önceki iki derste her iş kaleminin dokunduğu modüller baştan biliniyordu. El değiştirme, bekleme ve yeniden iş bu bilgiden hesaplandı. Gerçekte bir kalem başlarken bu bilgi yoktur: kalemin ne kadar süreceği tahmin edilir, ve tahmin iş ilerledikçe değişir.
Mimari kararların etkisi daha önce tahmin edilmişti; burada tahmin edilen şey iş kaleminin süresidir ve ölçüsü turdur. Ders bir tahmin kümesini gerçekleşen sürelerle karşılaştırır ve dört sayı üretir: hata payı, hatanın yönü, belirsizlik konisinin aşama aşama daralması ve tahmine göre kurulan planın kaç kalemde tuttuğu. Sonra tek kalem tahmini ile toplam tahmininin neden farklı davrandığı sayılır. Through-line bölgesel kütüphane ağıdır ve kurgudur.
Tahmin Edilen ile Gerçekleşen
ET15 — önceki iki dersin akış odaklı düzeni ve on iki iş kalemi değişmeden kullanılır. ET16 — bir kalemin gerçekleşen süresi, önceki derslerin akış modelinden gelir: çalışma turu artı bekleme turu artı yeniden işin eklediği turlar. Gerekçe: tahminin karşılaştırılacağı “gerçek” bir yerden gelmelidir; burada o yer daha önce koşturulmuş ve sayıları basılmış modeldir, yani gerçekleşen süre bu ders için bağımsız bir veri değil, aynı modelin çıktısıdır.
ET17 — sapma bir üreteçten çekilir; üreteç doğrusal eşlemedir ve tohumu 20250401 olarak
görünürdür. Gerekçe: tahmin hatasının rastgele bir bileşeni vardır ve koşum tekrarlanabilir
olmalıdır.
ET18 — üç tahmin aşaması vardır. Aşama 1’de yalnız kalemin başlığı bilinir ve dokunulacak modül sayısı ±%80 sapmayla tahmin edilir. Aşama 2’de kalem incelenmiştir, dokunulan modüller tam bilinir, sapma ±%30’dur. Aşama 3’te ilk ekip işini bitirmiştir; çalışma turu ve kaç ekibe dağılacağı bilinir, her el değiştirme için bir tur bekleme eklenir, sapma ±%10’dur. Gerekçe: aşamalar belirsizliğin doğal olarak azaldığı üç ana durağı temsil eder; her aşamada tahmincinin ne bildiği ayrıca yazılıdır, çünkü koninin daralması bilginin artmasından gelir.
// tahmin.mjs — uc asamali tahmin, ayni kalemlerin gerceklesen akis suresiyle karsilastirilir (model) import { writeFileSync } from "node:fs"; // ET15 — onceki iki dersin akis odakli duzeni ve on iki kalemi degismeden kullanilir const BOLUNME = { deneyim: "subeUcu personelUcu ceptenErisim", odunc: "oduncAkisi oduncKurali rezervasyonAkisi depoErisimi", ucret: "ucretAkisi ucretKurali", uyelik: "uyelikAkisi uyelikKurali kimlikKoprusu", katalog: "katalogKurali katalogKoprusu", platform: "ortakBicim olayGunlugu bildirimKuyrugu", }; const KANAL = "deneyim-odunc deneyim-ucret deneyim-uyelik odunc-ucret odunc-katalog " + "odunc-platform ucret-platform uyelik-platform katalog-platform"; const KALEM = [ ["gecikme ucreti orani", "ucretAkisi ucretKurali subeUcu ortakBicim"], ["rezervasyon iptali", "ceptenErisim rezervasyonAkisi oduncKurali bildirimKuyrugu"], ["uyelik hatirlatmasi", "uyelikAkisi uyelikKurali bildirimKuyrugu personelUcu"], ["katalog kaydinda alan", "katalogKoprusu katalogKurali ortakBicim ceptenErisim"], ["odunc suresi uzatma", "oduncAkisi oduncKurali subeUcu"], ["kimlikte ikinci adim", "kimlikKoprusu uyelikAkisi personelUcu ortakBicim"], ["ucret iadesi kaydi", "ucretAkisi depoErisimi olayGunlugu"], ["sube gecikme raporu", "personelUcu depoErisimi oduncAkisi"], ["bildirim metni bicimi", "bildirimKuyrugu ortakBicim"], ["rezervasyon sirasi", "ceptenErisim rezervasyonAkisi subeUcu"], ["odunc kurali istisnasi", "oduncKurali ucretKurali oduncAkisi ucretAkisi"], ["olay gunlugune alan", "olayGunlugu ortakBicim depoErisimi"], ]; const sahip = {}, E = Object.keys(BOLUNME), kom = Object.fromEntries(E.map((e) => [e, []])); for (const [e, ms] of Object.entries(BOLUNME)) for (const m of ms.split(" ")) sahip[m] = e; for (const k of KANAL.split(" ")) { const [x, y] = k.split("-"); kom[x].push(y); kom[y].push(x); } const d = {}; for (const s of E) { d[s] = Object.fromEntries(E.map((e) => [e, -1])); d[s][s] = 0; for (let q = [s]; q.length; ) { const u = q.shift(); for (const v of kom[u]) if (d[s][v] < 0) { d[s][v] = d[s][u] + 1; q.push(v); } } } const deg = {}; for (const [, ms] of KALEM) for (const m of ms.split(" ")) (deg[m] ??= new Set([sahip[m]])).add(sahip[ms.split(" ")[0]]); // ET16 — gerceklesen sure onceki derslerin akis modelinden gelir: calisma + bekleme + yeniden is const BEKLE = [0, 1, 3, 5], YOK = 8; const GERCEK = KALEM.map(([ad, dizi]) => { const ms = dizi.split(" "), sira = [...new Set(ms.map((m) => sahip[m]))]; let bek = 0, enUzun = 0, kopuk = 0; for (let j = 1; j < sira.length; j++) { const u = d[sira[j - 1]][sira[j]], b = u < 0 ? YOK : BEKLE[u]; bek += b; enUzun = Math.max(enUzun, b); if (u < 0 || u >= 2) kopuk += 1; } const neden = []; if (kopuk) neden.push("kisit"); if (ms.some((m) => deg[m].size >= 3)) neden.push("sinir"); if (sira.length >= 4) neden.push("bilgi"); const cal = ms.length + neden.length * 2, bekT = bek + neden.length * enUzun; return { ad, modul: ms.length, ekip: sira.length, calisma: cal, bekleme: bekT, yenidenIs: neden.length, gercek: cal + bekT }; }); // ET17 — uretec: dogrusal esleme, tohum gorunur; her asamada bir tur cekilir const TOHUM = 20250401; function uretec(t) { return () => { t = (t * 1103515245 + 12345) % 2147483648; return t / 2147483648; }; } const r = uretec(TOHUM); const sapma = (genislik) => 1 + (r() * 2 - 1) * genislik; // ET18 — uc tahmin asamasi: istek geldiginde, kalem incelendiginde, ilk ekip isini bitirdiginde const T = GERCEK.map((g) => { const a1 = Math.max(1, Math.round(g.modul * sapma(0.8))); // yalnizca basligi gorur const a2 = Math.round(g.modul * sapma(0.3)); // dokunulan modulleri bilir const a3 = Math.round((g.calisma + (g.ekip - 1)) * sapma(0.1)); // ekip sayisini da bilir return { ...g, a1, a2, a3 }; }); writeFileSync("tahmin.json", JSON.stringify(T)); console.log(`${"is kalemi".padEnd(24)}${"modul".padStart(6)}${"ekip".padStart(5)}` + `${"asama1".padStart(8)}${"asama2".padStart(8)}${"asama3".padStart(8)}${"gercek".padStart(8)}` + `${" = calisma + bekleme"}`); for (const t of T) console.log(`${t.ad.padEnd(24)}${String(t.modul).padStart(6)}${String(t.ekip).padStart(5)}` + `${String(t.a1).padStart(8)}${String(t.a2).padStart(8)}${String(t.a3).padStart(8)}` + `${String(t.gercek).padStart(8)} ${String(t.calisma).padStart(2)} + ${String(t.bekleme).padStart(2)}` + `${t.yenidenIs ? ` (${t.yenidenIs} yeniden is)` : ""}`); console.log(`\ntohum ${TOHUM}; toplam gercek ${T.reduce((s, t) => s + t.gercek, 0)} tur ` + `(${T.reduce((s, t) => s + t.calisma, 0)} calisma + ${T.reduce((s, t) => s + t.bekleme, 0)} bekleme)`);
is kalemi modul ekip asama1 asama2 asama3 gercek = calisma + bekleme gecikme ucreti orani 4 3 5 4 11 18 8 + 10 (2 yeniden is) rezervasyon iptali 4 3 1 3 7 9 6 + 3 (1 yeniden is) uyelik hatirlatmasi 4 3 6 5 10 18 8 + 10 (2 yeniden is) katalog kaydinda alan 4 3 4 3 9 18 8 + 10 (2 yeniden is) odunc suresi uzatma 3 2 1 2 6 7 5 + 2 (1 yeniden is) kimlikte ikinci adim 4 3 3 3 10 18 8 + 10 (2 yeniden is) ucret iadesi kaydi 3 3 4 4 6 8 5 + 3 (1 yeniden is) sube gecikme raporu 3 2 4 2 6 7 5 + 2 (1 yeniden is) bildirim metni bicimi 2 1 3 3 4 4 4 + 0 (1 yeniden is) rezervasyon sirasi 3 2 5 3 6 7 5 + 2 (1 yeniden is) odunc kurali istisnasi 4 2 6 5 5 5 4 + 1 olay gunlugune alan 3 2 5 4 6 7 5 + 2 (1 yeniden is) tohum 20250401; toplam gercek 126 tur (71 calisma + 55 bekleme)
Hata Payı ve Koninin Daralması
ET19 — bir kalemde plan “tuttu” sayılır: tahmin gerçeğin %20 bandı içinde kalıyorsa. ET20 — kalemler dokundukları ekip sayısına göre iki kümeye ayrılır: bir–iki ekibe dokunanlar ve üç ve daha çok ekibe dokunanlar. Gerekçe: bant olmadan “tuttu” sözcüğü sayıya çevrilemez; ikinci ayrım ise ekip sınırının tahmin üzerindeki payını yalıtır.
// koni.mjs — hata payi, belirsizlik konisinin daralmasi, tek kalem tahmini ile toplam tahmini import { readFileSync } from "node:fs"; const T = JSON.parse(readFileSync("tahmin.json", "utf8")); const AS = ["a1", "a2", "a3"]; const AD = { a1: "asama 1 (istek)", a2: "asama 2 (inceleme)", a3: "asama 3 (ilk ekip bitti)" }; const top = (f) => T.reduce((s, t) => s + f(t), 0); const yuzde = (x) => `%${(100 * x).toFixed(1)}`; // ET19 — plan bir kalemde "tuttu" sayilir: tahmin gercegin %20 bandi icinde kaliyorsa const BANT = 0.2; console.log(`${"asama".padEnd(26)}${"ort. mutlak hata".padStart(18)}${"ort. yanlilik".padStart(15)}` + `${"koni: tahmin/gercek".padStart(21)}${"genislik".padStart(10)}${"plan tuttu".padStart(12)}`); for (const a of AS) { const oran = T.map((t) => t[a] / t.gercek).sort((x, y) => x - y); const mape = top((t) => Math.abs(t[a] - t.gercek) / t.gercek) / T.length; const yan = top((t) => (t[a] - t.gercek) / t.gercek) / T.length; const tut = T.filter((t) => Math.abs(t[a] - t.gercek) / t.gercek <= BANT).length; console.log(`${AD[a].padEnd(26)}${yuzde(mape).padStart(18)}${yuzde(yan).padStart(15)}` + `${`${oran[0].toFixed(2)} - ${oran[oran.length - 1].toFixed(2)}`.padStart(21)}` + `${(oran[oran.length - 1] - oran[0]).toFixed(2).padStart(10)}${`${tut}/${T.length}`.padStart(12)}`); } console.log(`\n${"asama".padEnd(26)}${"toplam tahmin".padStart(15)}${"toplam gercek".padStart(15)}` + `${"toplamin hatasi".padStart(17)}${"tek kalem ort. hatasi".padStart(23)}`); for (const a of AS) { const tt = top((t) => t[a]), tg = top((t) => t.gercek); const mape = top((t) => Math.abs(t[a] - t.gercek) / t.gercek) / T.length; console.log(`${AD[a].padEnd(26)}${String(tt).padStart(15)}${String(tg).padStart(15)}` + `${yuzde((tt - tg) / tg).padStart(17)}${yuzde(mape).padStart(23)}`); } // hatanin nereden geldigi: asama 2 yalnizca calismayi tahmin eder const a2 = top((t) => t.a2), gercek = top((t) => t.gercek); console.log(`\nasama 2 toplami ${a2} tur; gercek ${gercek} tur; fark ${gercek - a2} tur`); console.log(` farkin bilesenleri: bekleme ${top((t) => t.bekleme)} tur, ` + `yeniden isin ekledigi calisma ${top((t) => 2 * t.yenidenIs)} tur, ` + `dokunulan modul ${top((t) => t.modul)} tur (asama 2 bunu tahmin eder)`); // ET20 — kalemler dokunduklari ekip sayisina gore ayrilir console.log(`\n${"kalem kumesi".padEnd(26)}${"kalem".padStart(7)}${"ort. gercek".padStart(13)}` + `${"bekleme payi".padStart(14)}${"asama 2 hatasi".padStart(16)}${"asama 3 hatasi".padStart(16)}`); for (const [ad, f] of [["1-2 ekibe dokunan", (t) => t.ekip <= 2], ["3+ ekibe dokunan", (t) => t.ekip >= 3]]) { const k = T.filter(f), s = (g) => k.reduce((x, t) => x + g(t), 0); console.log(`${ad.padEnd(26)}${String(k.length).padStart(7)}` + `${(s((t) => t.gercek) / k.length).toFixed(1).padStart(13)}` + `${yuzde(s((t) => t.bekleme) / s((t) => t.gercek)).padStart(14)}` + `${yuzde(s((t) => Math.abs(t.a2 - t.gercek) / t.gercek) / k.length).padStart(16)}` + `${yuzde(s((t) => Math.abs(t.a3 - t.gercek) / t.gercek) / k.length).padStart(16)}`); }
asama ort. mutlak hata ort. yanlilik koni: tahmin/gercek genislik plan tuttu asama 1 (istek) %55.8 %-52.5 0.11 - 1.20 1.09 1/12 asama 2 (inceleme) %58.4 %-58.4 0.17 - 1.00 0.83 1/12 asama 3 (ilk ekip bitti) %23.5 %-23.5 0.50 - 1.00 0.50 6/12 asama toplam tahmin toplam gercek toplamin hatasi tek kalem ort. hatasi asama 1 (istek) 47 126 %-62.7 %55.8 asama 2 (inceleme) 41 126 %-67.5 %58.4 asama 3 (ilk ekip bitti) 86 126 %-31.7 %23.5 asama 2 toplami 41 tur; gercek 126 tur; fark 85 tur farkin bilesenleri: bekleme 55 tur, yeniden isin ekledigi calisma 30 tur, dokunulan modul 41 tur (asama 2 bunu tahmin eder) kalem kumesi kalem ort. gercek bekleme payi asama 2 hatasi asama 3 hatasi 1-2 ekibe dokunan 6 6.2 %24.3 %44.6 %9.5 3+ ekibe dokunan 6 14.8 %51.7 %72.2 %37.5
Koni Daralırken Hata Neden Durdu
İlk tablonun iki sütunu ters yönlere gider. Koni gerçekten daralır: tahmin/gerçek oranının genişliği 1.09’dan 0.83’e, oradan 0.50’ye iner. Ama ortalama mutlak hata aynı yolu izlemez — aşama 1’de %55.8, aşama 2’de %58.4’tür. Belirsizlik azalırken hata azalmadı.
Nedeni yanlılık sütununda yazılıdır. Üç aşamanın üçünde de yanlılık negatiftir: %-52.5, %-58.4, %-23.5. Yani tahminler yalnız dağınık değil, hepsi aynı yöne yanlıştır — her aşamada süre olduğundan az tahmin edilir. Aşama 1’den aşama 2’ye geçerken tahmincinin öğrendiği şey dokunulan modüllerin tam listesidir; bu bilgi sapmayı ±%80’den ±%30’a indirir ama yanlılığa dokunmaz, çünkü yanlılık modül sayısını yanlış bilmekten gelmiyordu.
Nereden geldiğini ikinci çıktı bloğunun ortasındaki satır adlandırır. Aşama 2’nin toplam tahmini 41 tur, gerçekleşen toplam 126 turdur; aradaki 85 turun 55’i bekleme, 30’u yeniden işin eklediği çalışmadır. Aşama 2 dokunulan modül sayısını (41 tur) neredeyse tam bilir — ve tahmin ettiği tek şey odur. Tahmin çalışmayı tahmin eder; gerçekleşen süre akış süresidir. İkisinin arasındaki fark önceki iki dersin ölçtüğü şeyin ta kendisidir: el değiştirmede beklenen turlar ve yanlış sınır yüzünden geri dönen kalemler.
Aşama 3 hatayı %23.5’e indirir ve planın tuttuğu kalem sayısını 1’den 6’ya çıkarır. Yaptığı tek şey bekleme kavramını tahmine sokmaktır — her el değiştirme için bir tur. Bu kaba düzeltme bile hatanın yarısından fazlasını kapatır; kalan %23.5 ise beklemenin bir turdan uzun olduğu geçişlerden ve yeniden işten gelir.
Tek Kalem Tahmini ile Toplam Tahmini
İkinci tablo yaygın bir beklentiyi sınar: tek tek kalemlerde yapılan hataların toplamda birbirini götürmesi. Götürmez. Aşama 2’de tek kalem ortalama mutlak hatası %58.4, toplamın hatası %-67.5’tir — toplam, tek kalemden daha kötüdür. Aynı ilişki üç aşamada da sürer.
Hataların birbirini götürmesi ancak hataların iki yöne dağıldığı durumda olur. Burada on iki kalemin hiçbirinde aşama 2 tahmini gerçeği aşmaz; koni sütunundaki en yüksek oran 1.00’dır. Bir yöne yanlı hatalar toplandığında büyüklükleri de toplanır. Bir tahmin kümesinin toplamı, ancak kümedeki hatalar yansızsa tek kalem hatasından daha güvenilirdir; yanlılık varsa toplam tahmin tek kalem tahmininden daha az güvenilirdir.
Son tablo yanlılığın nereden geldiğini gösterir. Bir–iki ekibe dokunan altı kalemin ortalama gerçekleşen süresi 6.2 tur ve bunun %24.3’ü beklemedir; aşama 2 hatası %44.6, aşama 3 hatası %9.5’tir. Üç ve daha çok ekibe dokunan altı kalemde ise ortalama süre 14.8 tur, bekleme payı %51.7, aşama 2 hatası %72.2 ve aşama 3 hatası %37.5’tir. Aynı tahmin yöntemi, ekip sınırını çok geçen kalemlerde yaklaşık iki kat daha kötü çalışır. Tahminin kötüleştiği yer, önceki iki dersin akış süresinin uzadığı yerle aynıdır — modül sınırı ile ekip sınırının örtüşmediği kalemler.
Özet
- On iki kalemin gerçekleşen süresi önceki derslerin akış modelinden alındı (toplam 126 tur =
71 çalışma + 55 bekleme) ve üç aşamada üretilen tahminlerle karşılaştırıldı; üreteç tohumu
20250401. - Belirsizlik konisi aşama aşama daralır (tahmin/gerçek oranının genişliği 1.09 → 0.83 → 0.50) ama ortalama mutlak hata aynı yolu izlemez: %55.8 → %58.4 → %23.5. Aşama 1’den 2’ye geçişte koni daraldığı halde hata azalmadı.
- Üç aşamada da yanlılık negatiftir (%-52.5, %-58.4, %-23.5): tahminler dağınık değil, hepsi aynı yöne yanlıştır. Aşama 2’nin 41 turluk toplam tahmini ile 126 turluk gerçek arasındaki 85 turun 55’i bekleme, 30’u yeniden işin eklediği çalışmadır.
- Beklemeyi kaba biçimde (el değiştirme başına bir tur) tahmine sokmak hatayı %23.5’e indirir ve %20 bandında tutan kalem sayısını 1/12’den 6/12’ye çıkarır.
- Hatalar birbirini götürmez: aşama 2’de tek kalem ortalama hatası %58.4 iken toplamın hatası %-67.5’tir. Tek yöne yanlı hatalar toplandığında büyüklükleri de toplanır.
- Ekip sınırını çok geçen kalemlerde tahmin yaklaşık iki kat kötüleşir: 1–2 ekibe dokunan kalemlerde aşama 2 hatası %44.6 ve bekleme payı %24.3 iken, 3+ ekibe dokunanlarda %72.2 ve %51.7’dir.
Sonraki Adım
Bu dersin bütün sayıları bir varsayıma dayanıyordu: iş kalemi kümesi çeyrek boyunca sabittir. On iki kalem baştan sayıldı, tahmin edildi, koşturuldu. Gerçekte kalem kümesi durmaz — çeyrek ortasında yeni bir istek gelir, var olan bir kalemin kapsamı büyür, bir başkası iptal edilir. Bu durumda tahminin hata payı yalnız yukarıdaki nedenlerle değil, tahmin edilen işin kendisi değiştiği için de büyür. Sonraki ders bu değişimi ele alır: bir kalemin kapsamı büyüdüğünde akışta ne olur, değişiklik hangi noktadan sonra kabul edilirse yeniden iş kaçınılmaz olur ve değişimi denetleyen bir düzenin kendisi akışa kaç tur ekler.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.