Il mio problema : di recente ho incontrato uno statistico che mi ha informato che le spline sono utili solo per esplorare i dati e sono soggette a un eccesso di adattamento, quindi non utile nella previsione. Preferiva esplorare con semplici polinomi ... Dato che sono un grande fan delle spline, e questo va contro la mia intuizione, sono interessato a scoprire quanto siano validi questi argomenti e se esiste un grande gruppo di anti-spline- attivisti là fuori?
Background : provo a seguire Frank Harrell, Regression Modeling Strategies (1), quando creo i miei modelli. Sostiene che le spline cubiche con restrizioni sono uno strumento valido per esplorare variabili continue. Sostiene inoltre che i polinomi sono scarsi nel modellare determinate relazioni come soglie, logaritmiche (2). Per testare la linearità del modello, suggerisce un test ANOVA per la spline:
Ho cercato su Google per eccesso di adattamento con spline ma non ho trovato molto utile (a parte gli avvertimenti generali sul non usare troppi nodi). In questo forum sembra esserci una preferenza per la modellazione di spline, Kolassa , Harrell , gung .
Ho trovato un post sul blog sui polinomi, il diavolo del sovralimentazione che parla della previsione dei polinomi. Il post termina con questi commenti:
In una certa misura gli esempi qui presentati sono imbroglioni: la regressione polinomiale è altamente non robusta. Molto meglio in pratica è usare spline piuttosto che polinomi.
Ora questo mi ha spinto a verificare come si sarebbero comportate le spline con l'esempio:
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"))
Fornisce la seguente immagine:
In conclusione, non ho trovato molto che mi convincesse a riconsiderare le spline, cosa mi sto perdendo?
- FE Harrell, Strategie di modellazione della regressione: con applicazioni a modelli lineari, regressione logistica e analisi di sopravvivenza, ristampa rilegata in copertina rigida del 1 ° ed. 2001. Springer, 2010.
- FE Harrell, KL Lee e BG Pollock, "Modelli di regressione negli studi clinici: determinazione delle relazioni tra predittori e risposta", JNCI J Natl Cancer Inst, vol. 80, n. 15, pagg. 1198–1202, ottobre 1988.
Aggiornare
I commenti mi hanno fatto domandare cosa succede nell'arco di dati ma con curve scomode. Nella maggior parte delle situazioni non esco dal limite dei dati, come indica l'esempio sopra. Non sono sicuro che questo si qualifichi come previsione ...
Comunque ecco un esempio in cui creo una linea più complessa che non può essere tradotta in un polinomio. Dato che la maggior parte delle osservazioni sono al centro dei dati, ho cercato di simulare anche questo:
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)
Questo dà la seguente trama:
Aggiornamento 2
Da questo post ho pubblicato un articolo che esamina la non linearità per età in un set di dati di grandi dimensioni. Il supplemento confronta diversi metodi e ho scritto un post sul blog a riguardo .