Meu problema : recentemente, conheci um estatístico que me informou que as splines são úteis apenas para explorar dados e estão sujeitas a sobreajuste, portanto, não são úteis na previsão. Ele preferia explorar com polinômios simples ... Como sou um grande fã de splines, e isso vai contra a minha intuição. Estou interessado em descobrir quão válidos esses argumentos são e se existe um grande grupo de anti-splines- ativistas por aí?
Antecedentes : tento seguir Frank Harrell, Estratégias de Modelagem de Regressão (1), quando crio meus modelos. Ele argumenta que splines cúbicos restritos são uma ferramenta válida para explorar variáveis contínuas. Ele também argumenta que os polinômios são ruins na modelagem de certas relações, como limiares logarítmicos (2). Para testar a linearidade do modelo, ele sugere um teste ANOVA para o spline:
Pesquisei por overfitting com splines, mas não achei muito útil (além de avisos gerais sobre não usar muitos nós). Neste fórum, parece haver uma preferência pela modelagem de splines, Kolassa , Harrell , gung .
Eu encontrei uma postagem no blog sobre polinômios, o diabo da super adaptação que fala sobre a previsão de polinômios. A postagem termina com estes comentários:
Até certo ponto, os exemplos aqui apresentados são trapaceiros - sabe-se que a regressão polinomial é altamente não robusta. Muito melhor na prática é usar splines em vez de polinômios.
Agora, isso me levou a verificar o desempenho das splines com o exemplo:
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"))
Dá a seguinte imagem:
Em conclusão, não encontrei muita coisa que me convença de reconsiderar splines, o que estou perdendo?
- FE Harrell, Estratégias de modelagem de regressão: com aplicações em modelos lineares, regressão logística e análise de sobrevivência, reimpressão em capa mole da capa dura 1ª ed. 2001. Springer, 2010.
- FE Harrell, KL Lee e BG Pollock, "Modelos de Regressão em Estudos Clínicos: Determinando Relações entre Preditores e Resposta", JNCI J Natl Cancer Inst, vol. 80, n. 15, pp. 1198–1202, outubro de 1988.
Atualizar
Os comentários me fizeram pensar o que acontece no período de dados, mas com curvas desconfortáveis. Na maioria das situações, não vou além do limite de dados, como o exemplo acima indica. Não sei se isso se qualifica como previsão ...
Enfim, aqui está um exemplo em que eu crio uma linha mais complexa que não pode ser traduzida em um polinômio. Como a maioria das observações está no centro dos dados, tentei simular isso também:
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)
Isso fornece o seguinte gráfico:
Atualização 2
Desde este post, publiquei um artigo que analisa a não linearidade por idade em um grande conjunto de dados. O suplemento compara diferentes métodos e eu escrevi um post sobre isso .