我有两个想法,但都有缺点。也许你可以根据自己的需求调整其中一个。很遗憾此时无法访问Drive,所以使用了一些人工数据。
1. 手动拟合多项式模型
在这里,您可以指定任何您喜欢的模型,一些段可以是lm,一些可以是多项式等。
代码:
library(segmented)
library(ggplot2)
library(data.table)
set.seed(12)
xx <- 1:100
yy <- 2 + 1.5 * pmax(xx-35, 0) - 1.5 * pmax(xx-70, 0) + 15 * pmax(runif(100) - 0.5, 0) + rnorm(100, 0, 2)
dt <- data.table(x = xx, y = yy, type = 'act')
dt_all <- copy(dt)
lm_lin <- lm(y ~ x, data = dt)
summary(lm_lin)
lm_seg <- segmented(
lm_lin, seg.Z = ~ x, psi = list(x = c(30, 80)))
breaks <- unname(lm_seg$psi[, 'Est.'])
lm_poly1 <- lm(y ~ poly(x, 4), data = dt[x < breaks[1], ])
lm_2 <- lm(y ~ x, data = dt[x > breaks[1] & x < breaks[2], ])
lm_poly3 <- lm(y ~ poly(x, 4), data = dt[x > breaks[2], ])
dt_all <- rbind(
dt_all,
data.table(x = xx, y = c(
predict(lm_poly1),
predict(lm_2),
predict(lm_poly3)),
type = 'lm_poly'
)
)
2. 使用segmented
中的断点和一些样条拟合gam模型
在这里,您将获得分段之间的平滑过渡,但对发生的情况很少有控制。
library(mgcv)
spl <- gam(y ~ s(x, bs = "cc", k = 12), data = dt, knots = list(xx = breaks))
dt_all <- rbind(dt_all, data.table(x = xx, y = predict(spl), type = 'spl'))
ggplot(dt_all, aes(x = x, y = y)) + geom_point(size = 1) +
facet_grid(. ~ type) + theme_minimal()
![enter image description here](https://istack.dev59.com/tgSs2.webp)
这两个可以用list()
和lapply()
等方法自动化处理(对于不同数量的间断点等)。
编辑:
通过修改poly
和s
的参数,你可以得到略微“更好”的拟合模型,但是对于gam
而言,误差在边缘处相当大,参见degree = 6
和k = 30
的情况:
![enter image description here](https://istack.dev59.com/90HF0.webp)