R中GAM拟合光滑样条时节点数要求递增报错如何解决
问题核心原因
你遇到的节点数量报错,本质是对mgcv包中B样条基(bs="bs")的knots参数传参规则不熟悉导致的,两个核心错误:
- 你设置的
k=3基维度过低,三次B样条最少需要4个基函数才能成立,这个数值完全不足以拟合双峰分布的曲线形态,还会触发参数自动调整,导致节点数要求反复变化。 - 你传给
knots的只有3个自定义内部节点,但bs="bs"要求传入完整的全节点序列,必须覆盖x的取值边界、包含所有内部节点,不能只传你想手动指定的几个内部节点位置。
节点数量计算规则
默认状态下bs="bs"使用三次B样条(多项式次数为3,二阶差分惩罚),要求传入的节点总长度满足:总节点数 = k + 3,其中k是你在s()里设置的基维度。
不用死记硬背B样条阶数、边界重复次数的理论,最稳妥的方法是先跑一次不指定节点的临时模型,直接读取需要的节点长度,零出错:
# 临时拟合,获取需要的节点长度 tmp <- gam(y ~ s(x, bs = "bs", k = 10), data = data) req_knot_length <- length(tmp$smooth[[1]]$knots)
比如设置k=10时,返回的要求节点长度是13,和你之前遇到的“传7个节点又提示需要13个”的报错完全对应。
可复现的正确代码
你本来的需求是结合smooth.spline初步拟合的结果选节点,再传入gam做自定义节点的样条拟合,按下面的代码写即可:
library(npreg) library(splines) library(mgcv) x <- c(20.70, 20.44, 20.58, 21.02, 19.90, 6.20, 8.20, 6.92, 5.86, 6.44, 6.34, 8.48, 8.46, 9.00, 9.06, 9.00, 9.06, 17.98, 18.42, 19.18, 22.88, 24.16,20.20, 23.50) y <- c(19.884208, 12.772114, 12.932944, 5.016790, 11.405843, 3.310724, 3.950049, 3.641571, 4.073783, 4.616096, 3.425635, 7.773548, 7.498084, 9.474213, 6.162779, 11.041210, 12.618555, 6.287967, 4.286919, 3.242361, 7.571644, 3.379709, 5.274434, 8.8258) data = data.frame(x,y) # 第一步:初步smooth.spline拟合 fit_spline <- smooth.spline(x,y) # 提取初步拟合的节点,注意转换为原始x的尺度(smooth.spline内部将x标准化到[0,1]区间) init_knots <- fit_spline$fit$knots * (max(x) - min(x)) + min(x) # 结合双峰位置(一个峰在6-9区间,一个峰在20-24区间)自定义节点,凑够k=10要求的13个节点 my_knots <- c( rep(min(x),3), # 三次样条左边界重复3次 6,7,8,9,15,18,20, # 自定义内部节点,放在两个峰的关键位置 rep(max(x),3) # 三次样条右边界重复3次 ) # 第二步:拟合gam模型 myfit <- gam(y ~ s(x, bs = 'bs', k = 10), knots = list(x = my_knots), data = data) # 第三步:提取实际使用的内部节点、绘图 used_knots <- myfit$smooth[[1]]$xp plot(x, y, col= "grey", main = "自定义节点B样条拟合") lines(sort(x), myfit$fitted.values[order(x)], col = "red", lwd = 2) abline(v = used_knots, lty = 2, col = "blue")

注意:设置
k=10不会导致过拟合,mgcv的惩罚项会自动通过广义交叉验证调整光滑度,只需要保证k足够大、能捕捉数据的波动特征即可。
内容的提问来源于stack exchange,提问作者user8435999
相关产品推荐
相关产品推荐

