94_Anhang_Glossar_und_Literatur.md enthielt zwei verschiedene Nachschlagewerke
in einer Datei. Jetzt sind es zwei Anhaenge: E = Glossar (92 Eintraege),
F = Literaturverzeichnis (6 Kategorien). Aus 5 Anhaengen werden 6, aus 36
Kapiteldateien 37.
Die Teilung war billig: Die Datei trug bereits zwei eigenstaendige
Ueberschriften mit nichts als einem --- dazwischen, und im ganzen Buch gab es
genau einen {ref:anhang:glossar-literatur} - die Weiter-mit-Zeile im
Spickzettel. Geprueft: keine Inhaltszeile verloren, alle 92 Glossareintraege
auf der neuen Seite, Indexmarken unveraendert bei 328.
Das Seitenleisten-Menue bekommt zwei Eintraege:
Beispielprogramme
Notebooks
Download Notebooks als ZIP <- neu, eingerueckt
Glossar <- neu
Stichwortverzeichnis
Gesamtdokument (eine Seite)
Download als PDF
Der ZIP-Link benutzt dieselbe Konstante wie baue_notebooks_seite() beim
Schreiben des Archivs, damit Link und Datei nicht auseinanderlaufen. Das
Glossar erscheint absichtlich doppelt: hier als Abkuerzung neben dem
Stichwortverzeichnis, und unten in der Gruppe "Anhaenge", weil es ein Anhang
ist.
Die verwaiste anhang-glossar-literatur.html von Hand entfernt - der Build
raeumt alte Seiten nicht ab.
Nebenbefund, in PROGRESS.md festgehalten: OR_HTML_04/assets/site.css ist eine
von Hand gepflegte Quelle, die im als "generiert" beschriebenen Verzeichnis
liegt. Der Build schreibt sie nie. Dasselbe gilt fuer site.js, icons.svg,
highlight.css und plotly.min.js.
--check: 5 Teile, 23 Kapitel, 6 Anhaenge, 296 Abschnitte, 825 Querverweise,
328 Indexmarken, 37 Dateien, 28.544 Zeilen, 305 Hauptueberschriften, keine
Warnung. PDF unveraendert 759 Seiten.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
756 lines
92 KiB
HTML
Generated
756 lines
92 KiB
HTML
Generated
<!doctype html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>Kapitel 15: Predict-then-Optimize — die bessere Prognose, die schlechtere Entscheidung · Optimierte Entscheidungsfindung mit Python</title>
|
||
<script>
|
||
(function () {
|
||
try {
|
||
var t = localStorage.getItem("or-theme");
|
||
if (t) document.documentElement.setAttribute("data-theme", t);
|
||
} catch (e) {}
|
||
})();
|
||
</script>
|
||
<link rel="stylesheet" href="assets/highlight.css" />
|
||
<link rel="stylesheet" href="katex/katex.min.css" />
|
||
<script defer="" src="katex/katex.min.js"></script>
|
||
<script>document.addEventListener("DOMContentLoaded", function () {
|
||
var mathElements = document.getElementsByClassName("math");
|
||
var macros = [];
|
||
for (var i = 0; i < mathElements.length; i++) {
|
||
var texText = mathElements[i].firstChild;
|
||
if (mathElements[i].tagName == "SPAN") {
|
||
katex.render(texText.data, mathElements[i], {
|
||
displayMode: mathElements[i].classList.contains('display'),
|
||
throwOnError: false,
|
||
macros: macros,
|
||
fleqn: false
|
||
});
|
||
}}
|
||
// Der Browser springt zu einem #anker in der URL schon beim ersten Rendern
|
||
// an, BEVOR die KaTeX-Formeln oben im Text ihre finale Hoehe bekommen -
|
||
// durch den Reflow landet der Anker danach zu weit unten. Nach dem
|
||
// Formel-Rendering hier erneut zum Anker springen, das behebt es.
|
||
if (location.hash) {
|
||
var ziel = document.getElementById(decodeURIComponent(location.hash.slice(1)));
|
||
if (ziel) ziel.scrollIntoView({behavior: "instant", block: "start"});
|
||
}
|
||
});
|
||
</script>
|
||
<link rel="stylesheet" href="assets/site.css" />
|
||
</head>
|
||
<body>
|
||
<svg style="display:none" aria-hidden="true"><symbol id="icon-menu" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
||
<line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/>
|
||
</symbol>
|
||
<symbol id="icon-search" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
||
<circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.2" y2="16.2"/>
|
||
</symbol>
|
||
<symbol id="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
||
<circle cx="12" cy="12" r="4.5"/>
|
||
<line x1="12" y1="1.5" x2="12" y2="4"/><line x1="12" y1="20" x2="12" y2="22.5"/>
|
||
<line x1="1.5" y1="12" x2="4" y2="12"/><line x1="20" y1="12" x2="22.5" y2="12"/>
|
||
<line x1="4.5" y1="4.5" x2="6.2" y2="6.2"/><line x1="17.8" y1="17.8" x2="19.5" y2="19.5"/>
|
||
<line x1="19.5" y1="4.5" x2="17.8" y2="6.2"/><line x1="6.2" y1="17.8" x2="4.5" y2="19.5"/>
|
||
</symbol>
|
||
<symbol id="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M20 14.5A8.5 8.5 0 1 1 9.5 4a6.8 6.8 0 0 0 10.5 10.5z"/>
|
||
</symbol>
|
||
<symbol id="icon-chevron-left" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<polyline points="15 4 7 12 15 20"/>
|
||
</symbol>
|
||
<symbol id="icon-chevron-right" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<polyline points="9 4 17 12 9 20"/>
|
||
</symbol>
|
||
<symbol id="icon-check" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<polyline points="4 13 9.5 18.5 20 6"/>
|
||
</symbol>
|
||
<symbol id="icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M18 13.5V19a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 19V7A1.5 1.5 0 0 1 5 5.5h5.5"/>
|
||
<polyline points="14.5 3.5 20.5 3.5 20.5 9.5"/><line x1="11" y1="13" x2="20" y2="4"/>
|
||
</symbol>
|
||
<symbol id="icon-book" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M4 5.5A2 2 0 0 1 6 4h6v16H6a2 2 0 0 0-2 1.5z"/>
|
||
<path d="M20 5.5A2 2 0 0 0 18 4h-6v16h6a2 2 0 0 1 2 1.5z"/>
|
||
</symbol>
|
||
<symbol id="icon-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
|
||
</symbol>
|
||
<symbol id="icon-download" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M12 3v12"/><polyline points="7 10 12 15 17 10"/><path d="M4 19.5h16"/>
|
||
</symbol></svg>
|
||
<header class="site-header">
|
||
<button type="button" class="icon-btn" id="sidebar-toggle" aria-label="Menü öffnen"><svg class="icon" aria-hidden="true"><use href="#icon-menu"></use></svg></button>
|
||
<a class="brand" href="index.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> <span>Optimierte Entscheidungsfindung mit Python</span></a>
|
||
<div class="site-search">
|
||
<input id="suche-eingabe" type="search" placeholder="Suchen …" aria-label="Suche" autocomplete="off" />
|
||
<svg class="icon such-icon" aria-hidden="true"><use href="#icon-search"></use></svg>
|
||
<div id="suche-ergebnisse" class="suche-ergebnisse" hidden></div>
|
||
</div>
|
||
<button type="button" class="icon-btn" id="theme-toggle" aria-label="Darstellung umschalten">
|
||
<svg class="icon icon-sun" aria-hidden="true"><use href="#icon-sun"></use></svg><svg class="icon icon-moon" aria-hidden="true"><use href="#icon-moon"></use></svg>
|
||
</button>
|
||
</header>
|
||
<div class="site-body">
|
||
<div class="sidebar-overlay" id="sidebar-overlay" hidden></div>
|
||
<nav class="sidebar" id="sidebar" aria-label="Kapitelnavigation"><div class="sidebar-inhalt"><details class="sidebar-gruppe"><summary>Einstieg</summary><ul><li data-kapitel="vorwort.html"><a href="vorwort.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Vorwort & Lesehilfe</span></a></li><li data-kapitel="notation.html"><a href="notation.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Notation & Abkürzungen</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil I: Grundlagen des Operations Research</summary><ul><li data-kapitel="einfuehrung.html"><a href="einfuehrung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 1: Einführung in Operations Research — Vom Ursprung zur mathematischen Entscheidungsfindung</span></a></li><li data-kapitel="fundament.html"><a href="fundament.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 2: Das mathematische Fundament — Vektoren, Matrizen, Konvexität</span></a></li><li data-kapitel="oekosystem.html"><a href="oekosystem.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 3: Das Python-Ökosystem für OR — Solver, Bindings und Modellierungsschichten</span></a></li><li data-kapitel="modellierung.html"><a href="modellierung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 4: Vom Management-Wunsch zum Modell</span></a></li><li data-kapitel="synthese-grundlagen.html"><a href="synthese-grundlagen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil I</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil II: Die Kernverfahren der deterministischen Optimierung</summary><ul><li data-kapitel="lp.html"><a href="lp.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 5: Lineare Programmierung — Simplex, Dualität und Schattenpreise</span></a></li><li data-kapitel="milp.html"><a href="milp.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 6: Gemischt-ganzzahlige Optimierung — Diskrete Entscheidungen und Branch-and-Bound</span></a></li><li data-kapitel="cpsat.html"><a href="cpsat.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 7: Constraint Programming mit CP-SAT — Logik, Scheduling und Zuweisung</span></a></li><li data-kapitel="graphen.html"><a href="graphen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 8: Graphen, Flüsse und Touren — Min-Cost-Flow, Matching und VRP</span></a></li><li data-kapitel="metaheuristiken.html"><a href="metaheuristiken.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 9: Metaheuristiken — wenn der exakte Solver aussteigt</span></a></li><li data-kapitel="dekomposition.html"><a href="dekomposition.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 10: Spaltengenerierung — das Modell umbauen statt die Lösung raten</span></a></li><li data-kapitel="synthese-kernverfahren.html"><a href="synthese-kernverfahren.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil II</span></a></li></ul></details><details class="sidebar-gruppe" open><summary>Teil III: Nichtlinearität, Unsicherheit und mehrperiodige Dynamik</summary><ul><li data-kapitel="qp-nlp.html"><a href="qp-nlp.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 11: Quadratische und nichtlineare Optimierung — KKT, Lagrange, Konvexität</span></a></li><li data-kapitel="unsicherheit.html"><a href="unsicherheit.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 12: Optimierung unter Unsicherheit — Monte-Carlo, Stochastik, Robustheit</span></a></li><li data-kapitel="dynamische-programmierung.html"><a href="dynamische-programmierung.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 13: Dynamische Programmierung — Die Bellman-Gleichung und Order-Execution</span></a></li><li data-kapitel="mehrziel.html"><a href="mehrziel.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 14: Mehrere Ziele — Pareto-Fronten statt Gewichte</span></a></li><li data-kapitel="prognose.html" class="aktiv"><a href="prognose.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 15: Predict-then-Optimize — die bessere Prognose, die schlechtere Entscheidung</span></a></li><li data-kapitel="synthese-nichtlinear.html"><a href="synthese-nichtlinear.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil III</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil IV: Anwendungen — Energiewirtschaft und Finanzmärkte</summary><ul><li data-kapitel="bruecke.html"><a href="bruecke.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 16: Die Strukturbrücke — dieselbe Mathematik, zwei Welten</span></a></li><li data-kapitel="supplychain.html"><a href="supplychain.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 17: Supply-Chain und Energieeinsatz unter Unsicherheit</span></a></li><li data-kapitel="finanzdaten.html"><a href="finanzdaten.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 18: Finanzdaten-Modellierung — Renditen, Kovarianz und Shrinkage</span></a></li><li data-kapitel="markowitz.html"><a href="markowitz.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 19: Die moderne Portfoliotheorie nach Markowitz</span></a></li><li data-kapitel="cvar.html"><a href="cvar.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 20: Tail-Risiko, CVaR und Transaktionskosten</span></a></li><li data-kapitel="handelsmaschine.html"><a href="handelsmaschine.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 21: Die vollständige quantitative Handelsmaschine</span></a></li><li data-kapitel="synthese-anwendungen.html"><a href="synthese-anwendungen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil IV</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Teil V: Praxis</summary><ul><li data-kapitel="praxisfallen.html"><a href="praxisfallen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 22: Praxisfallen und der Weg zum produktiven Einsatz</span></a></li><li data-kapitel="testing.html"><a href="testing.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Kapitel 23: Testen, Messen, Ausliefern</span></a></li><li data-kapitel="synthese-praxis.html"><a href="synthese-praxis.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Synthese Teil V</span></a></li><li data-kapitel="projektwerkstatt.html"><a href="projektwerkstatt.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Projektwerkstatt</span></a></li></ul></details><details class="sidebar-gruppe"><summary>Anhänge</summary><ul><li data-kapitel="anhang-loesungen.html"><a href="anhang-loesungen.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang A: Lösungen zu allen Übungsaufgaben</span></a></li><li data-kapitel="anhang-modellierungsmuster.html"><a href="anhang-modellierungsmuster.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang B: Katalog der Modellierungsmuster</span></a></li><li data-kapitel="anhang-fehlerdiagnose.html"><a href="anhang-fehlerdiagnose.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang C: Fehlerdiagnose-Handbuch</span></a></li><li data-kapitel="anhang-spickzettel.html"><a href="anhang-spickzettel.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang D: Spickzettel der Solver</span></a></li><li data-kapitel="anhang-glossar.html"><a href="anhang-glossar.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang E: Glossar</span></a></li><li data-kapitel="anhang-literatur.html"><a href="anhang-literatur.html"><span class="fortschritt-haken"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg></span><span>Anhang F: Literaturverzeichnis</span></a></li></ul></details><ul class="sidebar-extra"><li><a href="programme.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> Beispielprogramme</a></li><li><a href="notebooks.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> Notebooks</a></li><li class="sidebar-unterpunkt"><a href="Notebooks_04.zip" download><svg class="icon" aria-hidden="true"><use href="#icon-download"></use></svg> Download Notebooks als ZIP</a></li><li><a href="anhang-glossar.html"><svg class="icon" aria-hidden="true"><use href="#icon-book"></use></svg> Glossar</a></li><li><a href="stichwortverzeichnis.html"><svg class="icon" aria-hidden="true"><use href="#icon-search"></use></svg> Stichwortverzeichnis</a></li><li><a href="gesamtdokument.html"><svg class="icon" aria-hidden="true"><use href="#icon-external-link"></use></svg> Gesamtdokument (eine Seite)</a></li><li><a href="Operations_Research_mit_Python_Version_04.pdf" download><svg class="icon" aria-hidden="true"><use href="#icon-download"></use></svg> Download als PDF</a></li></ul></div></nav>
|
||
<main class="content">
|
||
<nav class="breadcrumb" aria-label="Breadcrumb"><a href="index.html">Start</a> › <span>Teil III</span> › <span>Kapitel 15: Predict-then-Optimize — die bessere Prognose, die schlechtere Entscheidung</span></nav>
|
||
<nav class="prev-next"><a class="prev-next-knopf prev-next-prev" href="mehrziel.html"><svg class="icon" aria-hidden="true"><use href="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 14: Mehrere Ziele — Pareto-Fronten statt Gewichte</span></a><a class="prev-next-knopf prev-next-next" href="synthese-nichtlinear.html"><span><small>Weiter</small>Synthese Teil III</span><svg class="icon" aria-hidden="true"><use href="#icon-chevron-right"></use></svg></a></nav>
|
||
<article>
|
||
<h1 id="kap-prognose">Kapitel 15: Predict-then-Optimize — die bessere Prognose, die schlechtere Entscheidung</h1>
|
||
<div class="card card-blick">
|
||
<blockquote>
|
||
<p><strong>📌 Kapitel auf einen Blick</strong></p>
|
||
<p><strong>Worum geht es?</strong> Um die Naht zwischen zwei Welten, die in getrennten Abteilungen sitzen: Ein Modell <strong>prognostiziert</strong>, ein anderes <strong>entscheidet</strong>. Beide arbeiten sauber — und genau an der Naht entsteht ein Fehler, den keine der beiden Seiten sieht.</p>
|
||
<p><strong>Voraussetzungen:</strong> <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>, insbesondere das Newsvendor-Problem und das kritische Verhältnis. Etwas Regression hilft, ist aber nicht nötig.</p>
|
||
<p><strong>Danach können Sie:</strong> begründen, warum ein Prognosemodell mit kleinerem MSE teurere Entscheidungen erzeugen kann; die richtige <strong>Zielgröße</strong> einer Prognose bestimmen; und Prognosemodelle an Entscheidungskosten statt an Fehlermaßen bewerten.</p>
|
||
<p><strong>Zeitbedarf:</strong> ca. 3,5 Stunden.</p>
|
||
<p><strong>Programme:</strong><br />
|
||
<code>Predict_then_Optimize.py</code></p>
|
||
<p><strong>Notebook:</strong> <a href="Notebooks_04/prognose.ipynb">prognose.ipynb</a> — herunterladen und in Jupyter öffnen, in Colab hochladen oder mit dem Kurs-Image starten</p>
|
||
</blockquote>
|
||
</div>
|
||
<hr />
|
||
<h2 id="sec:prognose-schnellstart">15.1 In 5 Minuten gelöst</h2>
|
||
<div class="card card-schnellstart">
|
||
<blockquote>
|
||
<p><strong>🚀 In 5 Minuten gelöst: Der Durchschnitt ist die falsche Zahl</strong></p>
|
||
<p>Eine Bäckerei kennt die Nachfrage der letzten 20 Tage. Ein Brot bringt 6 € Marge, ein übriges kostet 3 € Einkauf. Wie viele soll sie ansetzen?</p>
|
||
<p>Die naheliegende Antwort — den Durchschnitt — ist nachweislich falsch:</p>
|
||
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>nachfrage <span class="op">=</span> np.array([<span class="dv">104</span>, <span class="dv">138</span>, <span class="dv">96</span>, <span class="dv">151</span>, <span class="dv">118</span>, <span class="dv">127</span>, <span class="dv">143</span>, <span class="dv">109</span>, <span class="dv">162</span>, <span class="dv">121</span>, <span class="co"># 20 Tage</span></span>
|
||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="dv">133</span>, <span class="dv">115</span>, <span class="dv">148</span>, <span class="dv">102</span>, <span class="dv">129</span>, <span class="dv">156</span>, <span class="dv">111</span>, <span class="dv">140</span>, <span class="dv">124</span>, <span class="dv">135</span>])</span>
|
||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>preis, einkauf <span class="op">=</span> <span class="fl">9.0</span>, <span class="fl">3.0</span></span>
|
||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>fehl, ueber <span class="op">=</span> preis <span class="op">-</span> einkauf, einkauf <span class="co"># 6 EUR zu wenig, 3 EUR zu viel</span></span>
|
||
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>kosten <span class="op">=</span> <span class="kw">lambda</span> menge: (fehl <span class="op">*</span> np.maximum(<span class="dv">0</span>, nachfrage <span class="op">-</span> menge)</span>
|
||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a> <span class="op">+</span> ueber <span class="op">*</span> np.maximum(<span class="dv">0</span>, menge <span class="op">-</span> nachfrage)).mean()</span>
|
||
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>erwartungswert <span class="op">=</span> <span class="bu">round</span>(nachfrage.mean())</span>
|
||
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>kritisch <span class="op">=</span> <span class="bu">round</span>(np.quantile(nachfrage, fehl <span class="op">/</span> (fehl <span class="op">+</span> ueber)))</span>
|
||
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"Erwartungswert bestellen: </span><span class="sc">{</span>erwartungswert<span class="sc">}</span><span class="ss"> Stueck -> </span><span class="sc">{</span>kosten(erwartungswert)<span class="sc">:5.2f}</span><span class="ss"> EUR/Tag"</span>)</span>
|
||
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"kritisches Quantil : </span><span class="sc">{</span>kritisch<span class="sc">}</span><span class="ss"> Stueck -> </span><span class="sc">{</span>kosten(kritisch)<span class="sc">:5.2f}</span><span class="ss"> EUR/Tag"</span>)</span>
|
||
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="ss">f"bestmoegliche feste Menge: </span><span class="sc">{</span><span class="bu">int</span>(np.argmin([kosten(m) <span class="cf">for</span> m <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">200</span>)]))<span class="sc">}</span><span class="ss"> Stueck"</span></span>
|
||
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a> <span class="ss">f" -> </span><span class="sc">{</span><span class="bu">min</span>(kosten(m) <span class="cf">for</span> m <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">200</span>))<span class="sc">:5.2f}</span><span class="ss"> EUR/Tag"</span>)</span></code></pre></div>
|
||
<p><strong>Ausgabe:</strong></p>
|
||
<pre><code>Erwartungswert bestellen: 128 Stueck -> 69.45 EUR/Tag
|
||
kritisches Quantil : 137 Stueck -> 62.25 EUR/Tag
|
||
bestmoegliche feste Menge: 138 Stueck -> 62.10 EUR/Tag</code></pre>
|
||
</blockquote>
|
||
</div>
|
||
<p><strong>Und jetzt der Punkt.</strong> Der Durchschnitt ist perfekt bestimmt — es ist der Mittelwert derselben Daten, aus denen auch das Quantil kommt. Trotzdem kostet er <strong>7,20 € je Tag mehr</strong>, gut 10 %.</p>
|
||
<p>Der Grund steht in den Preisen: Ein fehlendes Brot kostet doppelt so viel wie ein übriges. Bei asymmetrischen Kosten liegt die optimale Menge nicht in der Mitte der Verteilung, sondern beim <strong>kritischen Verhältnis</strong> <span class="math inline">c_-/(c_- + c_+) = 6/9 = 66{,}7\,\%</span> — das kennen Sie aus <a href="unsicherheit.html#kap-unsicherheit">Kapitel 12</a>.</p>
|
||
<p>Bemerkenswert ist die dritte Zeile: Die Quantilregel trifft mit 137 fast genau die beste überhaupt mögliche feste Menge (138). Sie ist nicht ungefähr richtig, sie ist richtig.</p>
|
||
<blockquote>
|
||
<p><strong>🎯 Merksatz</strong> Eine Prognose ist kein Selbstzweck. Sie liefert eine Zahl, die in eine Entscheidung eingeht — und <strong>welche</strong> Zahl das sein muss, bestimmt die Entscheidung, nicht die Statistik.</p>
|
||
</blockquote>
|
||
<p><strong>Warum funktioniert das?</strong> Weil die Kostenfunktion des Newsvendors geknickt und unsymmetrisch ist. Der Mittelwert minimiert den <em>quadratischen</em> Fehler; die Kosten sind aber stückweise linear mit verschiedenen Steigungen nach oben und unten. Zwei verschiedene Zielfunktionen haben zwei verschiedene Optima — das ist kein Paradox, sondern Arithmetik.</p>
|
||
<hr />
|
||
<h2 id="sec:prognose-lernziele">15.2 Lernziele</h2>
|
||
<p>Nach diesem Kapitel können Sie …</p>
|
||
<ol type="1">
|
||
<li>… die Zweiteilung <em>predict</em> / <em>optimize</em> benennen und sagen, wo dabei Information verloren geht.</li>
|
||
<li>… begründen, warum das MSE-beste Modell nicht das kostenbeste sein muss.</li>
|
||
<li>… die richtige Prognosegröße aus der Entscheidung ableiten statt aus Gewohnheit.</li>
|
||
<li>… erklären, warum ein pauschaler Sicherheitszuschlag schwächer ist als ein Modell, das die Unsicherheit aus den Merkmalen liest.</li>
|
||
<li>… Prognosemodelle an <strong>Entscheidungskosten</strong> messen — und wissen, wie viele Testdaten ein solcher Vergleich braucht.</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="sec:prognose-naht">15.3 Die Naht zwischen zwei Abteilungen</h2>
|
||
<p>In fast jedem Unternehmen sieht der Ablauf so aus:</p>
|
||
<pre><code> Verkaufsdaten -> [ PROGNOSE ] -> Nachfrageschätzung -> [ PLANUNG ] -> Bestellung
|
||
Data Science Disposition</code></pre>
|
||
<p>Beide Seiten arbeiten sorgfältig. Die Prognoseabteilung optimiert ihr Modell auf ein <strong>Fehlermaß</strong> — meist den mittleren quadratischen Fehler (MSE) oder MAPE — und berichtet stolz eine Verbesserung von 12 %. Die Disposition nimmt die Zahl entgegen und rechnet ihre Bestellmenge aus.</p>
|
||
<p>Der Fehler steckt nicht in einer der beiden Hälften, sondern in der Naht:</p>
|
||
<blockquote>
|
||
<p><strong>📖 Definition: Predict-then-Optimize</strong></p>
|
||
<p>Das übliche zweistufige Vorgehen: erst eine unbekannte Größe schätzen, dann mit der Schätzung optimieren, als wäre sie die Wahrheit.</p>
|
||
<p>Das Problem: Die erste Stufe wird auf ein <strong>statistisches</strong> Maß trainiert, die zweite erzeugt <strong>ökonomische</strong> Kosten. Niemand garantiert, dass ein besseres statistisches Maß zu geringeren Kosten führt — und in diesem Kapitel ist es nachweislich umgekehrt.</p>
|
||
</blockquote>
|
||
<blockquote>
|
||
<p><strong>⚠️ Warum das nicht auffällt</strong></p>
|
||
<p>Beide Abteilungen erfüllen ihre Kennzahl. Die Prognose wird besser (MSE sinkt), die Disposition arbeitet korrekt (sie wendet die Formel richtig an). Es gibt keinen Ort, an dem der Verlust sichtbar würde — außer man misst die Entscheidungskosten, und das ist niemandes Kennzahl.</p>
|
||
<p>Das ist dieselbe Struktur wie in <a href="testing.html#sec:testing-denkfehler">Abschnitt 23.9</a>: Der Fehler entsteht zwischen zwei Zuständigkeiten und wird deshalb von keiner Prüfung gefunden, die innerhalb einer der beiden liegt.</p>
|
||
</blockquote>
|
||
<hr />
|
||
<h2 id="sec:prognose-programm">15.4 Das Programm</h2>
|
||
<p>Dieselbe Bäckerei, aber mit Merkmalen: Wochentag, Temperatur, Aktionstage. Die Nachfrage muss jetzt <strong>modelliert</strong> werden.</p>
|
||
<p>Eine Eigenschaft der Daten ist dabei entscheidend und in der Praxis der Normalfall: An Aktionstagen ist die Nachfrage nicht nur höher, sondern auch <strong>viel unsicherer</strong> (heteroskedastisch).</p>
|
||
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co">#!/usr/bin/env python3</span></span>
|
||
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Predict_then_Optimize.py</span></span>
|
||
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="co">"""</span></span>
|
||
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="co">Kapitel Prognose: Die bessere Prognose trifft die schlechtere Entscheidung.</span></span>
|
||
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="co">Eine Baeckerei muss jeden Abend entscheiden, wie viel sie fuer den naechsten Tag</span></span>
|
||
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="co">ansetzt. Zu wenig kostet die Marge des entgangenen Verkaufs, zu viel kostet den</span></span>
|
||
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="co">Einkaufspreis der Retoure. Das ist das Newsvendor-Problem aus dem Kapitel</span></span>
|
||
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="co">Unsicherheit - nur dass die Nachfrage diesmal nicht aus einer Verteilung kommt,</span></span>
|
||
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a><span class="co">sondern PROGNOSTIZIERT werden muss: aus Wochentag, Temperatur und Aktionstagen.</span></span>
|
||
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="co">Damit zerfaellt die Aufgabe in zwei Schritte, und genau an der Naht entsteht der</span></span>
|
||
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="co">Fehler, um den es hier geht:</span></span>
|
||
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a><span class="co"> PREDICT ein Modell schaetzt die Nachfrage</span></span>
|
||
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a><span class="co"> OPTIMIZE daraus wird eine Bestellmenge</span></span>
|
||
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a><span class="co">Der Prognostiker optimiert seinen Modellfehler, meist den MSE. Der Planer traegt</span></span>
|
||
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a><span class="co">die Kosten. Beide messen etwas anderes - und die beiden Masse widersprechen</span></span>
|
||
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a><span class="co">einander. Das Programm zeigt:</span></span>
|
||
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a><span class="co"> 1. Vier Verfahren, verglichen nach MSE UND nach Entscheidungskosten. Das</span></span>
|
||
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a><span class="co"> Verfahren mit dem BESTEN MSE hat die HOECHSTEN Kosten.</span></span>
|
||
<span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a><span class="co"> 2. Warum ein pauschaler Sicherheitszuschlag zu kurz greift - die Streuung der</span></span>
|
||
<span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></a><span class="co"> Nachfrage haengt selbst von den Merkmalen ab.</span></span>
|
||
<span id="cb4-27"><a href="#cb4-27" aria-hidden="true" tabindex="-1"></a><span class="co"> 3. Eine Messfalle, in die der Autor dieses Programms zuerst selbst getappt</span></span>
|
||
<span id="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></a><span class="co"> ist: Bei kurzen Testzeitraeumen ist der MSE-Vergleich nicht stabil.</span></span>
|
||
<span id="cb4-29"><a href="#cb4-29" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-30"><a href="#cb4-30" aria-hidden="true" tabindex="-1"></a><span class="co">Benoetigt: numpy, scipy, scikit-learn</span></span>
|
||
<span id="cb4-31"><a href="#cb4-31" aria-hidden="true" tabindex="-1"></a><span class="co">"""</span></span>
|
||
<span id="cb4-32"><a href="#cb4-32" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-33"><a href="#cb4-33" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> __future__ <span class="im">import</span> annotations</span>
|
||
<span id="cb4-34"><a href="#cb4-34" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-35"><a href="#cb4-35" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span>
|
||
<span id="cb4-36"><a href="#cb4-36" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> scipy.stats <span class="im">import</span> norm</span>
|
||
<span id="cb4-37"><a href="#cb4-37" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> sklearn.linear_model <span class="im">import</span> LinearRegression, QuantileRegressor</span>
|
||
<span id="cb4-38"><a href="#cb4-38" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-39"><a href="#cb4-39" aria-hidden="true" tabindex="-1"></a>VERKAUFSPREIS <span class="op">=</span> <span class="fl">9.0</span></span>
|
||
<span id="cb4-40"><a href="#cb4-40" aria-hidden="true" tabindex="-1"></a>EINKAUFSPREIS <span class="op">=</span> <span class="fl">3.0</span></span>
|
||
<span id="cb4-41"><a href="#cb4-41" aria-hidden="true" tabindex="-1"></a>KOSTEN_FEHLMENGE <span class="op">=</span> VERKAUFSPREIS <span class="op">-</span> EINKAUFSPREIS <span class="co"># entgangene Marge: 6 EUR</span></span>
|
||
<span id="cb4-42"><a href="#cb4-42" aria-hidden="true" tabindex="-1"></a>KOSTEN_UEBERHANG <span class="op">=</span> EINKAUFSPREIS <span class="co"># Retoure: 3 EUR</span></span>
|
||
<span id="cb4-43"><a href="#cb4-43" aria-hidden="true" tabindex="-1"></a>KRITISCHES_VERHAELTNIS <span class="op">=</span> KOSTEN_FEHLMENGE <span class="op">/</span> (KOSTEN_FEHLMENGE <span class="op">+</span> KOSTEN_UEBERHANG)</span>
|
||
<span id="cb4-44"><a href="#cb4-44" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-45"><a href="#cb4-45" aria-hidden="true" tabindex="-1"></a>TAGE <span class="op">=</span> <span class="dv">5000</span> <span class="co"># Simulation, siehe Hinweis unten</span></span>
|
||
<span id="cb4-46"><a href="#cb4-46" aria-hidden="true" tabindex="-1"></a>TRAINING <span class="op">=</span> <span class="dv">1000</span></span>
|
||
<span id="cb4-47"><a href="#cb4-47" aria-hidden="true" tabindex="-1"></a>SAAT <span class="op">=</span> <span class="dv">11</span></span>
|
||
<span id="cb4-48"><a href="#cb4-48" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-49"><a href="#cb4-49" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-50"><a href="#cb4-50" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> erzeuge_daten(tage: <span class="bu">int</span> <span class="op">=</span> TAGE, saat: <span class="bu">int</span> <span class="op">=</span> SAAT):</span>
|
||
<span id="cb4-51"><a href="#cb4-51" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Taegliche Nachfrage mit Wochentag, Temperatur und Aktionstagen.</span></span>
|
||
<span id="cb4-52"><a href="#cb4-52" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-53"><a href="#cb4-53" aria-hidden="true" tabindex="-1"></a><span class="co"> Die entscheidende Eigenschaft steckt in 'streuung': An Aktionstagen ist die</span></span>
|
||
<span id="cb4-54"><a href="#cb4-54" aria-hidden="true" tabindex="-1"></a><span class="co"> Nachfrage nicht nur hoeher, sondern auch viel UNSICHERER. Solche</span></span>
|
||
<span id="cb4-55"><a href="#cb4-55" aria-hidden="true" tabindex="-1"></a><span class="co"> heteroskedastischen Daten sind der Normalfall - und der Grund, warum ein</span></span>
|
||
<span id="cb4-56"><a href="#cb4-56" aria-hidden="true" tabindex="-1"></a><span class="co"> pauschaler Sicherheitszuschlag nicht genuegt.</span></span>
|
||
<span id="cb4-57"><a href="#cb4-57" aria-hidden="true" tabindex="-1"></a><span class="co"> """</span></span>
|
||
<span id="cb4-58"><a href="#cb4-58" aria-hidden="true" tabindex="-1"></a> rng <span class="op">=</span> np.random.default_rng(saat)</span>
|
||
<span id="cb4-59"><a href="#cb4-59" aria-hidden="true" tabindex="-1"></a> wochentag <span class="op">=</span> np.arange(tage) <span class="op">%</span> <span class="dv">7</span></span>
|
||
<span id="cb4-60"><a href="#cb4-60" aria-hidden="true" tabindex="-1"></a> temperatur <span class="op">=</span> (<span class="dv">12</span> <span class="op">+</span> <span class="dv">10</span> <span class="op">*</span> np.sin(<span class="dv">2</span> <span class="op">*</span> np.pi <span class="op">*</span> np.arange(tage) <span class="op">/</span> <span class="dv">365</span>)</span>
|
||
<span id="cb4-61"><a href="#cb4-61" aria-hidden="true" tabindex="-1"></a> <span class="op">+</span> rng.normal(<span class="dv">0</span>, <span class="dv">3</span>, tage))</span>
|
||
<span id="cb4-62"><a href="#cb4-62" aria-hidden="true" tabindex="-1"></a> aktion <span class="op">=</span> (rng.random(tage) <span class="op"><</span> <span class="fl">0.15</span>).astype(<span class="bu">float</span>)</span>
|
||
<span id="cb4-63"><a href="#cb4-63" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-64"><a href="#cb4-64" aria-hidden="true" tabindex="-1"></a> merkmale <span class="op">=</span> np.column_stack([np.eye(<span class="dv">7</span>)[wochentag][:, <span class="dv">1</span>:], temperatur, aktion])</span>
|
||
<span id="cb4-65"><a href="#cb4-65" aria-hidden="true" tabindex="-1"></a> erwartung <span class="op">=</span> (<span class="dv">120</span></span>
|
||
<span id="cb4-66"><a href="#cb4-66" aria-hidden="true" tabindex="-1"></a> <span class="op">+</span> np.eye(<span class="dv">7</span>)[wochentag] <span class="op">@</span> np.array([<span class="dv">0</span>, <span class="dv">10</span>, <span class="dv">12</span>, <span class="dv">14</span>, <span class="dv">18</span>, <span class="dv">35</span>, <span class="op">-</span><span class="dv">40</span>])</span>
|
||
<span id="cb4-67"><a href="#cb4-67" aria-hidden="true" tabindex="-1"></a> <span class="op">+</span> <span class="fl">1.8</span> <span class="op">*</span> temperatur <span class="op">+</span> <span class="dv">45</span> <span class="op">*</span> aktion)</span>
|
||
<span id="cb4-68"><a href="#cb4-68" aria-hidden="true" tabindex="-1"></a> streuung <span class="op">=</span> <span class="dv">8</span> <span class="op">+</span> <span class="dv">22</span> <span class="op">*</span> aktion</span>
|
||
<span id="cb4-69"><a href="#cb4-69" aria-hidden="true" tabindex="-1"></a> nachfrage <span class="op">=</span> np.maximum(<span class="fl">0.0</span>, erwartung <span class="op">+</span> rng.normal(<span class="dv">0</span>, <span class="dv">1</span>, tage) <span class="op">*</span> streuung)</span>
|
||
<span id="cb4-70"><a href="#cb4-70" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> merkmale, nachfrage, aktion</span>
|
||
<span id="cb4-71"><a href="#cb4-71" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-72"><a href="#cb4-72" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-73"><a href="#cb4-73" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> tageskosten(bestellung: np.ndarray, nachfrage: np.ndarray) <span class="op">-></span> <span class="bu">float</span>:</span>
|
||
<span id="cb4-74"><a href="#cb4-74" aria-hidden="true" tabindex="-1"></a> <span class="co">"""Die Zahl, auf die es ankommt - und die kein Prognosemass kennt."""</span></span>
|
||
<span id="cb4-75"><a href="#cb4-75" aria-hidden="true" tabindex="-1"></a> fehlmenge <span class="op">=</span> np.maximum(<span class="fl">0.0</span>, nachfrage <span class="op">-</span> bestellung)</span>
|
||
<span id="cb4-76"><a href="#cb4-76" aria-hidden="true" tabindex="-1"></a> ueberhang <span class="op">=</span> np.maximum(<span class="fl">0.0</span>, bestellung <span class="op">-</span> nachfrage)</span>
|
||
<span id="cb4-77"><a href="#cb4-77" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> <span class="bu">float</span>((KOSTEN_FEHLMENGE <span class="op">*</span> fehlmenge</span>
|
||
<span id="cb4-78"><a href="#cb4-78" aria-hidden="true" tabindex="-1"></a> <span class="op">+</span> KOSTEN_UEBERHANG <span class="op">*</span> ueberhang).mean())</span>
|
||
<span id="cb4-79"><a href="#cb4-79" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-80"><a href="#cb4-80" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-81"><a href="#cb4-81" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="va">__name__</span> <span class="op">==</span> <span class="st">"__main__"</span>:</span>
|
||
<span id="cb4-82"><a href="#cb4-82" aria-hidden="true" tabindex="-1"></a> merkmale, nachfrage, aktion <span class="op">=</span> erzeuge_daten()</span>
|
||
<span id="cb4-83"><a href="#cb4-83" aria-hidden="true" tabindex="-1"></a> lernen <span class="op">=</span> <span class="bu">slice</span>(<span class="dv">0</span>, TRAINING)</span>
|
||
<span id="cb4-84"><a href="#cb4-84" aria-hidden="true" tabindex="-1"></a> pruefen <span class="op">=</span> <span class="bu">slice</span>(TRAINING, TAGE)</span>
|
||
<span id="cb4-85"><a href="#cb4-85" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-86"><a href="#cb4-86" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb4-87"><a href="#cb4-87" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" DIE BESSERE PROGNOSE TRIFFT DIE SCHLECHTERE ENTSCHEIDUNG"</span>)</span>
|
||
<span id="cb4-88"><a href="#cb4-88" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb4-89"><a href="#cb4-89" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Verkaufspreis </span><span class="sc">{</span>VERKAUFSPREIS<span class="sc">:.0f}</span><span class="ss"> EUR, Einkauf </span><span class="sc">{</span>EINKAUFSPREIS<span class="sc">:.0f}</span><span class="ss"> EUR."</span>)</span>
|
||
<span id="cb4-90"><a href="#cb4-90" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Fehlmenge kostet </span><span class="sc">{</span>KOSTEN_FEHLMENGE<span class="sc">:.0f}</span><span class="ss"> EUR, Ueberhang "</span></span>
|
||
<span id="cb4-91"><a href="#cb4-91" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>KOSTEN_UEBERHANG<span class="sc">:.0f}</span><span class="ss"> EUR je Stueck."</span>)</span>
|
||
<span id="cb4-92"><a href="#cb4-92" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"Kritisches Verhaeltnis: </span><span class="sc">{</span>KRITISCHES_VERHAELTNIS<span class="sc">:.3f}</span><span class="ss"> - der Planer sollte "</span></span>
|
||
<span id="cb4-93"><a href="#cb4-93" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"also das"</span>)</span>
|
||
<span id="cb4-94"><a href="#cb4-94" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="sc">{</span>KRITISCHES_VERHAELTNIS<span class="sc">:.1%}</span><span class="ss">-Quantil der Nachfrage bestellen, nicht ihren "</span></span>
|
||
<span id="cb4-95"><a href="#cb4-95" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"Erwartungswert."</span>)</span>
|
||
<span id="cb4-96"><a href="#cb4-96" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss">Training: Tag 1 bis </span><span class="sc">{</span>TRAINING<span class="sc">}</span><span class="ss">. Bewertung: die restlichen "</span></span>
|
||
<span id="cb4-97"><a href="#cb4-97" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>TAGE <span class="op">-</span> TRAINING<span class="sc">}</span><span class="ss"> Tage.</span><span class="ch">\n</span><span class="ss">"</span>)</span>
|
||
<span id="cb4-98"><a href="#cb4-98" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-99"><a href="#cb4-99" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Die vier Verfahren ----------------------------------------------</span></span>
|
||
<span id="cb4-100"><a href="#cb4-100" aria-hidden="true" tabindex="-1"></a> kleinste_quadrate <span class="op">=</span> LinearRegression().fit(merkmale[lernen], nachfrage[lernen])</span>
|
||
<span id="cb4-101"><a href="#cb4-101" aria-hidden="true" tabindex="-1"></a> punktprognose <span class="op">=</span> kleinste_quadrate.predict(merkmale[pruefen])</span>
|
||
<span id="cb4-102"><a href="#cb4-102" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-103"><a href="#cb4-103" aria-hidden="true" tabindex="-1"></a> restfehler <span class="op">=</span> nachfrage[lernen] <span class="op">-</span> kleinste_quadrate.predict(merkmale[lernen])</span>
|
||
<span id="cb4-104"><a href="#cb4-104" aria-hidden="true" tabindex="-1"></a> pauschalzuschlag <span class="op">=</span> norm.ppf(KRITISCHES_VERHAELTNIS) <span class="op">*</span> restfehler.std()</span>
|
||
<span id="cb4-105"><a href="#cb4-105" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-106"><a href="#cb4-106" aria-hidden="true" tabindex="-1"></a> <span class="co"># Ein Zuschlag, der nicht aus der Normalverteilung kommt, sondern direkt</span></span>
|
||
<span id="cb4-107"><a href="#cb4-107" aria-hidden="true" tabindex="-1"></a> <span class="co"># auf den Trainingsdaten die Kosten minimiert.</span></span>
|
||
<span id="cb4-108"><a href="#cb4-108" aria-hidden="true" tabindex="-1"></a> kandidaten <span class="op">=</span> np.linspace(<span class="op">-</span><span class="fl">10.0</span>, <span class="fl">30.0</span>, <span class="dv">401</span>)</span>
|
||
<span id="cb4-109"><a href="#cb4-109" aria-hidden="true" tabindex="-1"></a> trainingsprognose <span class="op">=</span> kleinste_quadrate.predict(merkmale[lernen])</span>
|
||
<span id="cb4-110"><a href="#cb4-110" aria-hidden="true" tabindex="-1"></a> kostenzuschlag <span class="op">=</span> <span class="bu">float</span>(kandidaten[np.argmin(</span>
|
||
<span id="cb4-111"><a href="#cb4-111" aria-hidden="true" tabindex="-1"></a> [tageskosten(trainingsprognose <span class="op">+</span> z, nachfrage[lernen]) <span class="cf">for</span> z <span class="kw">in</span> kandidaten])])</span>
|
||
<span id="cb4-112"><a href="#cb4-112" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-113"><a href="#cb4-113" aria-hidden="true" tabindex="-1"></a> <span class="co"># Und das Verfahren, das von vornherein das richtige Quantil schaetzt.</span></span>
|
||
<span id="cb4-114"><a href="#cb4-114" aria-hidden="true" tabindex="-1"></a> quantilmodell <span class="op">=</span> QuantileRegressor(quantile<span class="op">=</span>KRITISCHES_VERHAELTNIS,</span>
|
||
<span id="cb4-115"><a href="#cb4-115" aria-hidden="true" tabindex="-1"></a> alpha<span class="op">=</span><span class="fl">0.0</span>, solver<span class="op">=</span><span class="st">"highs"</span>)</span>
|
||
<span id="cb4-116"><a href="#cb4-116" aria-hidden="true" tabindex="-1"></a> quantilmodell.fit(merkmale[lernen], nachfrage[lernen])</span>
|
||
<span id="cb4-117"><a href="#cb4-117" aria-hidden="true" tabindex="-1"></a> quantilprognose <span class="op">=</span> quantilmodell.predict(merkmale[pruefen])</span>
|
||
<span id="cb4-118"><a href="#cb4-118" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-119"><a href="#cb4-119" aria-hidden="true" tabindex="-1"></a> verfahren <span class="op">=</span> [</span>
|
||
<span id="cb4-120"><a href="#cb4-120" aria-hidden="true" tabindex="-1"></a> (<span class="st">"bestelle die Punktprognose"</span>, punktprognose, punktprognose),</span>
|
||
<span id="cb4-121"><a href="#cb4-121" aria-hidden="true" tabindex="-1"></a> (<span class="st">"+ Zuschlag aus der Normalverteilung"</span>,</span>
|
||
<span id="cb4-122"><a href="#cb4-122" aria-hidden="true" tabindex="-1"></a> punktprognose, punktprognose <span class="op">+</span> pauschalzuschlag),</span>
|
||
<span id="cb4-123"><a href="#cb4-123" aria-hidden="true" tabindex="-1"></a> (<span class="st">"+ Zuschlag auf Kosten trainiert"</span>,</span>
|
||
<span id="cb4-124"><a href="#cb4-124" aria-hidden="true" tabindex="-1"></a> punktprognose, punktprognose <span class="op">+</span> kostenzuschlag),</span>
|
||
<span id="cb4-125"><a href="#cb4-125" aria-hidden="true" tabindex="-1"></a> (<span class="st">"Quantilregression aufs kritische Quantil"</span>,</span>
|
||
<span id="cb4-126"><a href="#cb4-126" aria-hidden="true" tabindex="-1"></a> quantilprognose, quantilprognose),</span>
|
||
<span id="cb4-127"><a href="#cb4-127" aria-hidden="true" tabindex="-1"></a> ]</span>
|
||
<span id="cb4-128"><a href="#cb4-128" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-129"><a href="#cb4-129" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span><span class="st">'Verfahren'</span><span class="sc">:<42}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'MSE'</span><span class="sc">:>9}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Kosten/Tag'</span><span class="sc">:>12}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'gegen Zeile 1'</span><span class="sc">:>14}</span><span class="ss">"</span>)</span>
|
||
<span id="cb4-130"><a href="#cb4-130" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" "</span> <span class="op">+</span> <span class="st">"-"</span> <span class="op">*</span> <span class="dv">80</span>)</span>
|
||
<span id="cb4-131"><a href="#cb4-131" aria-hidden="true" tabindex="-1"></a> ergebnisse <span class="op">=</span> {}</span>
|
||
<span id="cb4-132"><a href="#cb4-132" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> name, prognose, bestellung <span class="kw">in</span> verfahren:</span>
|
||
<span id="cb4-133"><a href="#cb4-133" aria-hidden="true" tabindex="-1"></a> mse <span class="op">=</span> <span class="bu">float</span>(((prognose <span class="op">-</span> nachfrage[pruefen]) <span class="op">**</span> <span class="dv">2</span>).mean())</span>
|
||
<span id="cb4-134"><a href="#cb4-134" aria-hidden="true" tabindex="-1"></a> kosten <span class="op">=</span> tageskosten(bestellung, nachfrage[pruefen])</span>
|
||
<span id="cb4-135"><a href="#cb4-135" aria-hidden="true" tabindex="-1"></a> ergebnisse[name] <span class="op">=</span> (mse, kosten)</span>
|
||
<span id="cb4-136"><a href="#cb4-136" aria-hidden="true" tabindex="-1"></a> basis <span class="op">=</span> ergebnisse[verfahren[<span class="dv">0</span>][<span class="dv">0</span>]][<span class="dv">1</span>]</span>
|
||
<span id="cb4-137"><a href="#cb4-137" aria-hidden="true" tabindex="-1"></a> vergleich <span class="op">=</span> <span class="st">""</span> <span class="cf">if</span> name <span class="op">==</span> verfahren[<span class="dv">0</span>][<span class="dv">0</span>] <span class="cf">else</span> <span class="ss">f"</span><span class="sc">{</span>(kosten <span class="op">-</span> basis) <span class="op">/</span> basis<span class="sc">:+13.1%}</span><span class="ss">"</span></span>
|
||
<span id="cb4-138"><a href="#cb4-138" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span>name<span class="sc">:<42}</span><span class="ss"> </span><span class="sc">{</span>mse<span class="sc">:>9.1f}</span><span class="ss"> </span><span class="sc">{</span>kosten<span class="sc">:>10.2f}</span><span class="ss"> EUR </span><span class="sc">{</span>vergleich<span class="sc">:>14}</span><span class="ss">"</span>)</span>
|
||
<span id="cb4-139"><a href="#cb4-139" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-140"><a href="#cb4-140" aria-hidden="true" tabindex="-1"></a> bester_mse <span class="op">=</span> <span class="bu">min</span>(ergebnisse, key<span class="op">=</span><span class="kw">lambda</span> k: ergebnisse[k][<span class="dv">0</span>])</span>
|
||
<span id="cb4-141"><a href="#cb4-141" aria-hidden="true" tabindex="-1"></a> beste_kosten <span class="op">=</span> <span class="bu">min</span>(ergebnisse, key<span class="op">=</span><span class="kw">lambda</span> k: ergebnisse[k][<span class="dv">1</span>])</span>
|
||
<span id="cb4-142"><a href="#cb4-142" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> bester MSE: </span><span class="sc">{</span>bester_mse<span class="sc">}</span><span class="ss">"</span>)</span>
|
||
<span id="cb4-143"><a href="#cb4-143" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" beste Kosten: </span><span class="sc">{</span>beste_kosten<span class="sc">}</span><span class="ss">"</span>)</span>
|
||
<span id="cb4-144"><a href="#cb4-144" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> Das Verfahren mit dem besten MSE hat die HOECHSTEN Kosten, und das"</span>)</span>
|
||
<span id="cb4-145"><a href="#cb4-145" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Verfahren mit den besten Kosten hat einen um "</span></span>
|
||
<span id="cb4-146"><a href="#cb4-146" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"</span><span class="sc">{</span>(ergebnisse[beste_kosten][<span class="dv">0</span>] <span class="op">/</span> ergebnisse[bester_mse][<span class="dv">0</span>] <span class="op">-</span> <span class="dv">1</span>)<span class="sc">:.0%}</span><span class="ss"> SCHLECHTEREN MSE."</span>)</span>
|
||
<span id="cb4-147"><a href="#cb4-147" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Wer Prognosemodelle nach MSE auswaehlt, waehlt hier das falsche."</span>)</span>
|
||
<span id="cb4-148"><a href="#cb4-148" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-149"><a href="#cb4-149" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Warum der pauschale Zuschlag zu kurz greift ---------------------</span></span>
|
||
<span id="cb4-150"><a href="#cb4-150" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">"</span> <span class="op">+</span> <span class="st">"-"</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb4-151"><a href="#cb4-151" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Warum ein pauschaler Zuschlag nicht genuegt</span><span class="ch">\n</span><span class="st">"</span>)</span>
|
||
<span id="cb4-152"><a href="#cb4-152" aria-hidden="true" tabindex="-1"></a> ist_aktion <span class="op">=</span> aktion[pruefen] <span class="op">></span> <span class="fl">0.5</span></span>
|
||
<span id="cb4-153"><a href="#cb4-153" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span><span class="st">'Verfahren'</span><span class="sc">:<42}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'normale Tage'</span><span class="sc">:>14}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'Aktionstage'</span><span class="sc">:>14}</span><span class="ss">"</span>)</span>
|
||
<span id="cb4-154"><a href="#cb4-154" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" "</span> <span class="op">+</span> <span class="st">"-"</span> <span class="op">*</span> <span class="dv">74</span>)</span>
|
||
<span id="cb4-155"><a href="#cb4-155" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> name, _, bestellung <span class="kw">in</span> verfahren:</span>
|
||
<span id="cb4-156"><a href="#cb4-156" aria-hidden="true" tabindex="-1"></a> normal <span class="op">=</span> tageskosten(bestellung[<span class="op">~</span>ist_aktion], nachfrage[pruefen][<span class="op">~</span>ist_aktion])</span>
|
||
<span id="cb4-157"><a href="#cb4-157" aria-hidden="true" tabindex="-1"></a> aktionstag <span class="op">=</span> tageskosten(bestellung[ist_aktion], nachfrage[pruefen][ist_aktion])</span>
|
||
<span id="cb4-158"><a href="#cb4-158" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span>name<span class="sc">:<42}</span><span class="ss"> </span><span class="sc">{</span>normal<span class="sc">:>10.2f}</span><span class="ss"> EUR </span><span class="sc">{</span>aktionstag<span class="sc">:>10.2f}</span><span class="ss"> EUR"</span>)</span>
|
||
<span id="cb4-159"><a href="#cb4-159" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-160"><a href="#cb4-160" aria-hidden="true" tabindex="-1"></a> <span class="co"># Nachgerechnet statt behauptet: Welcher Zuschlag waere je Tagesart richtig?</span></span>
|
||
<span id="cb4-161"><a href="#cb4-161" aria-hidden="true" tabindex="-1"></a> aktion_training <span class="op">=</span> aktion[lernen] <span class="op">></span> <span class="fl">0.5</span></span>
|
||
<span id="cb4-162"><a href="#cb4-162" aria-hidden="true" tabindex="-1"></a> z <span class="op">=</span> norm.ppf(KRITISCHES_VERHAELTNIS)</span>
|
||
<span id="cb4-163"><a href="#cb4-163" aria-hidden="true" tabindex="-1"></a> richtig_normal <span class="op">=</span> z <span class="op">*</span> restfehler[<span class="op">~</span>aktion_training].std()</span>
|
||
<span id="cb4-164"><a href="#cb4-164" aria-hidden="true" tabindex="-1"></a> richtig_aktion <span class="op">=</span> z <span class="op">*</span> restfehler[aktion_training].std()</span>
|
||
<span id="cb4-165"><a href="#cb4-165" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> Der pauschale Zuschlag betraegt </span><span class="sc">{</span>pauschalzuschlag<span class="sc">:.1f}</span><span class="ss"> Stueck. Aus den"</span>)</span>
|
||
<span id="cb4-166"><a href="#cb4-166" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Trainingsresten getrennt nach Tagesart waere richtig:"</span>)</span>
|
||
<span id="cb4-167"><a href="#cb4-167" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" normale Tage : </span><span class="sc">{</span>richtig_normal<span class="sc">:5.1f}</span><span class="ss"> Stueck"</span>)</span>
|
||
<span id="cb4-168"><a href="#cb4-168" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Aktionstage : </span><span class="sc">{</span>richtig_aktion<span class="sc">:5.1f}</span><span class="ss"> Stueck"</span>)</span>
|
||
<span id="cb4-169"><a href="#cb4-169" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Ein Zuschlag fuer alle Tage kann nur einen Mittelweg treffen - hier"</span>)</span>
|
||
<span id="cb4-170"><a href="#cb4-170" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" ist er an normalen Tagen </span><span class="sc">{</span>pauschalzuschlag <span class="op">/</span> richtig_normal<span class="sc">:.1f}</span><span class="ss">-mal zu gross und an"</span>)</span>
|
||
<span id="cb4-171"><a href="#cb4-171" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Aktionstagen nur </span><span class="sc">{</span>pauschalzuschlag <span class="op">/</span> richtig_aktion<span class="sc">:.0%}</span><span class="ss"> dessen, was noetig waere."</span>)</span>
|
||
<span id="cb4-172"><a href="#cb4-172" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f"</span><span class="ch">\n</span><span class="ss"> Die Quantilregression schaetzt das </span><span class="sc">{</span>KRITISCHES_VERHAELTNIS<span class="sc">:.1%}</span><span class="ss">-Quantil "</span></span>
|
||
<span id="cb4-173"><a href="#cb4-173" aria-hidden="true" tabindex="-1"></a> <span class="ss">f"direkt aus den"</span>)</span>
|
||
<span id="cb4-174"><a href="#cb4-174" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" Merkmalen und darf deshalb an verschiedenen Tagen verschieden weit"</span>)</span>
|
||
<span id="cb4-175"><a href="#cb4-175" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" ueber dem Erwartungswert liegen. Genau das ist der Unterschied"</span>)</span>
|
||
<span id="cb4-176"><a href="#cb4-176" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" zwischen 'ein Modell und danach eine Formel' und 'ein Modell, das"</span>)</span>
|
||
<span id="cb4-177"><a href="#cb4-177" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" weiss, wofuer es gebraucht wird'."</span>)</span>
|
||
<span id="cb4-178"><a href="#cb4-178" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-179"><a href="#cb4-179" aria-hidden="true" tabindex="-1"></a> <span class="co"># --- Die Messfalle ---------------------------------------------------</span></span>
|
||
<span id="cb4-180"><a href="#cb4-180" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">"</span> <span class="op">+</span> <span class="st">"-"</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb4-181"><a href="#cb4-181" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Eine Messfalle, in die der Autor zuerst selbst getappt ist</span><span class="ch">\n</span><span class="st">"</span>)</span>
|
||
<span id="cb4-182"><a href="#cb4-182" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Der erste Entwurf dieses Programms bewertete auf 230 Testtagen - ein"</span>)</span>
|
||
<span id="cb4-183"><a href="#cb4-183" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" realistischer Zeitraum. Dort hatte die Quantilregression den BESSEREN"</span>)</span>
|
||
<span id="cb4-184"><a href="#cb4-184" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" MSE, und die ganze Aussage des Kapitels stand auf dem Kopf."</span>)</span>
|
||
<span id="cb4-185"><a href="#cb4-185" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st"> Wie oft das passiert, laesst sich ausmessen:</span><span class="ch">\n</span><span class="st">"</span>)</span>
|
||
<span id="cb4-186"><a href="#cb4-186" aria-hidden="true" tabindex="-1"></a> rng <span class="op">=</span> np.random.default_rng(<span class="dv">0</span>)</span>
|
||
<span id="cb4-187"><a href="#cb4-187" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span><span class="st">'Testfenster'</span><span class="sc">:>14}</span><span class="ss"> </span><span class="sc">{</span><span class="st">'QR sieht MSE-besser aus'</span><span class="sc">:>26}</span><span class="ss">"</span>)</span>
|
||
<span id="cb4-188"><a href="#cb4-188" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" "</span> <span class="op">+</span> <span class="st">"-"</span> <span class="op">*</span> <span class="dv">42</span>)</span>
|
||
<span id="cb4-189"><a href="#cb4-189" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> fenster <span class="kw">in</span> (<span class="dv">180</span>, <span class="dv">365</span>, <span class="dv">730</span>, <span class="dv">2000</span>):</span>
|
||
<span id="cb4-190"><a href="#cb4-190" aria-hidden="true" tabindex="-1"></a> treffer <span class="op">=</span> <span class="dv">0</span></span>
|
||
<span id="cb4-191"><a href="#cb4-191" aria-hidden="true" tabindex="-1"></a> versuche <span class="op">=</span> <span class="dv">400</span></span>
|
||
<span id="cb4-192"><a href="#cb4-192" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> _ <span class="kw">in</span> <span class="bu">range</span>(versuche):</span>
|
||
<span id="cb4-193"><a href="#cb4-193" aria-hidden="true" tabindex="-1"></a> start <span class="op">=</span> <span class="bu">int</span>(rng.integers(TRAINING, TAGE <span class="op">-</span> fenster))</span>
|
||
<span id="cb4-194"><a href="#cb4-194" aria-hidden="true" tabindex="-1"></a> ausschnitt <span class="op">=</span> <span class="bu">slice</span>(start, start <span class="op">+</span> fenster)</span>
|
||
<span id="cb4-195"><a href="#cb4-195" aria-hidden="true" tabindex="-1"></a> mse_punkt <span class="op">=</span> ((kleinste_quadrate.predict(merkmale[ausschnitt])</span>
|
||
<span id="cb4-196"><a href="#cb4-196" aria-hidden="true" tabindex="-1"></a> <span class="op">-</span> nachfrage[ausschnitt]) <span class="op">**</span> <span class="dv">2</span>).mean()</span>
|
||
<span id="cb4-197"><a href="#cb4-197" aria-hidden="true" tabindex="-1"></a> mse_quantil <span class="op">=</span> ((quantilmodell.predict(merkmale[ausschnitt])</span>
|
||
<span id="cb4-198"><a href="#cb4-198" aria-hidden="true" tabindex="-1"></a> <span class="op">-</span> nachfrage[ausschnitt]) <span class="op">**</span> <span class="dv">2</span>).mean()</span>
|
||
<span id="cb4-199"><a href="#cb4-199" aria-hidden="true" tabindex="-1"></a> treffer <span class="op">+=</span> mse_quantil <span class="op"><</span> mse_punkt</span>
|
||
<span id="cb4-200"><a href="#cb4-200" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f" </span><span class="sc">{</span>fenster<span class="sc">:>10}</span><span class="ss"> Tage </span><span class="sc">{</span>treffer <span class="op">/</span> versuche<span class="sc">:>24.1%}</span><span class="ss">"</span>)</span>
|
||
<span id="cb4-201"><a href="#cb4-201" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-202"><a href="#cb4-202" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st"> Bei einem halben Jahr Testdaten sieht das schlechtere Modell in gut"</span>)</span>
|
||
<span id="cb4-203"><a href="#cb4-203" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" jedem zehnten Fall besser aus. Das ist keine grosse Zahl - aber wer"</span>)</span>
|
||
<span id="cb4-204"><a href="#cb4-204" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" EINMAL misst, hat genau eine Ziehung aus dieser Verteilung."</span>)</span>
|
||
<span id="cb4-205"><a href="#cb4-205" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st"> Die Lehre ist nicht 'nimm 4.000 Testtage' - die hat niemand. Sie"</span>)</span>
|
||
<span id="cb4-206"><a href="#cb4-206" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" lautet: Ein Kennzahlenvergleich ohne Angabe seiner Streuung ist keine"</span>)</span>
|
||
<span id="cb4-207"><a href="#cb4-207" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Aussage. Bei kurzen Zeitraeumen gehoert eine Kreuzvalidierung dazu."</span>)</span>
|
||
<span id="cb4-208"><a href="#cb4-208" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb4-209"><a href="#cb4-209" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="ch">\n</span><span class="st">"</span> <span class="op">+</span> <span class="st">"="</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb4-210"><a href="#cb4-210" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" WAS MAN DARAUS MITNIMMT"</span>)</span>
|
||
<span id="cb4-211"><a href="#cb4-211" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">84</span>)</span>
|
||
<span id="cb4-212"><a href="#cb4-212" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Der Prognostiker optimiert den MSE, der Planer traegt die Kosten - und"</span>)</span>
|
||
<span id="cb4-213"><a href="#cb4-213" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"die beiden Masse zeigen hier in verschiedene Richtungen. Drei Saetze:"</span>)</span>
|
||
<span id="cb4-214"><a href="#cb4-214" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>()</span>
|
||
<span id="cb4-215"><a href="#cb4-215" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" 1. Sagen Sie nicht den Erwartungswert vorher, sondern die Groesse, die"</span>)</span>
|
||
<span id="cb4-216"><a href="#cb4-216" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" in die Entscheidung eingeht. Beim Newsvendor ist das das kritische"</span>)</span>
|
||
<span id="cb4-217"><a href="#cb4-217" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Quantil - und das kann man direkt schaetzen."</span>)</span>
|
||
<span id="cb4-218"><a href="#cb4-218" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" 2. Bewerten Sie Prognosemodelle an den ENTSCHEIDUNGSKOSTEN. Die sind"</span>)</span>
|
||
<span id="cb4-219"><a href="#cb4-219" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" in Euro und damit vergleichbar; ein MSE ist es nicht."</span>)</span>
|
||
<span id="cb4-220"><a href="#cb4-220" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" 3. Ein pauschaler Sicherheitszuschlag ist besser als nichts und"</span>)</span>
|
||
<span id="cb4-221"><a href="#cb4-221" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" schlechter als ein Modell, das die Unsicherheit selbst aus den"</span>)</span>
|
||
<span id="cb4-222"><a href="#cb4-222" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">" Merkmalen liest."</span>)</span>
|
||
<span id="cb4-223"><a href="#cb4-223" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>()</span>
|
||
<span id="cb4-224"><a href="#cb4-224" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Der naechste Schritt - Prognosemodelle so zu trainieren, dass sie die"</span>)</span>
|
||
<span id="cb4-225"><a href="#cb4-225" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Entscheidungskosten direkt minimieren (Smart Predict-then-Optimize,"</span>)</span>
|
||
<span id="cb4-226"><a href="#cb4-226" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"differenzierbare Optimierungsschichten) - ist Forschungsstand und"</span>)</span>
|
||
<span id="cb4-227"><a href="#cb4-227" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"erfordert Bibliotheken wie cvxpylayers. Die dritte Zeile der Tabelle"</span>)</span>
|
||
<span id="cb4-228"><a href="#cb4-228" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"oben ist seine einfachste denkbare Form: ein einziger Parameter, auf"</span>)</span>
|
||
<span id="cb4-229"><a href="#cb4-229" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"Kosten statt auf Fehler trainiert."</span>)</span>
|
||
<span id="cb4-230"><a href="#cb4-230" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"="</span> <span class="op">*</span> <span class="dv">84</span>)</span></code></pre></div>
|
||
<p><strong>Erwartete Ausgabe:</strong></p>
|
||
<pre><code>====================================================================================
|
||
DIE BESSERE PROGNOSE TRIFFT DIE SCHLECHTERE ENTSCHEIDUNG
|
||
====================================================================================
|
||
Verkaufspreis 9 EUR, Einkauf 3 EUR.
|
||
Fehlmenge kostet 6 EUR, Ueberhang 3 EUR je Stueck.
|
||
Kritisches Verhaeltnis: 0.667 - der Planer sollte also das
|
||
66.7%-Quantil der Nachfrage bestellen, nicht ihren Erwartungswert.
|
||
|
||
Training: Tag 1 bis 1000. Bewertung: die restlichen 4000 Tage.
|
||
|
||
Verfahren MSE Kosten/Tag gegen Zeile 1
|
||
--------------------------------------------------------------------------------
|
||
bestelle die Punktprognose 201.0 42.63 EUR
|
||
+ Zuschlag aus der Normalverteilung 201.0 39.51 EUR -7.3%
|
||
+ Zuschlag auf Kosten trainiert 201.0 39.14 EUR -8.2%
|
||
Quantilregression aufs kritische Quantil 227.6 38.08 EUR -10.7%
|
||
|
||
bester MSE: bestelle die Punktprognose
|
||
beste Kosten: Quantilregression aufs kritische Quantil
|
||
|
||
Das Verfahren mit dem besten MSE hat die HOECHSTEN Kosten, und das
|
||
Verfahren mit den besten Kosten hat einen um 13% SCHLECHTEREN MSE.
|
||
Wer Prognosemodelle nach MSE auswaehlt, waehlt hier das falsche.
|
||
|
||
------------------------------------------------------------------------------------
|
||
Warum ein pauschaler Zuschlag nicht genuegt
|
||
|
||
Verfahren normale Tage Aktionstage
|
||
--------------------------------------------------------------------------
|
||
bestelle die Punktprognose 29.67 EUR 108.59 EUR
|
||
+ Zuschlag aus der Normalverteilung 27.53 EUR 100.49 EUR
|
||
+ Zuschlag auf Kosten trainiert 26.67 EUR 102.58 EUR
|
||
Quantilregression aufs kritische Quantil 26.49 EUR 97.07 EUR
|
||
|
||
Der pauschale Zuschlag betraegt 5.9 Stueck. Aus den
|
||
Trainingsresten getrennt nach Tagesart waere richtig:
|
||
normale Tage : 3.5 Stueck
|
||
Aktionstage : 12.3 Stueck
|
||
Ein Zuschlag fuer alle Tage kann nur einen Mittelweg treffen - hier
|
||
ist er an normalen Tagen 1.7-mal zu gross und an
|
||
Aktionstagen nur 48% dessen, was noetig waere.
|
||
|
||
Die Quantilregression schaetzt das 66.7%-Quantil direkt aus den
|
||
Merkmalen und darf deshalb an verschiedenen Tagen verschieden weit
|
||
ueber dem Erwartungswert liegen. Genau das ist der Unterschied
|
||
zwischen 'ein Modell und danach eine Formel' und 'ein Modell, das
|
||
weiss, wofuer es gebraucht wird'.
|
||
|
||
------------------------------------------------------------------------------------
|
||
Eine Messfalle, in die der Autor zuerst selbst getappt ist
|
||
|
||
Der erste Entwurf dieses Programms bewertete auf 230 Testtagen - ein
|
||
realistischer Zeitraum. Dort hatte die Quantilregression den BESSEREN
|
||
MSE, und die ganze Aussage des Kapitels stand auf dem Kopf.
|
||
|
||
Wie oft das passiert, laesst sich ausmessen:
|
||
|
||
Testfenster QR sieht MSE-besser aus
|
||
------------------------------------------
|
||
180 Tage 11.8%
|
||
365 Tage 5.5%
|
||
730 Tage 0.0%
|
||
2000 Tage 0.0%
|
||
|
||
Bei einem halben Jahr Testdaten sieht das schlechtere Modell in gut
|
||
jedem zehnten Fall besser aus. Das ist keine grosse Zahl - aber wer
|
||
EINMAL misst, hat genau eine Ziehung aus dieser Verteilung.
|
||
|
||
Die Lehre ist nicht 'nimm 4.000 Testtage' - die hat niemand. Sie
|
||
lautet: Ein Kennzahlenvergleich ohne Angabe seiner Streuung ist keine
|
||
Aussage. Bei kurzen Zeitraeumen gehoert eine Kreuzvalidierung dazu.
|
||
|
||
====================================================================================
|
||
WAS MAN DARAUS MITNIMMT
|
||
====================================================================================
|
||
Der Prognostiker optimiert den MSE, der Planer traegt die Kosten - und
|
||
die beiden Masse zeigen hier in verschiedene Richtungen. Drei Saetze:
|
||
|
||
1. Sagen Sie nicht den Erwartungswert vorher, sondern die Groesse, die
|
||
in die Entscheidung eingeht. Beim Newsvendor ist das das kritische
|
||
Quantil - und das kann man direkt schaetzen.
|
||
2. Bewerten Sie Prognosemodelle an den ENTSCHEIDUNGSKOSTEN. Die sind
|
||
in Euro und damit vergleichbar; ein MSE ist es nicht.
|
||
3. Ein pauschaler Sicherheitszuschlag ist besser als nichts und
|
||
schlechter als ein Modell, das die Unsicherheit selbst aus den
|
||
Merkmalen liest.
|
||
|
||
Der naechste Schritt - Prognosemodelle so zu trainieren, dass sie die
|
||
Entscheidungskosten direkt minimieren (Smart Predict-then-Optimize,
|
||
differenzierbare Optimierungsschichten) - ist Forschungsstand und
|
||
erfordert Bibliotheken wie cvxpylayers. Die dritte Zeile der Tabelle
|
||
oben ist seine einfachste denkbare Form: ein einziger Parameter, auf
|
||
Kosten statt auf Fehler trainiert.
|
||
====================================================================================</code></pre>
|
||
<hr />
|
||
<h2 id="sec:prognose-befund">15.5 Der Befund</h2>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 27%" />
|
||
<col style="width: 36%" />
|
||
<col style="width: 36%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr class="header">
|
||
<th>Verfahren</th>
|
||
<th style="text-align: right;">MSE</th>
|
||
<th style="text-align: right;">Kosten je Tag</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td>bestelle die Punktprognose</td>
|
||
<td style="text-align: right;"><strong>201,0</strong> (bester)</td>
|
||
<td style="text-align: right;">42,63 € (schlechteste)</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td>+ Zuschlag aus der Normalverteilung</td>
|
||
<td style="text-align: right;">201,0</td>
|
||
<td style="text-align: right;">39,51 €</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td>+ Zuschlag auf Kosten trainiert</td>
|
||
<td style="text-align: right;">201,0</td>
|
||
<td style="text-align: right;">39,14 €</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td>Quantilregression aufs kritische Quantil</td>
|
||
<td style="text-align: right;">227,6 (schlechtester)</td>
|
||
<td style="text-align: right;"><strong>38,08 €</strong> (beste)</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><strong>Das Modell mit dem besten MSE hat die höchsten Kosten.</strong> Das kostenbeste Modell hat einen um 13 % schlechteren MSE — und spart 10,7 % der Kosten.</p>
|
||
<p>Wer Prognosemodelle nach MSE auswählt (und das ist die Voreinstellung jeder Modellauswahl-Bibliothek), wählt hier das falsche.</p>
|
||
<div class="card card-formel">
|
||
<blockquote>
|
||
<p><strong>🔤 Formel-Übersetzer: zwei Zielfunktionen</strong></p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 50%" />
|
||
<col style="width: 50%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr class="header">
|
||
<th>Mathematik</th>
|
||
<th>Was sie belohnt</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td><span class="math inline">\min \sum_t (\hat{d}_t - d_t)^2</span></td>
|
||
<td>„Liege im Mittel richtig.” Abweichungen nach oben und unten zählen gleich, große Abweichungen überproportional.</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td><span class="math inline">\min \sum_t \big[c_-(d_t - q_t)^+ + c_+(q_t - d_t)^+\big]</span></td>
|
||
<td>„Sei lieber etwas zu großzügig als etwas zu knapp.” Beide Richtungen zählen <strong>verschieden</strong> und beide nur linear.</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td><span class="math inline">(x)^+</span></td>
|
||
<td>„nur der positive Teil” — also <span class="math inline">\max(0, x)</span>.</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td><span class="math inline">c_- \ne c_+</span></td>
|
||
<td>Der ganze Grund, warum die beiden Optima auseinanderfallen.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Wären <span class="math inline">c_-</span> und <span class="math inline">c_+</span> gleich groß, läge das Optimum beim <strong>Median</strong> — immer noch nicht beim Mittelwert, aber wenigstens in der Mitte. Erst die Asymmetrie schiebt es ans Quantil.</p>
|
||
</blockquote>
|
||
</div>
|
||
<h3 id="warum-ein-pauschaler-zuschlag-zu-kurz-greift">Warum ein pauschaler Zuschlag zu kurz greift</h3>
|
||
<p>Die zweite Zeile der Tabelle ist die verbreitete Praxis: Punktprognose plus Sicherheitsbestand. Sie hilft (−7,3 %), bleibt aber hinter der Quantilregression zurück. Das Programm rechnet nach, warum:</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th></th>
|
||
<th style="text-align: right;">benötigter Zuschlag</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td>normale Tage</td>
|
||
<td style="text-align: right;">3,5 Stück</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td>Aktionstage</td>
|
||
<td style="text-align: right;">12,3 Stück</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td><strong>pauschal verwendet</strong></td>
|
||
<td style="text-align: right;"><strong>5,9 Stück</strong></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Ein einziger Wert kann nur einen Mittelweg treffen: An normalen Tagen ist er 1,7-mal zu groß, an Aktionstagen erreicht er nur 48 % dessen, was nötig wäre.</p>
|
||
<p>Die Quantilregression schätzt das 66,7-%-Quantil <strong>direkt aus den Merkmalen</strong> und darf deshalb an verschiedenen Tagen verschieden weit über dem Erwartungswert liegen. Das ist der Unterschied zwischen <em>„ein Modell und danach eine Formel”</em> und <em>„ein Modell, das weiß, wofür es gebraucht wird”</em>.</p>
|
||
<blockquote>
|
||
<p><strong>🎯 Merksatz</strong> Sagen Sie nicht den Erwartungswert vorher, sondern <strong>die Größe, die in die Entscheidung eingeht</strong>. Beim Newsvendor ist das das kritische Quantil — und das lässt sich direkt schätzen, statt es nachträglich aus einer Punktprognose zu basteln.</p>
|
||
</blockquote>
|
||
<hr />
|
||
<h2 id="sec:prognose-messfalle">15.6 Eine Messfalle, in die der Autor selbst getappt ist</h2>
|
||
<p>Der erste Entwurf dieses Programms bewertete auf <strong>230 Testtagen</strong> — ein realistischer Zeitraum, gut sieben Monate. Dort hatte die Quantilregression den <em>besseren</em> MSE, und die ganze Aussage dieses Kapitels stand auf dem Kopf.</p>
|
||
<p>Das war kein Denkfehler, sondern Zufall. Wie viel Zufall, lässt sich ausmessen:</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: right;">Testfenster</th>
|
||
<th style="text-align: right;">Quantilregression sieht MSE-besser aus</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: right;">180 Tage</td>
|
||
<td style="text-align: right;">11,8 %</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: right;">365 Tage</td>
|
||
<td style="text-align: right;">5,5 %</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: right;">730 Tage</td>
|
||
<td style="text-align: right;">0,0 %</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: right;">2 000 Tage</td>
|
||
<td style="text-align: right;">0,0 %</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Bei einem halben Jahr Testdaten sieht das (bezogen auf den MSE) schlechtere Modell in gut jedem zehnten Fall besser aus. Das ist keine große Zahl — aber <strong>wer einmal misst, hat genau eine Ziehung aus dieser Verteilung.</strong></p>
|
||
<blockquote>
|
||
<p><strong>⚠️ Was daraus folgt — und was nicht</strong></p>
|
||
<p>Die Lehre ist <strong>nicht</strong> „nimm 4 000 Testtage”. Die hat niemand; das Programm arbeitet deshalb mit simulierten Daten und sagt das auch.</p>
|
||
<p>Die Lehre ist: <strong>Ein Kennzahlenvergleich ohne Angabe seiner Streuung ist keine Aussage.</strong> Bei kurzen Zeiträumen gehört eine Kreuzvalidierung dazu, und der Unterschied zwischen zwei Modellen muss größer sein als die Schwankung zwischen zwei Zeitfenstern.</p>
|
||
<p>Verwandt, aber nicht dasselbe: <a href="handelsmaschine.html#kap-handelsmaschine">Kapitel 21</a>, <code>Data_Snooping.py</code>. Dort geht es um die Zahl der <em>Versuche</em>, hier um die Zahl der <em>Beobachtungen</em>. Beide Male führt eine weggelassene Angabe zu einer Aussage, die nicht trägt.</p>
|
||
</blockquote>
|
||
<hr />
|
||
<h2 id="sec:prognose-ausblick">15.7 Wie weit das Verfahren reicht</h2>
|
||
<p>Die dritte Zeile der Ergebnistabelle — „Zuschlag auf Kosten trainiert” — ist die einfachste denkbare Form einer Idee, die derzeit erforscht wird: <strong>das Prognosemodell direkt auf die Entscheidungskosten zu trainieren</strong> statt auf ein Fehlermaß.</p>
|
||
<p>Hier war es ein einziger Parameter, mit einer Rasterschleife bestimmt. Der allgemeine Fall ist schwieriger, weil die Optimierung zwischen Modell und Kosten steht: Um den Gradienten der Kosten nach den Modellparametern zu bilden, muss man <strong>durch das Optimierungsproblem hindurch ableiten</strong>.</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 33%" />
|
||
<col style="width: 33%" />
|
||
<col style="width: 33%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr class="header">
|
||
<th>Ansatz</th>
|
||
<th>Idee</th>
|
||
<th>Bibliothek</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td><strong>Richtige Zielgröße</strong> (dieses Kapitel)</td>
|
||
<td>Schätze das Quantil, das die Entscheidung braucht</td>
|
||
<td><code>sklearn</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td><strong>SPO+</strong> (Elmachtoub/Grigas)</td>
|
||
<td>Ein Ersatzverlust, der die Entscheidungskosten nach oben abschätzt und konvex ist</td>
|
||
<td>—</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td><strong>Differenzierbare Optimierung</strong></td>
|
||
<td>Das Optimierungsproblem wird eine Schicht im neuronalen Netz</td>
|
||
<td><code>cvxpylayers</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<blockquote>
|
||
<p><strong>💡 Womit man anfängt</strong></p>
|
||
<p>Nicht mit <code>cvxpylayers</code>. Der Ertrag der ersten Zeile ist in der Praxis meist der größte und kostet einen Nachmittag: Fragen Sie, welche Größe die Entscheidung wirklich braucht, und schätzen Sie diese. In diesem Kapitel bringt das 10,7 % — die aufwendigen Verfahren ringen danach um die letzten Prozentpunkte.</p>
|
||
</blockquote>
|
||
<hr />
|
||
<h2 id="sec:prognose-uebungsaufgaben">15.8 Übungsaufgaben</h2>
|
||
<blockquote>
|
||
<p>Lösungen: <a href="anhang-loesungen.html#sec:loesungen-prognose">Abschnitt A.15</a>.</p>
|
||
</blockquote>
|
||
<p><strong>Aufgabe 15.1 ⭐ — Andere Preise.</strong> Die Bäckerei kann übrige Ware am Folgetag zum halben Preis abgeben; der Überhang kostet dann nur noch 1,50 € statt 3 €. Wie ändert sich das kritische Verhältnis, und in welche Richtung verschiebt sich die Bestellmenge?</p>
|
||
<p><strong>Aufgabe 15.2 ⭐ — Wann ist der Mittelwert richtig?</strong> Nennen Sie die Bedingung, unter der Erwartungswert und optimale Bestellmenge zusammenfallen. Wie realistisch ist sie?</p>
|
||
<p><strong>Aufgabe 15.3 ⭐⭐ — Die Kennzahl der Prognoseabteilung.</strong> Ersetzen Sie im Programm den MSE durch den MAPE (mittlerer absoluter prozentualer Fehler). Ändert sich die Rangfolge der vier Verfahren? Begründen Sie, warum das kein Zufall ist.</p>
|
||
<p><strong>Aufgabe 15.4 ⭐⭐ — Zwei Quantile.</strong> Schätzen Sie zusätzlich das 5-%- und das 95-%-Quantil und zeichnen Sie für 30 Testtage ein Band um die Punktprognose. An welchen Tagen ist es breit — und passt das zu Ihrer Erwartung?</p>
|
||
<p><strong>Aufgabe 15.5 ⭐⭐⭐ — Der Wert der Merkmale.</strong> Entfernen Sie das Merkmal „Aktion” aus dem Modell. Wie verschlechtern sich MSE und Kosten — und zwar <strong>in unterschiedlichem Ausmaß</strong>? Was sagt das über den Wert eines Merkmals aus?</p>
|
||
<hr />
|
||
<h2 id="sec:prognose-denkfehler">15.9 Finde den Denkfehler</h2>
|
||
<div class="card card-denkfehler">
|
||
<blockquote>
|
||
<p><strong>🐛 „Wir haben die Prognose um 18 % verbessert”</strong></p>
|
||
<p>Ein Data-Science-Team stellt sein Quartalsergebnis vor:</p>
|
||
<blockquote>
|
||
<p><em>„Wir haben das alte lineare Modell durch ein Gradient-Boosting-Modell ersetzt. Der MSE > auf den Testdaten ist um 18 % gesunken, der MAPE um 14 %. Das ist die größte > Prognoseverbesserung, die wir je erreicht haben. Die Disposition bekommt ab nächstem > Monat die neuen Werte.”</em></p>
|
||
</blockquote>
|
||
<p>Sechs Wochen später meldet die Disposition, die Retouren seien gestiegen.</p>
|
||
<p>Das Team prüft alles nach: Die Modellgüte stimmt, die Testdaten waren sauber getrennt, es gibt kein Leck. Das neue Modell prognostiziert die Nachfrage tatsächlich deutlich besser als das alte.</p>
|
||
<p><strong>Wie kann eine bessere Prognose zu schlechteren Ergebnissen führen — und was hätte das Team messen müssen?</strong></p>
|
||
<p>Ein zweiter Hinweis für den zweiten Teil der Antwort: Die Disposition rechnet mit Punktprognose plus einem Sicherheitszuschlag, der aus den <strong>Residuen des alten Modells</strong> stammt und seit Jahren unverändert ist.</p>
|
||
</blockquote>
|
||
</div>
|
||
<hr />
|
||
<h2 id="sec:prognose-quiz">15.10 Micro-Quiz</h2>
|
||
<div class="card card-quiz">
|
||
<blockquote>
|
||
<p><strong>❓ Drei Fragen</strong></p>
|
||
<p><strong>1. Warum ist der Erwartungswert beim Newsvendor die falsche Bestellmenge?</strong> a) Weil er statistisch unzuverlässig geschätzt wird. b) Weil die Kosten für Fehlmenge und Überhang verschieden hoch sind und das Optimum deshalb am kritischen Quantil liegt. c) Weil die Nachfrage nicht normalverteilt ist.</p>
|
||
<p><strong>2. Ein Kollege schlägt vor, den Sicherheitszuschlag jährlich aus den Residuen neu zu berechnen. Was löst das nicht?</strong> a) Nichts — das ist die richtige Lösung. b) Der Zuschlag bleibt für alle Tage gleich, obwohl die Unsicherheit von den Merkmalen abhängt. c) Residuen sind grundsätzlich ungeeignet, um Unsicherheit zu schätzen.</p>
|
||
<p><strong>3. Bei 180 Testtagen sieht das MSE-schlechtere Modell in 11,8 % der Fälle besser aus. Was folgt daraus für die Praxis?</strong> a) Man braucht mindestens 730 Testtage, sonst ist jeder Vergleich wertlos. b) Ein einzelner Kennzahlenvergleich ohne Streuungsangabe ist keine belastbare Aussage; bei kurzen Zeiträumen gehört eine Kreuzvalidierung dazu. c) Der MSE ist grundsätzlich unbrauchbar.</p>
|
||
</blockquote>
|
||
</div>
|
||
<hr />
|
||
<h2 id="sec:prognose-selbsttest">15.11 Selbsttest</h2>
|
||
<ol type="1">
|
||
<li>Erklären Sie in zwei Sätzen, warum „predict then optimize” eine Naht hat, an der Information verlorengeht.</li>
|
||
<li>Welche Größe muss ein Prognosemodell liefern, wenn die Entscheidung ein Newsvendor ist — und woher kennen Sie den Wert?</li>
|
||
<li>Warum ist ein pauschaler Sicherheitszuschlag schwächer als eine Quantilregression? Nennen Sie die Dateneigenschaft, um die es geht.</li>
|
||
<li>Ihre Prognoseabteilung meldet 18 % besseren MSE. Welche eine Frage stellen Sie?</li>
|
||
<li>Wie viele Testdaten braucht ein Modellvergleich? Formulieren Sie die Antwort ohne eine konkrete Zahl.</li>
|
||
</ol>
|
||
<hr />
|
||
<h2 id="sec:prognose-zusammenfassung">15.12 Zusammenfassung</h2>
|
||
<ul>
|
||
<li><strong>Predict-then-Optimize</strong> trennt Schätzen und Entscheiden. Die erste Stufe wird auf ein statistisches Maß trainiert, die zweite erzeugt ökonomische Kosten — und die beiden Maße können in verschiedene Richtungen zeigen.</li>
|
||
<li>Im Beispiel hat das Verfahren mit dem <strong>besten MSE die höchsten Kosten</strong>; das kostenbeste Verfahren hat einen um 13 % schlechteren MSE und spart 10,7 %.</li>
|
||
<li>Der Grund ist die <strong>Asymmetrie</strong> der Kosten: Fehlmenge und Überhang kosten verschieden viel, deshalb liegt das Optimum am kritischen Quantil und nicht am Erwartungswert.</li>
|
||
<li>Ein <strong>pauschaler Sicherheitszuschlag</strong> hilft, greift aber zu kurz, wenn die Unsicherheit selbst von den Merkmalen abhängt: Hier wäre er an normalen Tagen 1,7-mal zu groß und an Aktionstagen halb so groß wie nötig.</li>
|
||
<li><strong>Bewerten Sie Prognosemodelle an den Entscheidungskosten.</strong> Sie sind in Euro und damit vergleichbar; ein MSE ist es nicht.</li>
|
||
<li>Ein Kennzahlenvergleich braucht eine <strong>Streuungsangabe</strong>. Bei 180 Testtagen sah das schlechtere Modell in gut jedem zehnten Fall besser aus — und wer einmal misst, hat genau eine Ziehung.</li>
|
||
</ul>
|
||
|
||
</article>
|
||
<button type="button" class="fortschritt-knopf" data-kapitel="prognose.html"><svg class="icon" aria-hidden="true"><use href="#icon-check"></use></svg> <span>Als gelesen markieren</span></button>
|
||
<nav class="prev-next"><a class="prev-next-knopf prev-next-prev" href="mehrziel.html"><svg class="icon" aria-hidden="true"><use href="#icon-chevron-left"></use></svg><span><small>Zurück</small>Kapitel 14: Mehrere Ziele — Pareto-Fronten statt Gewichte</span></a><a class="prev-next-knopf prev-next-next" href="synthese-nichtlinear.html"><span><small>Weiter</small>Synthese Teil III</span><svg class="icon" aria-hidden="true"><use href="#icon-chevron-right"></use></svg></a></nav>
|
||
</main>
|
||
</div>
|
||
<footer class="site-footer">
|
||
<p>© Dieter Schlüter · <a href="gesamtdokument.html">Gesamtdokument</a> ·
|
||
<a href="programme.html">Beispielprogramme</a></p>
|
||
</footer>
|
||
<script defer src="assets/search-index.js"></script>
|
||
<script defer src="assets/programme.js"></script>
|
||
<script defer src="assets/site.js"></script>
|
||
</body>
|
||
</html>
|