我需要将样条拟合到一组数据,并且结果函数需要单调递减和凸起。我传递给splinefun的数据保证具有这些属性,但这并不能保证得到的函数是凸的。有没有办法将样条拟合到一组数据并要求结果函数是凸的?
答案 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)
我们可以使用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)
对于单调凸样条,您需要使用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)
请注意以下事项:
bs="mdcx"
表示我们需要减少凸花键。如果你想增加凸面,减少凹面等,那么请查找相应的bs
值here。splinefun(x,y,"monoH.FC")
函数,我们会收到错误。scam
函数,那么您仍然会得到一个样条曲线。改变数据以使小凸起变为凸起。没有任何警告,所以要小心,因为您的数据可能看起来完全不同。作为一个例子,下面的图是使用与上面相同的代码制作的,除了我们bs="mdcv"
用于减少凹函数:# 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
scam
函数预测点需要更长的时间
使用单调样条或cobs样条。您可以从下面的microbenchmark
# 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样条的包,如果数据是单调的和凸/凹的,它是单调的和凸/凹的。它很快并且插入所有数据点。
举个例子:
#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'))
您可以看到二阶导数始终为正(对于正常的单调样条曲线,情况并非如此。请参阅包的插图)。
请注意,如果数据是全局凸/凹,则样条曲线将仅为全局凸/凹。这是不可避免的,因为这是一个插值样条曲线。
此样条曲线比cobs和scam样条曲线快。创建比单调样条更慢,但评估速度更快。可以在小插图中找到全速测试。