Моя проблема : Нещодавно я зустрічався зі статистиком, який повідомив мені, що сплайни корисні лише для дослідження даних і піддаються надмірній відповідності, тому не корисні для прогнозування. Він вважав за краще досліджувати прості полиноми ... Оскільки я великий фанат сплайнів, і це суперечить моїй інтуїції, мені цікаво дізнатися, наскільки ці аргументи справедливі, і чи існує велика група анти-сплайн- активісти там?
Передумови : Коли я створюю свої моделі, я намагаюся дотримуватися Франка Харрелла, стратегії регресійного моделювання (1). Він стверджує, що обмежені кубічні сплайни є вагомим інструментом для дослідження безперервних змінних. Він також стверджує, що поліноми бідні при моделюванні певних відносин, таких як пороги, логарифмічні (2). Для перевірки лінійності моделі він пропонує тест ANOVA для сплайну:
Я переглянув Google, щоб переобладнати сплайни, але не знайшов корисного (крім загальних попереджень про не занадто багато вузлів). На цьому форумі, здається, є перевага для сплайн-моделювання, Коласса , Харрелл , Гунг .
Я знайшов одну публікацію в блозі про поліноми, про чорт перенапруги, який говорить про передбачення поліномів. Допис закінчується цими коментарями:
В якійсь мірі приклади, представлені тут, є обманом - поліноміальна регресія, як відомо, є дуже ненадійною. Набагато краще на практиці використовувати сплайни, а не многочлени.
Тепер це підштовхнуло мене перевірити, як спрацюють сплайни на прикладі:
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"))
Надає таке зображення:
На закінчення я не знайшов багато чого, що переконувало б переглядати сплайни, чого я пропускаю?
- Ф. А. Гаррелл, стратегії регресійного моделювання: із застосуванням до лінійних моделей, логістичної регресії та аналізу виживання, передрук у твердій обкладинці твердої обкладинки 1-е видання. 2001. Спрингер, 2010.
- Ф. А. Гаррелл, К. Л. Лі та Б. Г. Поллок, “Регресійні моделі в клінічних дослідженнях: визначення взаємозв'язків між прогнозами та реакцією”, JNCI J Natl Cancer Inst, vol. 80, ні. 15, стор. 1198–1202, жовтень 1988.
Оновлення
Зауваження змусили мене замислитися, що відбувається в межах даних, але з незручними кривими. У більшості ситуацій я не виходжу за межі даних, як свідчить приклад вище. Я не впевнений, що це кваліфікується як передбачення ...
У всякому разі, ось приклад, коли я створюю більш складну лінію, яку неможливо перекласти в многочлен. Оскільки більшість спостережень знаходяться в центрі даних, я також намагався моделювати це:
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)
Це дає такий сюжет:
Оновлення 2
Починаючи з цієї публікації, я опублікував статтю, яка розглядає нелінійність за віком на великому наборі даних. Додаток порівнює різні методи, і я написав про це повідомлення в блозі .