library(readr)
sprints24 <- read_delim(
"https://www-user.tu-chemnitz.de/~burma/blog_data/team_sprints_24.csv",
delim = ";", escape_double = FALSE, trim_ws = TRUE)
sprints24[ , c("Pkt_24", "Sprints_24")] <- sprints24[, c("Pkt_24", "Sprints_24")] / 26
scatter.smooth(sprints24$Sprints_24, sprints24$Pkt_24,
ylab = "Punkte / Spiel", xlab = "Anzahl der Sprints / Spiel")Lernziele
- Curve-Fitting mit
poly - Unterschied zwischen guter Datenpassung und guter Vorhersage
- Overfitting am Beispiel von Sprints zur Prognose der Bundesliga-Tabelle
Curve Fitting
Mit geeigneten Polynomen kann man vorhandene Daten fast beliebig gut treffen. Das sieht beeindruckend aus und führt zu hohen Werten von \(R^2\). Für echte Vorhersagen ist das aber oft wertlos oder sogar schädlich.
Ohne Theorie im Hintergrund wird Curve-Fitting schnell zu Overfitting: Das Modell beschreibt vor allem den Zufall in den Trainingsdaten und scheitert, sobald neue Daten ins Spiel kommen.
Unter Curve-Fitting versteht man umgangssprachlich die Anpassung einer mathematischen Funktion (oft eines Polynoms) an vorhandene Daten.
Beim Curve-Fitting sucht man direkt nach der Funktion, die die gegebenen Daten möglichst gut beschreibt. Das widerspricht einer theoriegeleiteten Vorgehensweise, bei der zuerst eine inhaltliche Erwartung formuliert und daraus ein Modell abgeleitet wird, das dann an Daten geprüft wird.
Curve Fitting:
- Daten -> polynome Funktion
Theoriegeleitet:
- inhaltliche Annahme → Modell (oft einfach, z. B. linear) → Daten
Curve-Fitting kann in der Exploration hilfreich sein, ersetzt aber niemals eine theoretische Einbettung.
Beispiel “Sprints” in der Bundesliga
Um die Koeffizienten später besser vergleichen zu können, berechnen wir zunächst die durchschnittlichen Punkte pro Spiel und die durchschnittlichen Sprints pro Spiel. Anschließend zeichnen wir ein Streudiagramm mit einer Loess-Kurve.
Ermittlung der Polynome nach Least-Squares
Wir schätzen nun polynome Funktionen bis zum 4. Grad und zusätzlich ein Modell 10. Grades, allgemein:
\[\hat{y} = f(x) = a + b_1x^1 + b_2x^2 + b_3x^3+ b_4x^4 + ... + b_nx^n\]
Mit der Funktion poly und das Argument degree können wir in R die entsprechende Funktion erzeugen. Für degree = 1 ergibt sich die bekannte lineare Regressionsgerade:
model_grad1 <- lm(Pkt_24 ~ poly(Sprints_24, degree = 1), data = sprints24)
model_grad2 <- lm(Pkt_24 ~ poly(Sprints_24, degree = 2), data = sprints24)
model_grad3 <- lm(Pkt_24 ~ poly(Sprints_24, degree = 3), data = sprints24)
model_grad4 <- lm(Pkt_24 ~ poly(Sprints_24, degree = 4), data = sprints24)
model_grad10 <- lm(Pkt_24 ~ poly(Sprints_24, degree = 10), data = sprints24)
# R2
R2 <- c(summary(model_grad1)$r.squared, summary(model_grad2)$r.squared,
summary(model_grad3)$r.squared, summary(model_grad4)$r.squared,
summary(model_grad10)$r.squared)| R2 | |
|---|---|
| Grad: 1 | 0.030 |
| Grad: 2 | 0.287 |
| Grad: 3 | 0.310 |
| Grad: 4 | 0.310 |
| Grad: 10 | 0.534 |
Model 2 ist augenscheinlich ziemlich gut:
\[\hat{y_i} = f(x) = 1.37 + 0.43x_i - 1.25x_i^2\]
round(summary(model_grad2)$coefficients, 2) Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.37 0.13 10.79 0.00
poly(Sprints_24, degree = 2)1 0.43 0.54 0.80 0.44
poly(Sprints_24, degree = 2)2 -1.25 0.54 -2.33 0.03
Die Varianzaufklärung der quadratischen Funktion steigt von 3% auf fast 29%. Das Modell 10. Grades ist natürlich noch besser, aber definitv keine einfachere Beschreibung des Zusammenhangs. Wir halten es zum Vergleich im “Rennen”.
Auf der z-Skala ist der RMSE direkt in Standardabweichungen interpretierbar.
Außerdem zeichnen wir das Polynom in die Grafik (hier gibt es eine Inspiration für die Zeichnung):
# X-Werte
par(mfrow = c(1,2))
z_sprints24 <- data.frame(sapply(sprints24[, 3:4], scale))
z_model_grad2 <- lm(Pkt_24 ~ poly(Sprints_24, degree = 2), data = z_sprints24)
X_Werte <- seq( min(z_sprints24$Sprints_24), max(z_sprints24$Sprints_24), length = 1000)
Y_Werte2 <- predict(z_model_grad2, newdata = data.frame(Sprints_24 = X_Werte))
# Plot
plot(z_sprints24$Sprints_24, z_sprints24$Pkt_24, ylim = c(-18, 2.1),
ylab = "z_Punkte", xlab = "z_Sprints",
main = "RMSE = 0.82", pch = 19, col = "blue")
lines(X_Werte, Y_Werte2)
z_model_grad10 <- lm(Pkt_24 ~ poly(Sprints_24, degree = 10), data = z_sprints24)
Y_Werte10 <- predict(z_model_grad10, newdata = data.frame(Sprints_24 = X_Werte))
plot(z_sprints24$Sprints_24, z_sprints24$Pkt_24, ylim = c(-18, 2.1),
ylab = "z_Punkte", xlab = "z_Spiel",
main = "RMSE = 0.66", pch = 19, col = "blue")
lines(X_Werte, Y_Werte10)Für die Saison 23/24 ergibt sich also in etwa:
Modell Grad 2: RMSE ≈ 0,82
Modell Grad 10: RMSE ≈ 0,66
Das Modell Grad 10 passt die Trainingsdaten noch etwas besser, der typische Fehler ist kleiner als beim Modell Grad 2. Bis hierhin wirkt das komplexere Modell überlegen.
Gute Passung ist keine gute Vorhersage
Spannend wird es, wenn wir dieselben Modelle auf neue Daten anwenden.
Wir betrachten nun die Saison 22/23, standardisieren wieder Punkte und Sprints und verwenden die Modelle, die auf den 24er Daten geschätzt wurden, um die 23er Punkte vorherzusagen.
sprints23 <- read_delim(
"https://www-user.tu-chemnitz.de/~burma/blog_data/team_sprints_23.csv",
delim = ";", escape_double = FALSE, trim_ws = TRUE
)
z_sprints23 <- as.data.frame(sapply(sprints23[, c("Pkt_23", "Sprints_23")], scale))
X_Werte <- seq( min(z_sprints23$Sprints_23), max(z_sprints23$Sprints_23), length = 1000)
# ohne Schalke und Hertha
par(mfrow = c(1,2))
plot(z_sprints23$Sprints_23, z_sprints23$Pkt_23, ylim = c(-18, 2.1),
ylab = "z_Punkte", xlab = "z_Sprints",
main = "RMSE = 1.29", pch = 19, col = "blue")
lines(X_Werte, Y_Werte2)
plot(z_sprints23$Sprints_23, z_sprints23$Pkt_23, ylim = c(-18, 2.1),
ylab = "z_Punkte", xlab = "z_Sprints",
main = "RMSE = 1669.89", pch = 19, col = "blue")
lines(X_Werte, Y_Werte10)In den Grafiken sieht man die deutlich schlechtere Passung. Zur Bewertung berechnen wir wieder den RMSE, jetzt aber nicht auf den 24er Trainingsdaten, sondern auf den 23er Vorhersagen.
\[ \mathrm{RMSE}=\sqrt{\frac{1}{n}\sum_{i=1}^{n}\bigl(y_i-\hat y_i\bigr)^2} \]
\[ \hat y_i=f_{24}(x_i)=\beta_0+\beta_1 x_i+\beta_2 x_i^2\,(+\dots) \]
damit ergibt sich für die vorhersagegüte auf den 23er daten zum beispiel
\[ \mathrm{RMSE}_{23\mid 24} = \sqrt{\frac{1}{n}\sum_{i=1}^n \bigl(y_i^{(23)} - f_{24}(x_i^{(23)})\bigr)^2} \]
rmse <- function(y, y_hat) {
sqrt(mean((y - y_hat)^2))
}
rmse_24_grad2 <- rmse(z_sprints24$Pkt_24, fitted(z_model_grad2))
rmse_24_grad10 <- rmse(z_sprints24$Pkt_24, fitted(z_model_grad10))
rmse_24_grad2; rmse_24_grad10[1] 0.8204382
[1] 0.6634291
yhat_23_grad2 <- predict(
z_model_grad2,
newdata = data.frame(Sprints_24 = z_sprints23$Sprints_23)
)
yhat_23_grad10 <- predict(
z_model_grad10,
newdata = data.frame(Sprints_24 = z_sprints23$Sprints_23)
)
rmse_23_grad2 <- rmse(z_sprints23$Pkt_23, yhat_23_grad2)
rmse_23_grad10 <- rmse(z_sprints23$Pkt_23, yhat_23_grad10)
rmse_23_grad2; rmse_23_grad10[1] 1.290033
[1] 1669.888
Ergebnis (auf der z-Skala):
RMSE für die Saison 22/23 mit Modell Grad 2: etwa 1,29
RMSE für die Saison 22/23 mit Modell Grad 10: etwa 1669,89
Die echten z-Punkte liegen ungefähr im Bereich von vielleicht −2 bis +2. (!)
Das Modell 2. Grades liegt im Schnitt etwa 1,29 Standardabweichungen daneben. Das ist bereits schlechter als ein triviales Modell, das immer nur den Mittelwert vorhersagt (RMSE = 1 auf der z-Skala).
Beim Modell 10. Grades “explodieren” die Vorhersagen vollständig: Es sagt für manche Teams Werte im Bereich von über 7000 Standardabweichungen voraus. Die quadratischen Fehler sind daher gigantisch, und der RMSE landet bei etwa 1669. Das Modell ist für Vorhersagen damit faktisch unbrauchbar.
Mathematisch lässt sich das als Overfitting beschreiben: Das Modell 10. Grades nutzt seine vielen Freiheitsgrade, um die 24er Daten sehr präzise zu modellieren. Die Struktur, die es gelernt hat, ist aber so an diese eine Saison angepasst, dass sie auf die Saison 22/23 also andere Daten, nicht übertragbar ist.
Fazit
Das Beispiel zeigt:
Hohe Varianzaufklärung im Trainingsdatensatz (hohes \(R^2\), kleiner RMSE) bedeutet nicht, dass ein Modell gute vorhersagen macht.
Polynome hohen Grades können die Trainingsdaten sehr gut treffen, scheitern aber auf neuen Daten dramatisch.
Ohne theoretische Leitplanken beschreibt Curve-Fitting häufig Zufallsschwankungen statt systematischer Zusammenhänge.
Für die Praxis heißt das:
Polynommodelle können zur Exploration interessant sein, sollten aber nie allein über ihre Passung auf einem Datensatz bewertet werden. Wichtiger sind theoretische Überlegungen und die Frage, wie sich ein Modell auf neue, unabhängige Daten überträgt.
Literatur
Colonescu, C. (2016). Principles of Econometrics with R. https://bookdown.org/ccolonescu/RPoE4/prediction-r-squared-and-modeling.html
Marewski, J. N., & Olsson, H. (2009). Beyond the null ritual: Formal modeling of psychological processes. Zeitschrift für Psychologie/Journal of Psychology, 217(1), 49–60.