R smooth.spline(): smoothing spline is not smooth but overfitting my data
我有几个数据点似乎适合通过它们拟合样条曲线。当我这样做时,我得到了一个相当坎bump的拟合,例如过度拟合,这不是我所理解的平滑。
是否有一个特殊的选项/参数来恢复像这样的非常平滑的样条曲线的功能。
以下是数据和代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | results <- structure( list( beta = c( 0.983790622281964, 0.645152464354322, 0.924104713597375, 0.657703886566088, 0.788138034115623, 0.801080207252363, 1, 0.858337365965949, 0.999687052533693, 0.666552625121279, 0.717453633245958, 0.621570152961453, 0.964658181346544, 0.65071758770312, 0.788971505000918, 0.980476054183113, 0.670263506919246, 0.600387040967624, 0.759173403408052, 1, 0.986409675965, 0.982996471134736, 1, 0.995340781899163, 0.999855895958986, 1, 0.846179233381267, 0.879226324448832, 0.795820998892035, 0.997586607285667, 0.848036806290156, 0.905320944437968, 0.947709125535428, 0.592172373022407, 0.826847031044922, 0.996916006944244, 0.785967729206612, 0.650346929853076, 0.84206351833549, 0.999043126652724, 0.936879214753098, 0.76674066557003, 0.591431233516217, 1, 0.999833445117791, 0.999606223666537, 0.6224971799303, 1, 0.974537160571494, 0.966717133936379 ), inventoryCost = c( 1750702.95138889, 442784.114583333, 1114717.44791667, 472669.357638889, 716895.920138889, 735396.180555556, 3837320.74652778, 872873.4375, 2872414.93055556, 481095.138888889, 538125.520833333, 392199.045138889, 1469500.95486111, 459873.784722222, 656220.486111111, 1654143.83680556, 437511.458333333, 393295.659722222, 630952.170138889, 4920958.85416667, 1723517.10069444, 1633579.86111111, 4639909.89583333, 2167748.35069444, 3062420.65972222, 5132702.34375, 838441.145833333, 937659.288194444, 697767.1875, 2523016.31944444, 800903.819444444, 1054991.49305556, 1266970.92013889, 369537.673611111, 764995.399305556, 2322879.6875, 656021.701388889, 458403.038194444, 844133.420138889, 2430700, 1232256.68402778, 695574.479166667, 351348.524305556, 3827440.71180556, 3687610.41666667, 2950652.51736111, 404550.78125, 4749901.64930556, 1510481.59722222, 1422708.07291667 ) ), .Names = c("beta","inventoryCost"), class = c("data.frame") ) plot(results$beta,results$inventoryCost) mySpline <- smooth.spline(results$beta,results$inventoryCost, penalty=999999) lines(mySpline$x, mySpline$y, col="red", lwd = 2) |
在建模之前合理地转换数据
根据您的
1 2 3 4 5 6 | x <- results$beta; y <- log(results$inventoryCost) reorder <- order(x); x <- x[reorder]; y <- y[reorder] par(mfrow = c(1,2)) plot(x, y, main ="take log transform") hist(x, main ="x is skewed") |
左图看起来更好吗?另外,强烈建议对
以下转换是合适的:
1 | x1 <- -(1-x)^(1/3) |
1 2 3 | par(mfrow = c(1,2)) plot(x1, y, main = expression(y %~% ~ x1)) hist(x1, main ="x1 is well spread out") |
拟合样条线
现在,我们可以进行统计建模了。尝试以下呼叫:
1 2 3 4 5 | fit <- smooth.spline(x1, y, nknots = 10) pred <- stats:::predict.smooth.spline(fit, x1)$y ## predict at all x1 ## or you can simply call: pred <- predict(fit, x1)$y plot(x1, y) ## scatter plot lines(x1, pred, lwd = 2, col = 2) ## fitted spline |
看起来不错吗?注意,我已经使用
我也放下了
要将拟合转换回原始比例,请执行以下操作:
1 2 | plot(x, exp(y), main = expression(Inventory %~%~ beta)) lines(x, exp(pred), lwd = 2, col = 2) |
如您所见,拟合的样条曲线与您期望的一样平滑。
拟合样条线的说明
让我们看一下拟合的样条线的摘要:
1 2 3 4 5 6 | > fit Smoothing Parameter spar= 0.4549062 lambda= 0.0008657722 (11 iterations) Equivalent Degrees of Freedom (Df): 6.022959 Penalized Criterion: 0.08517417 GCV: 0.004288539 |
我们使用了10个结,以6个自由度结束,因此惩罚可抑制约4个参数。经过11次迭代后,选择的平滑参数GCV为
为什么我们必须将
1 2 3 4 5 | y0 <- as.numeric(tapply(y, x, mean)) ## remove tied values x0 <- unique(x) ## remove tied values dy0 <- diff(y0)/diff(x0) ## 1st order difference ddy0 <- diff(dy0)/diff(x0[-1]) ## 2nd order difference plot(x0[1:43], abs(ddy0), pch = 19) |
看看二阶差分/导数的巨大峰值!现在,如果我们直接拟合样条曲线,则围绕此更改点的样条曲线将受到严重惩罚。
1 2 3 4 5 | bad <- smooth.spline(x, y, all.knots = TRUE) bad.pred <- predict(bad, x)$y plot(x, exp(y), main = expression(Inventory %~% ~ beta)) lines(x, exp(bad.pred), col = 2, lwd = 3) abline(v = 0.98, lwd = 2, lty = 2) |
您可以清楚地看到,在
当然,有一些方法可以在此更改点之后获得更好的逼近度,例如,通过手动设置较小的平滑参数或较高的自由度。但是,我们将走向另一个极端。请记住,惩罚和自由度都是一项全球措施。在
1 2 3 4 | worse <- smooth.spline(x, y, all.knots = TRUE, df = 45) worse.pred <- predict(worse, x)$y plot(x, exp(y), main = expression(Inventory %~% ~ beta)) lines(x, exp(worse.pred), col = 2, lwd = 2) |
如您所见,曲线凹凸不平。当然,我们已经过拟合了50个数据集和45个自由度。
实际上,您最初对
1 2 3 4 5 6 7 8 | > mySpline Call: smooth.spline(x = results$beta, y = results$inventoryCost, penalty = 999999) Smoothing Parameter spar= -0.8074624 lambda= 3.266077e-19 (17 iterations) Equivalent Degrees of Freedom (Df): 45 Penalized Criterion: 5.598386 GCV: 0.03824885 |
糟糕,自由度为45,过拟合!
我不认为您应该使用/想要
1 2 3 4 5 6 7 8 9 | library(mgcv) fit <- gam(inventoryCost ~ s(beta, bs ="cr", k = 20), data = results) summary(fit) gam.check(fit) plot(fit) plot(inventoryCost ~ beta, data = results, col ="dark red", , pch = 16) curve(predict(fit, newdata = data.frame(beta = x)), add = TRUE, from = min(results$beta), to = max(results$beta), n = 1e3, lwd = 2) |