在开始回答的主要部分之前,先澄清一下:在问题中,您说要最小化“拟合残差(输入信号和平滑信号之间的差异)”。最小化残差之和几乎从来没有意义,因为这个和可能是负数 - 因此,尝试最小化这个函数将导致可以找到的最大负残差和(通常甚至不会收敛,因为残差可以变得无限负)。几乎总是做的是最小化残差的平方和,这就是我在这里所做的。
让我们从一个返回残差平方和的支付函数开始
payoff <- function(fl, forder) {
M <- sav.gol(df[,1], fl = fl, forder = forder)
resid2 <- (M-df[,1])^2
sum(resid2)
}
请注意,我没有将 df 作为参数传递给此函数,而只是从父范围访问它。这是为了避免每次调用函数时不必要地复制数据帧,以减少内存和时间开销。
现在进入主要问题,对于整数值 1
这里的主要困难是优化参数fl和forder是整数。大多数典型的优化方法(例如那些由 optimize、optim 或 nlm 使用的方法)都是为连续参数的连续函数而设计的。离散优化完全是另一回事,其方法包括遗传算法等方法。例如,有关整数或离散优化的一些方法,请参阅这些 SO 帖子 here 和 here。
对于离散优化没有完美的解决方案,尤其是当您正在寻找全局最小值而不是局部最小值时。在您的情况下,残差平方和(收益)函数的表现不是很好并且会振荡。所以我们真的应该寻找一个全局最小值,而不是可能有很多的局部最小值。找到全局最小值的唯一确定方法是通过蛮力,实际上我们可以在这里采用这种方法,因为蛮力解决方案可以在合理的时间长度内计算。以下代码将计算 fl 和 forder 的所有值下的收益(目标)函数:
resord2 <- sapply(1:NROW(df), FUN= function(x) payoff(x, 2))
resord4 <- sapply(1:NROW(df), FUN= function(x) payoff(x, 4))
计算这些函数的时间仅随数据行数线性增加。使用你的 43k 行,这在我不是特别快的笔记本电脑上大约需要一天半的时间。
不过,幸运的是,我们不需要投入那么多计算时间。下图显示了 forder=2(蓝线)和 forder=4(红线)的残差平方和,fl up 为 40。
resord2 <- sapply(1:40, FUN= function(x) payoff(x, 2))
resord4 <- sapply(1:40, FUN= function(x) payoff(x, 4))
plot(1:40, resord2, log="y", type="l", col="blue", xlab="dl", ylab="residual sum of squares")
lines(1:40, resord4, col="red")
很明显,fl 的高值会导致高残差平方和。因此我们可以将优化搜索限制在 dl
resord2 <- sapply(1:40, FUN= function(x) payoff(x, 2))
resord4 <- sapply(1:40, FUN= function(x) payoff(x, 4))
which.min(resord2)
# 3
which.min(resord4)
# 3
如果我们想说服自己残差平方和确实会在更大范围内随着 fl 的增加而增加,我们可以使用更大范围的值来创建快速现实检查,让 fl 以更大的步长递增:
low_fl <- 10
high_fl <- 100
step_size <- 10
fl <- seq(low_fl, high_fl, by=step_size)
resord2 <- sapply(fl, FUN= function(x) payoff(x, 2))
plot(fl, resord2)