【问题标题】:How to make monotonic (increasing) smooth spline with smooth.spline() function?如何使用 smooth.spline() 函数制作单调(递增)平滑样条?
【发布时间】:2014-08-22 13:17:33
【问题描述】:

我有严格递增的数据,并且由于该函数易于使用,如果可能的话,我希望使用 smooth.spline() 函数拟合单调递增的平滑样条曲线。

比如我的数据可以通过例子有效复现:

testx <- 1:100
testy <- abs(rnorm(length(testx)))^3
testy <- cumsum(testy)
plot(testx,testy)
sspl <- smooth.spline(testx,testy)
lines(sspl,col="blue")

这不一定在所有地方都在增加。有什么建议吗?

【问题讨论】:

  • 你可以改变一些参数来产生你想要的行为;这可能必须根据具体情况进行。 sspl &lt;- smooth.spline(testx,testy,tol = 3)(或分箱)适用于这个特定的数据集。
  • 谢谢!不幸的是,我正在寻找一个通用的解决方案。 IE。我的数据总是单调的,但每次运行样条曲线时都会有所不同。
  • 鉴于数据是单调递增的,那么样条曲线真的最有意义吗?为什么不拟合单调递增函数?只是一个想法。
  • 您也可以查看lowess 作为替代拟合方法。可以使用f 参数调整粒度。概括地说,您可以将其包装在一个方法中以尝试参数选项并检查 min(diff(sspl$y,1)) 以确保单调行为。

标签: r spline


【解决方案1】:

这不使用smooth.spline(),但splinefun(..., method="hyman") 将适合单调递增的样条曲线并且也易于使用。比如:

testx <- 1:100
testy <- abs(rnorm(length(testx)))^3
testy <- cumsum(testy)
plot(testx,testy)
sspl <- smooth.spline(testx,testy)
lines(sspl,col="blue")
tmp <- splinefun(x=testx, y=cumsum(testy), method="hyman")
lines(testx[-1], diff(tmp(testx)), col="red")

得到下图(红色是来自单调递增样条的值)

来自splinefun 的帮助文件:“方法“hyman”使用方法的海曼过滤计算单调三次样条 = “fmm”适合严格单调的输入。(在 R 2.15.2 中添加。)”

【讨论】:

  • splinefun 正是我所需要的。致未来的读者:splinefun 返回一个您可以直接调用的新函数,而不是返回传统 R 意义上的拟合模型。要使用此拟合样条函数预测新值,请调用新创建的函数并传入新数据。这取代了您习惯于传统模型拟合的predict 的使用。例如,MonotonicSpline &lt;- splinefun(x = toFit$x, y = toFit$y, method = "hyman"); monotonicFit &lt;- MonotonicSpline(inputVector)
  • 这仅适用于所有原始数据实际上都是单调递增的,即数据中没有噪声(否则 splinefun 会返回错误)。如果有,那么您可以在骗局或 cob 包中使用形状约束样条线,如下所述...
  • 回应@TomWenseleers:你对这仅适用于单调增加的数据是正确的。然而,这可能是由嘈杂的数据引起的,其中基础数据是嘈杂的,但您已经获取了一个累积总和,cumsum()。我过去曾使用它在具有非负值的时间序列中插入观察值。我希望在与我观察到的数据不同的时间尺度上进行观察。例如。我想要每周数据,但我只有每月对公共卫生监测病例数的观察(即必须大于或等于 0)。
【解决方案2】:

您可以为此使用形状约束样条线,例如使用scam 包:

require(scam)
fit = scam(testy~s(testx, k=100, bs="mpi", m=5), 
            family=gaussian(link="identity"))
plot(testx,testy)
lines(testx,predict(fit),col="red")

或者,如果您想使用 L1 损失而不是 L2 损失,后者对异常值不太敏感,您也可以为此使用 cobs 包...

与上述解决方案相比,此方法的优势在于,如果原始数据可能由于存在噪声而不是 100% 单调,它也可以工作...

【讨论】:

  • 很好的答案。对于单个回归器,cob 包是两者中最灵活的。
【解决方案3】:

我建议将loess 用于这种类型的单调递增函数。

检查样条的导数,我们发现它在某些情况下是负数且非平凡的:

> plot(testx,testy)
> sspl <- smooth.spline(testx,testy)
> min(diff(sspl$y))
[1] -0.4851321

如果我们使用黄土,我认为这个问题会不那么严重。

 d <- data.frame(testx,testy)
 fit.lo <- loess(testy ~ testx,data=d)
 lines(fit.lo$x,fit.lo$y)

然后检查我们得到的导数:

> min(diff(fit.lo$y))
[1] 1.151079e-12

本质上是 0。在接近 0 时,我们有时会得到一个很小的负值。

这是上述黄土拟合的示例。

不确定这是否适用于所有情况,但它似乎比样条线做得更好。

【讨论】:

    猜你喜欢
    • 2013-02-02
    • 2015-11-06
    • 2013-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-08
    相关资源
    最近更新 更多