Programming lesson
Penalisierte Spline-Regression und Kernel-Schätzer in R: Eine praktische Anleitung mit dem WarsawApts-Datensatz
Lerne, wie du mit R lineare Spline-Basisfunktionen und Kernel-Regression implementierst – inklusive praktischer Beispiele aus der Computational Statistics. Perfekt für Studierende der Datenwissenschaft.
Einleitung: Splines und Kernel – die Werkzeuge der modernen Datenwissenschaft
In der Computational Statistics und Data Science geht es oft darum, flexible Modelle zu bauen, die nichtlineare Zusammenhänge erfassen. Zwei mächtige Ansätze sind penalisierte Spline-Regression und Kernel-Regression. In diesem Tutorial zeige ich dir Schritt für Schritt, wie du beide Methoden in R umsetzt – basierend auf dem Datensatz WarsawApts aus der Bibliothek HRW. Der Fokus liegt auf dem Verständnis der Algorithmen, nicht auf Copy-Paste-Lösungen. Stell dir vor, du entwickelst ein KI-Modell, das Immobilienpreise in Berlin vorhersagt – genau solche Techniken brauchst du dafür.
1. Penalisierte Spline-Regression (PSR) implementieren
1.1 Datenvorbereitung und Knotenauswahl
Zuerst laden wir den Datensatz und extrahieren die Variable construction.date als x und areaPerMzloty als y. Die Knoten für die Spline-Basis werden mit quantile erzeugt – ein typischer Schritt, den du auch in anderen Projekten wie der Analyse von Aktienkursen oder Temperaturdaten brauchst.
library(HRW)
data(WarsawApts)
x <- WarsawApts$construction.date
y <- WarsawApts$areaPerMzloty
probs <- seq(0, 1, length = 22)[-c(1, 22)]
k <- quantile(x, probs = probs)1.2 Z-Matrix der linearen Spline-Basisfunktionen
Die linearen Spline-Basisfunktionen sind definiert als (x - k_i)_+. Das erzeugt eine Matrix Z mit 20 Spalten. Du kannst dir das wie die versteckten Schichten in einem neuronalen Netz vorstellen – jede Basis reagiert auf einen bestimmten Bereich von x.
Z <- outer(x, k, function(x, k) pmax(x - k, 0))
matplot(x, Z, type = "l", ylim = c(-1, 2), xlab = "Baujahr", ylab = "Basis", main = "Lineare Spline-Basisfunktionen")1.3 C-Matrix und D-Matrix für die Penalized Regression
Die C-Matrix kombiniert einen Einservektor, x und Z (Größe n × 22). Die D-Matrix ist eine Diagonalmatrix, die die ersten beiden Diagonalelemente auf Null setzt (keine Bestrafung für den linearen Teil). Das ist typisch für penalisierte Splines – sie glätten die Kurve und verhindern Overfitting.
C <- cbind(1, x, Z)
D <- diag(22)
D[1:2, 1:2] <- 01.4 Tuning-Parameter λ und GCV
Wir testen 100 Werte von λ zwischen 0 und 50. Für jeden λ berechnen wir die Koeffizienten via solve(t(C) %*% C + lambda * D) %*% t(C) %*% y. Dann folgen RSS, Freiheitsgrade und GCV – das ist wie die Kreuzvalidierung bei der Hyperparameter-Optimierung in Machine-Learning-Modellen.
lambda_seq <- seq(0, 50, length = 100)
RSS <- numeric(100)
df <- numeric(100)
GCV <- numeric(100)
for(i in 1:100) {
beta_hat <- solve(t(C) %*% C + lambda_seq[i] * D) %*% t(C) %*% y
y_hat <- C %*% beta_hat
RSS[i] <- sum((y - y_hat)^2)
H <- C %*% solve(t(C) %*% C + lambda_seq[i] * D) %*% t(C)
df[i] <- sum(diag(H))
GCV[i] <- RSS[i] / (1 - df[i]/length(y))^2
}1.5 Optimale Anpassung und Vergleich mit mehr Basen
Das λ mit minimalem GCV liefert die beste Anpassung. Mit 20 Basen wirkt die Kurve oft zu linear – wie ein Underfitted Modell. Erhöhen wir die Anzahl der Knoten auf 60, wird die Kurve flexibler. Der MSE zeigt, ob die Verbesserung signifikant ist. In der Praxis wählst du die Anzahl der Basen ähnlich wie die Anzahl der Neuronen in einem Netzwerk.
opt_idx <- which.min(GCV)
y_hat_opt <- C %*% solve(t(C) %*% C + lambda_seq[opt_idx] * D) %*% t(C) %*% y
plot(x, y, main = "Anpassung mit optimalem λ")
lines(x[order(x)], y_hat_opt[order(x)], col = "red", lwd = 2)2. Kernel-Regression: K-Nächste-Nachbarn und Kernel-Gewichtung
2.1 K-NN-Averaging
Der k-NN-Ansatz ist intuitiv: Für jeden Punkt x_i suchst du die k nächsten Nachbarn und mittelst deren y-Werte. Das erinnert an Empfehlungssysteme: „Nutzer mit ähnlichem Verhalten mögen ähnliche Produkte“. Hier testen wir k = 3, 7, 11, 15, 19, 23.
k_vals <- c(3, 7, 11, 15, 19, 23)
y_hat_knn <- matrix(NA, nrow = length(y), ncol = length(k_vals))
for (j in seq_along(k_vals)) {
for (i in seq_along(x)) {
d <- abs(x[i] - x)
idx <- order(d)[1:k_vals[j]]
y_hat_knn[i, j] <- mean(y[idx])
}
}Die MSE-Werte zeigen, welches k am besten ist. Oft schneidet k-NN bei glatten Funktionen schlechter ab als Splines – ähnlich wie ein simpler Klassifikator gegen ein tiefes Netzwerk verliert.
2.2 Sechs Kernel-Funktionen für die Kernel-Regression
Wir schreiben eine einzige Funktion, die sechs gängige Kernel berechnet: Uniform, Triangular, Epanechnikov, Quartic, Triweight und Gaussian. Das ist wie verschiedene Aufmerksamkeitsmechanismen in Transformer-Modellen – jeder Kernel gewichtet die Nachbarschaft anders.
kernel_fun <- function(u) {
u_abs <- abs(u)
uniform <- ifelse(u_abs <= 1, 0.5, 0)
triangular <- ifelse(u_abs <= 1, 1 - u_abs, 0)
epanechnikov <- ifelse(u_abs <= 1, 0.75 * (1 - u^2), 0)
quartic <- ifelse(u_abs <= 1, (15/16) * (1 - u^2)^2, 0)
triweight <- ifelse(u_abs <= 1, (35/32) * (1 - u^2)^3, 0)
gaussian <- (1/sqrt(2*pi)) * exp(-0.5 * u^2)
c(uniform, triangular, epanechnikov, quartic, triweight, gaussian)
}2.3 Kernel-Regression mit fester Bandbreite
Mit Bandbreite h = 2 berechnen wir für jeden Punkt x_i die gewichteten Mittel. Die Formel f_hat(x_i) = sum(K_h(x_i, x_j) * y_j) / sum(K_h(x_i, x_j)) ist das Herzstück der Nadaraya-Watson-Schätzung. Das Ergebnis: sechs geglättete Kurven, eine pro Kernel.
h <- 2
n <- length(x)
f_hat <- matrix(0, nrow = n, ncol = 6)
for (i in 1:n) {
u <- (x[i] - x) / h
K <- t(sapply(u, kernel_fun))
K <- t(K) / h # Skalierung
for (j in 1:6) {
f_hat[i, j] <- sum(K[j, ] * y) / sum(K[j, ])
}
}Die MSE-Werte zeigen, dass der Gauß-Kernel oft die geringsten Fehler liefert – ähnlich wie die Radial Basis Function (RBF) in Support Vector Machines.
3. Ausblick: Expectation-Maximization (EM) für Gaußsche Mischmodelle
Obwohl wir hier nicht ins Detail gehen, ist der EM-Algorithmus ein weiteres wichtiges Werkzeug. Stell dir vor, du analysierst die Gehälter in einem Unternehmen – oft gibt es mehrere Gruppen (z.B. Junior, Senior, Management) mit unterschiedlichen Mittelwerten und Varianzen. Der EM-Algorithmus schätzt diese Parameter, ohne dass du die Gruppenzugehörigkeit kennst. Das ist wie ein Clustering, aber mit Wahrscheinlichkeiten.
Fazit
Du hast gesehen, wie du penalisierte Spline-Regression und Kernel-Regression selbst codest – ohne fertige Pakete. Diese Techniken sind grundlegend für Computational Statistics und Data Science. Mit den Konzepten aus diesem Tutorial kannst du nun eigene nichtlineare Modelle bauen, sei es für Immobilienpreise, Aktienkurse oder sogar für die Analyse von Gaming-Daten (z.B. Spielerleistung über Zeit). Probiere es selbst aus und variiere die Parameter – so vertiefst du dein Verständnis.