Lineare Regression
Kurz gesagt: Die lineare Regression sagt eine Zahl als Summe der Merkmale mit Koeffizienten voraus; der MAE sagt, wie weit sie im Schnitt daneben liegt, und der RMSE gewichtet große Fehler stärker, beide in derselben Einheit.
Problem
„Wie viel Geld erwarte ich am Freitag?“
Die Buchhaltung plant das Geld für die nächsten Wochen. Sie fragt, wie viel Umsatz am Freitag, dem 6. November, und am Sonntag, dem 8. November, zu erwarten ist. Hier ist der Umsatz nach Tagen des Jahres, ohne die stornierten Bestellungen, weil sie kein Geld bringen:
Ein Tag bringt im Schnitt 304,62 €. Der Freitag bringt 350,79 € und der Sonntag 250,85 €. Dezembertage bringen im Schnitt 513,42 €. Der Mittelwert jedes Wochentags ist ein Anfang, aber der Dezember und das langsame Wachstum übers Jahr sind darin vermischt. Du brauchst ein Modell, das sie zusammenbringt.
Die Idee
Eine Summe aus Merkmalen
Die lineare Regression sagt als Summe voraus: eine Startzahl plus eine Zahl für jedes Merkmal, multipliziert mit seinem Wert. Diese Zahlen sind die Koeffizienten. Die Merkmale sind hier von dreierlei Art:
- der Wochentag, als Spalten aus 0 und 1. Mit
drop_first=Truefällt die Spalte für Montag weg: Der Montag ist die Basis, und jeder andere Tag ist „wie viel mehr als Montag“; day, die laufende Nummer des Tages: 0 am 1. November 2025. Das ist der Trend;december: 1 für die Tage im Dezember.
Das Modell lernt von November bis Juni, 242 Tage. Juli bis Oktober, 123 Tage, sind für den Test. Warum nicht gemischt, steht am Ende der Lektion:
Die Startzahl ist 273,98 €: ein Montag an Tag 0, außerhalb des Dezembers. Der Freitag fügt 63,58 € hinzu, und der Sonntag nimmt 45,44 € weg. Der Dezember fügt 233,05 € pro Tag hinzu. Jeder Tag fügt 0,06 € hinzu, das sind etwa 21,33 € pro Jahr. Die Vorhersage für einen Freitag im Dezember ist also 273,98 + 63,58 + 233,05 plus der Trend.
Genauer, für Neugierige
Die Koeffizienten sind Schätzungen und tragen Rauschen, wie der Mittelwert in der Lektion über Stichproben. Mit allen 365 Tagen trainiert, gibt das Modell dem Freitag +44,70 €, nicht +63,58 €. Wie die Regression die Zahlen findet (die kleinste Summe der Fehlerquadrate), steht ohne Bibliothek in der Lektion Lineare Regression des KI-Kurses.
Probier es aus
Welcher ist die Basis
Die Idee
Wie weit es daneben liegt: MAE und RMSE
Der Fehler wird auf dem Test gemessen. Es gibt zwei übliche Maße:
- MAE (mean absolute error, mittlerer absoluter Fehler): der mittlere Fehler ohne Vorzeichen. In Euro, und der Chef versteht ihn: „Wir liegen im Schnitt so viel pro Tag daneben.“
- RMSE (root mean squared error, Wurzel des mittleren quadratischen Fehlers): Die Fehler werden quadriert, der Mittelwert gebildet und dann die Wurzel gezogen. Er ist ebenfalls in Euro, aber ein großer Fehler wiegt mehr.
sklearn.metrics hat beide:
Das Modell liegt im Schnitt um 59,88 € pro Tag daneben (MAE), und der RMSE ist 75,91 €. Die zwei kleinen Rechnungen zeigen den Unterschied. Fehler von 10 und 10 ergeben einen MAE von 10 und einen RMSE von 10. Fehler von 0 und 20 ergeben denselben MAE von 10, aber einen RMSE von 14,14. Wenn dich ein großer Fehler mehr kostet als ein paar kleine, zum Beispiel eine leere Kasse am Freitag, schaust du auf den RMSE. Sonst ist der MAE für den Chef klarer.
Probier es aus
Und die Baseline?
Schlägt das Modell „immer der durchschnittliche Tag“? Lege in guess den mittleren Umsatz der Trainingstage ab und in mae_base und rmse_base die Fehler dieser Vorhersage an den Testtagen.
Lösung
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
orders = pd.read_csv('year_orders.csv')
items = pd.read_csv('year_items.csv')
orders = orders[orders['status'] != 'cancelled']
orders['ordered_at'] = pd.to_datetime(orders['ordered_at'])
items['revenue'] = items['quantity'] * items['unit_price']
lines = items.merge(orders, left_on='order_id', right_on='id')
daily = lines.set_index('ordered_at').resample('D')['revenue'].sum().to_frame()
daily['weekday'] = daily.index.dayofweek
daily['day'] = np.arange(len(daily))
daily['december'] = (daily.index.month == 12).astype(int)
X = pd.get_dummies(daily[['weekday', 'day', 'december']], columns=['weekday'], drop_first=True, dtype=int)
y = daily['revenue']
train = daily.index < '2026-07-01'
X_train, X_test = X[train], X[~train]
y_train, y_test = y[train], y[~train]
model = LinearRegression().fit(X_train, y_train)
guess = y_train.mean()
mae_base = np.abs(y_test - guess).mean()
rmse_base = np.sqrt(((y_test - guess) ** 2).mean())
print(round(guess, 2), round(mae_base, 2), round(rmse_base, 2))Die Baseline sagt für jeden Tag 314,34 €. Sie liegt mit einem MAE von 66,24 € und einem RMSE von 82,67 € daneben. Das Modell hat 59,88 € und 75,91 €: bei beiden Maßen 6 bis 7 € pro Tag weniger. Das ist nicht viel: Der Umsatz eines Tages ist verrauscht, und der größte Teil des Fehlers kommt daher, welche Kunden zufällig an dem Tag gekommen sind. Ohne die Wurzel bekommst du 6.834,32: Euro zum Quadrat, was sich mit nichts vergleichen lässt. Mit dem Mittelwert des Tests (285,49 €) ist der MAE 61,02 € und die Baseline sieht fast so gut aus wie das Modell, aber sie benutzt die Antwort.
Die Idee
Die Residuen
Ein Residuum ist der Istwert minus die Vorhersage. Plus heißt, der Shop hat mehr verkauft, als das Modell sagte. Bei einem guten Modell streuen die Residuen um 0, ohne Muster. Ein Muster ist etwas, das das Modell nicht weiß:
Der größte Fehler ist am 30. Juli 2026: 239,28 € über der Vorhersage. Es ist ein ungewöhnlich starker Donnerstag mit 535,40 € Umsatz. Nach Monaten liegen Juli, August und Oktober nah bei 0 (3,99 €, −8,03 € und 20,42 €). Der September ist −58,85 € pro Tag: Einen ganzen Monat lang hat der Shop weniger verkauft, als der Tag und der Trend erklären. Das ist kein Rauschen, es ist etwas passiert. Was, finden wir im Kursprojekt heraus.
Die Idee
Was das Modell nicht kann
Das Modell weiß nur, was seine Merkmale ihm sagen. Ohne die Spalte december:
Der Trend wird −0,40 € pro Tag, −147,35 € pro Jahr. Der Dezember liegt am Anfang der Trainingsdaten und „hebt“ den Anfang der Linie, und das Modell kann ihn nicht anders erklären. Der Testfehler wird 69,43 €, schlechter als die Baseline (66,24 €). Der Sprung durch die Geschenkkarten im Dezember zeigt sich nur, wenn ein Merkmal es sagt.
Zwei weitere Grenzen:
- Keine Extrapolation. Die Linie geht ewig weiter. Aus 8 Monaten beträgt das Wachstum 21,33 € pro Jahr, aber ob es im nächsten Jahr weitergeht, sagen die Daten nicht. Wir haben nur einen Dezember gesehen.
- Ein Koeffizient ist keine Ursache. „+63,58 € am Freitag“ heißt nicht, dass eine auf den Freitag verlegte Aktion 63,58 € bringt. Der Koeffizient beschreibt die Daten. Wie viel eine Aktion bringt, sagt dir ein Experiment, wie in der Lektion Korrelation und Ursache.
Probier es aus
Wo das Modell blind ist
Trainiere das Modell ohne die Spalte december mit den Trainingstagen. Berechne seine Residuen auf denselben Tagen und das mittlere Residuum pro Monat in by_month (gruppiere nach res.index.strftime('%Y-%m')). Zeichne by_month als Balken, mit Titel und Beschriftung der senkrechten Achse.
Lösung
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
orders = pd.read_csv('year_orders.csv')
items = pd.read_csv('year_items.csv')
orders = orders[orders['status'] != 'cancelled']
orders['ordered_at'] = pd.to_datetime(orders['ordered_at'])
items['revenue'] = items['quantity'] * items['unit_price']
lines = items.merge(orders, left_on='order_id', right_on='id')
daily = lines.set_index('ordered_at').resample('D')['revenue'].sum().to_frame()
daily['weekday'] = daily.index.dayofweek
daily['day'] = np.arange(len(daily))
daily['december'] = (daily.index.month == 12).astype(int)
X = pd.get_dummies(daily[['weekday', 'day', 'december']], columns=['weekday'], drop_first=True, dtype=int)
y = daily['revenue']
train = daily.index < '2026-07-01'
X_train, X_test = X[train], X[~train]
y_train, y_test = y[train], y[~train]
import matplotlib.pyplot as plt
no_dec = X.drop(columns='december')
blind = LinearRegression().fit(no_dec[train], y_train)
res = y_train - blind.predict(no_dec[train])
by_month = res.groupby(res.index.strftime('%Y-%m')).mean()
fig, ax = plt.subplots(figsize=(8, 3.5))
ax.bar(by_month.index, by_month.values)
ax.axhline(0, color='black', linewidth=1)
ax.set_title('Modell ohne Dezember: mittleres Residuum pro Monat')
ax.set_ylabel('€ pro Tag')Der Dezember liegt 167,92 € pro Tag über der Vorhersage: Das Modell sieht die Geschenkkarten und die Feiertage nicht. Der Januar ist −100,63 €: Die wegen des Dezembers nach unten geneigte Linie ist am Jahresanfang zu hoch. Mit der Spalte december ist der Balken des Dezembers fast 0. Das Residuum ist Istwert minus Vorhersage. Drehst du es um, kommt der Dezember unter 0 heraus und das Diagramm sagt das Gegenteil.
Die Idee
Nach der Zeit trennen, nicht mischen
Das Modell in dieser Lektion lernt von November bis Juni und wird mit Juli bis Oktober geprüft. Warum nicht mit train_test_split? Hier ist ein Modell mit Tag und Monat, auf beide Arten geprüft. Die zweite Zahl in jeder Zeile ist die Baseline:
Gemischt liegt das Modell um 59,81 € daneben und die Baseline um 81,48 €: 27 % besser. Aber 87 der 92 Testtage haben einen Nachbartag, den davor oder den danach, in den Trainingsdaten. Das Modell hat gelernt, wie die Tage um den Testtag herum liefen, auch die späteren.
Nach der Zeit geprüft liegt dasselbe Modell um 71,98 € daneben, mehr als die Baseline (66,24 €). Die Monate Juli bis Oktober sind nicht in den Trainingsdaten. Ihre Spalten sind in allen Trainingszeilen 0, und das Modell gibt ihnen das Niveau des Januars, des schwächsten Monats.
Eine echte Vorhersage gilt immer für Tage nach allen Beispielen. Also muss auch der Test nach dem Training liegen. Das Mischen der Tage lässt die Zukunft ins Training. Das ist ein Datenleck, und eine ganze Lektion weiter hinten handelt davon.
Übung
Freitag und Sonntag
Jetzt die Antwort für die Buchhaltung. Trainiere das Modell noch einmal mit allen 365 Tagen. Bilde X_new für Freitag, den 6. November 2026, und Sonntag, den 8. November 2026 (day zählt ab dem 1. November 2025 weiter, december ist 0) und lege in forecast die Vorhersage für die beiden Tage ab (eine Series mit den Daten als Index).
Lösung
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
orders = pd.read_csv('year_orders.csv')
items = pd.read_csv('year_items.csv')
orders = orders[orders['status'] != 'cancelled']
orders['ordered_at'] = pd.to_datetime(orders['ordered_at'])
items['revenue'] = items['quantity'] * items['unit_price']
lines = items.merge(orders, left_on='order_id', right_on='id')
daily = lines.set_index('ordered_at').resample('D')['revenue'].sum().to_frame()
daily['weekday'] = daily.index.dayofweek
daily['day'] = np.arange(len(daily))
daily['december'] = (daily.index.month == 12).astype(int)
X = pd.get_dummies(daily[['weekday', 'day', 'december']], columns=['weekday'], drop_first=True, dtype=int)
y = daily['revenue']
train = daily.index < '2026-07-01'
X_train, X_test = X[train], X[~train]
y_train, y_test = y[train], y[~train]
final = LinearRegression().fit(X, y)
dates = pd.to_datetime(['2026-11-06', '2026-11-08'])
new = pd.DataFrame({'weekday': dates.dayofweek, 'day': (dates - daily.index[0]).days, 'december': 0}, index=dates)
X_new = pd.get_dummies(new, columns=['weekday'], dtype=int).reindex(columns=X.columns, fill_value=0)
forecast = pd.Series(final.predict(X_new), index=dates).round(2)
print(forecast)Der Freitag ist 336,38 €, der Sonntag 236,58 €. Bei einem Fehler von etwa 60 € pro Tag lautet die ehrliche Antwort „etwa 340 € am Freitag und etwa 240 € am Sonntag, plus minus 60 €“. Der Test war die Prüfung. Für die Vorhersage trainierst du mit allen Tagen, weil die letzten Monate dem November am nächsten sind. Deshalb ist der Freitag +44,70 € gegenüber dem Montag, nicht +63,58 €. day ist 370 und 372, genau wie im Training gezählt. Mit day 0 ist die Vorhersage 329,70 € und 229,86 €, und mit dem alten, bis Juni trainierten Modell 359,17 € und 250,27 €.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Das erste Diagramm · Verteilungen · Korrelation und Ursache · Modelle: aus Beispielen lernen
- Geht weiter in: Klassifikation · Datenleck · Kreuzvalidierung
- Aufgaben zum Thema: Modelle mit scikit-learn