要求样条曲线凸出

时间:2014-09-29 21:17:52

标签: r spline

我需要将样条拟合到一组数据,并且结果函数需要单调递减和凸起。我传递给splinefun的数据保证具有这些属性,但这并不能保证得到的函数是凸的。有没有办法将样条拟合到一组数据并要求结果函数是凸的?

2 个答案:

答案 0 :(得分:8)

首先提供一些示例数据:

x = c(0,1,2,3,4,5,6)
y = c(2,1, 0.59, 0.27, 0.25, -0.23, -0.45)
dat <- data.frame(x=x,y=y)

Monotonic Spline

我们可以使用splinefun(x,y,"monoH.FC")进行单调样条,如@fang建议的那样。

# Setting up Monotonic Spline
MonoSpline = splinefun(x,y,"monoH.FC")
#Getting Ready for plotting Monotonic Spline
xArray = seq(0,6,0.01)
MonoResult = MonoSpline(xArray)

Monotonic Convex Spline(带骗局包)

对于单调凸样条,您需要使用scam包。那么我们可以:

# Setting up Monotonic Convex Spline
# install.packages("scam")
require(scam)
MonoConvexSpline <- scam(y~s(x,k=4,bs="mdcx",m=1),data=dat)
MonoConvexSplinePredict =function(Test){
  predict.scam(MonoConvexSpline,data.frame(x = Test))
} 
#Getting Ready for plotting Monotonic Convex Spline
MonoConvexSplineResult = MonoConvexSplinePredict(xArray)

请注意以下事项:

  1. 选项bs="mdcx"表示我们需要减少凸花键。如果你想增加凸面,减少凹面等,那么请查找相应的bshere
  2. 如果您将非单调数据放入splinefun(x,y,"monoH.FC")函数,我们会收到错误。
  3. 如果您将非凸数据放入scam函数,那么您仍然会得到一个样条曲线。改变数据以使小凸起变为凸起。没有任何警告,所以要小心,因为您的数据可能看起来完全不同。作为一个例子,下面的图是使用与上面相同的代码制作的,除了我们bs="mdcv"用于减少凹函数:
  4. 单调凸花键(带有玉米棒包装)

    # Convex Cobs Spline
    library(cobs)
    spCobs = cobs(x , y, constraint = c("decrease", "convex"), nknots = 8)
    spCobsResults = predict(spCobs, xArray)[,2] 
    

    绘制一切

    然后用

    绘制它们
    Plot = qplot(xlab = "x", ylab = "y")
    Plot = Plot + geom_line(aes(xArray,MonoResult            , colour = "Monotonic Spline"            ))
    Plot = Plot + geom_line(aes(xArray,MonoConvexSplineResult, colour = "Monotonic Convex scam Spline"))
    Plot = Plot + geom_line(aes(xArray,spCobsResults         , colour = "Monotonic Convex cobs Spline"))
    Plot
    

    Monotonic and Convex Splines

    速度

    • 使用scam函数预测点需要更长的时间 使用单调样条或cobs样条。您可以从下面的microbenchmark
    • 中看到这一点
    • cobs样条曲线和scam样条曲线初始计算所需的时间比一般单调样条曲线要长得多。

    # Prediction
    library(microbenchmark)
        microbenchmark(
          MonoSpline(xArray),
          predict.scam(MonoConvexSpline,data.frame(x = xArray)),
          predict(spCobs, xArray)[,2] 
        )
    
    Unit: microseconds
                                                       expr      min        lq      mean    median        uq      max neval
                                         MonoSpline(xArray)  141.540  147.8175  223.3695  156.9490  167.9830 1593.456   100
     predict.scam(MonoConvexSpline, data.frame(x = xArray)) 2778.655 2838.0095 3161.2282 2914.8665 3153.4285 6168.741   100
                               predict(spCobs, xArray)[, 2]  125.179  133.1690  155.1226  145.1535  162.2755  366.784   100
    
    # Calculating Spline
    library(microbenchmark)
    microbenchmark(
      splinefun(x,y,"monoH.FC"),
      scam(y~s(x,k=4,bs="mdcx",m=1),data=dat),
      cobs(x , y, constraint = c("decrease", "convex"), nknots = 8) 
    )
    
    Unit: microseconds
                                                             expr        min         lq        mean      median         uq       max neval
                                      splinefun(x, y, "monoH.FC")     90.175    127.462    411.6407    153.7155    198.993  24877.47   100
            scam(y ~ s(x, k = 4, bs = "mdcx", m = 1), data = dat) 166769.270 196719.139 231631.5321 224372.7940 265074.525 355734.37   100
     cobs(x, y, constraint = c("decrease", "convex"), nknots = 8) 145511.335 172887.618 203786.0940 202997.4795 228688.607 347661.29   100
    

答案 1 :(得分:1)

我对这个问题的另一个答案显示单调样条和玉米棒和骗局形状约束样条。这些形状约束样条的问题是它们相当慢,并且不一定要插入所有数据点。

Schumaker Spline

我已经发布了一个实现Schumaker样条的包,如果数据是单调的和凸/凹的,它是单调的和凸/凹的。它很快并且插入所有数据点。

举个例子:

#install.packages("schumaker")
library(schumaker)

x = seq(1,10)
y = -log(x)
xarray = seq(1,10,0.01)

SchumSpline = schumaker::Schumaker(x,y)
Schum0 = SchumSpline$Spline(xarray)
Schum1 = SchumSpline$DerivativeSpline(xarray)
Schum2 = SchumSpline$SecondDerivativeSpline(xarray)

plot(xarray, Schum0, type = "l", col = 4, ylim = c(-3,1), main = "Schumaker Spline and first two derivatives",
     ylab = "Spline and derivatives", xlab = "x")
points(x,y)
lines(xarray, Schum1, col = 2)
lines(xarray, Schum2, col = 3)
abline(h = 0, col = 1)
text(x=rep(8,8,8), y=c(-2, -0.5,+0.2), pos=4, labels=c('Spline', 'First Derivative', 'Second Derivative'))

Schumaker Spline and Derivatives

您可以看到二阶导数始终为正(对于正常的单调样条曲线,情况并非如此。请参阅包的插图)。

请注意,如果数据是全局凸/凹,则样条曲线将仅为全局凸/凹。这是不可避免的,因为这是一个插值样条曲线。

此样条曲线比cobs和scam样条曲线快。创建比单调样条更慢,但评估速度更快。可以在小插图中找到全速测试。