Mon problème : j'ai récemment rencontré un statisticien qui m'a informé que les splines ne sont utiles que pour explorer des données et sont sujettes à un surajustement, ce qui n'est donc pas utile pour la prédiction. Il préférait explorer avec des polynômes simples ... Comme je suis un grand fan des splines et que cela va à l'encontre de mon intuition, je suis curieux de savoir si ces arguments sont valables et s'il existe un grand groupe d' anti-splines ... les activistes là-bas?
Contexte : J'essaie de suivre Frank Harrell, Stratégies de modélisation par régression (1), lors de la création de mes modèles. Il soutient que les splines cubiques restreintes sont un outil valable pour explorer des variables continues. Il soutient également que les polynômes sont médiocres pour la modélisation de certaines relations telles que les seuils, logarithmique (2). Pour tester la linéarité du modèle, il propose un test ANOVA pour la spline:
J'ai cherché sur Google pour avoir trop équipé de splines mais je n'ai pas trouvé cela très utile (mis à part les avertissements généraux de ne pas utiliser trop de nœuds). Dans ce forum, il semble y avoir une préférence pour la modélisation spline, Kolassa , Harrell , Gung .
J'ai trouvé un article de blog sur les polynômes, le diable de l'overfitting, qui parle de la prédiction des polynômes. Le post se termine par ces commentaires:
Dans une certaine mesure, les exemples présentés ici sont de la triche - la régression polynomiale est réputée pour être extrêmement robuste. En pratique, il est préférable d’utiliser des splines plutôt que des polynômes.
Maintenant, cela m'a incité à vérifier comment les splines fonctionneraient avec l'exemple:
library(rms)
p4 <- poly(1:100, degree=4)
true4 <- p4 %*% c(1,2,-6,9)
days <- 1:70
set.seed(7987)
noise4 <- true4 + rnorm(100, sd=.5)
reg.n4.4 <- lm(noise4[1:70] ~ poly(days, 4))
reg.n4.4ns <- lm(noise4[1:70] ~ ns(days,4))
dd <- datadist(noise4[1:70], days)
options("datadist" = "dd")
reg.n4.4rcs_ols <- ols(noise4[1:70] ~ rcs(days,5))
plot(1:100, noise4)
nd <- data.frame(days=1:100)
lines(1:100, predict(reg.n4.4, newdata=nd), col="orange", lwd=3)
lines(1:100, predict(reg.n4.4ns, newdata=nd), col="red", lwd=3)
lines(1:100, predict(reg.n4.4rcs_ols, newdata=nd), col="darkblue", lwd=3)
legend("top", fill=c("orange", "red","darkblue"),
legend=c("Poly", "Natural splines", "RCS - ols"))
Donne l'image suivante:
En conclusion, je n'ai pas trouvé grand chose qui me convaincrait de reconsidérer les splines. Qu'est-ce qui me manque?
- FE Harrell, Stratégies de modélisation par régression: avec applications aux modèles linéaires, régression logistique et analyse de survie, réimpression à couverture souple de la couverture rigide 1st ed. 2001. Springer, 2010.
- FE Harrell, KL Lee et BG Pollock, «Modèles de régression dans les études cliniques: détermination des relations entre les prédicteurs et la réponse», JNCI J Natl Cancer Inst, vol. 80, non. 15, pages 1198 à 1202, octobre 1988.
Mise à jour
Les commentaires m'ont fait me demander ce qui se passe dans la plage de données mais avec des courbes inconfortables. Dans la plupart des situations, je ne vais pas hors des limites de données, comme le montre l'exemple ci-dessus. Je ne suis pas sûr que cela soit qualifié de prédiction ...
Quoi qu'il en soit, voici un exemple où je crée une ligne plus complexe qui ne peut pas être traduite en polynôme. Comme la plupart des observations sont au centre des données, j'ai essayé de simuler cela aussi:
library(rms)
cmplx_line <- 1:200/10
cmplx_line <- cmplx_line + 0.05*(cmplx_line - quantile(cmplx_line, .7))^2
cmplx_line <- cmplx_line - 0.06*(cmplx_line - quantile(cmplx_line, .3))^2
center <- (length(cmplx_line)/4*2):(length(cmplx_line)/4*3)
cmplx_line[center] <- cmplx_line[center] +
dnorm(6*(1:length(center)-length(center)/2)/length(center))*10
ds <- data.frame(cmplx_line, x=1:200)
days <- 1:140/2
set.seed(1234)
sample <- round(rnorm(600, mean=100, 60))
sample <- sample[sample <= max(ds$x) &
sample >= min(ds$x)]
sample_ds <- ds[sample, ]
sample_ds$noise4 <- sample_ds$cmplx_line + rnorm(nrow(sample_ds), sd=2)
reg.n4.4 <- lm(noise4 ~ poly(x, 6), data=sample_ds)
dd <- datadist(sample_ds)
options("datadist" = "dd")
reg.n4.4rcs_ols <- ols(noise4 ~ rcs(x, 7), data=sample_ds)
AIC(reg.n4.4)
plot(sample_ds$x, sample_ds$noise4, col="#AAAAAA")
lines(x=ds$x, y=ds$cmplx_line, lwd=3, col="black", lty=4)
nd <- data.frame(x=ds$x)
lines(ds$x, predict(reg.n4.4, newdata=ds), col="orange", lwd=3)
lines(ds$x, predict(reg.n4.4rcs_ols, newdata=ds), col="lightblue", lwd=3)
legend("bottomright", fill=c("black", "orange","lightblue"),
legend=c("True line", "Poly", "RCS - ols"), inset=.05)
Cela donne l'intrigue suivante:
Mise à jour 2
Depuis cet article, j'ai publié un article sur la non-linéarité de l'âge sur un grand ensemble de données. Le supplément compare différentes méthodes et j'ai écrit un billet de blog à ce sujet .