How to make a monotonous (increasing) smooth spline with the smooth.spline () function?

I have data that is strictly growing and would like to place a smoothing spline that monotonously grows also using the smooth.spline() function, if possible, due to the ease of use of this function.

For example, my data can be efficiently reproduced using an example:

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

which does not necessarily increase everywhere. Any suggestions?

+5
source share
3 answers

This does not use smooth.spline() , but splinefun(..., method="hyman") will correspond to a monotonously increasing spline, and is also easy to use. For example:

 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") 

The following figure displays (red - values ​​from a monotonously growing spline) enter image description here

From the splinefun help splinefun : "The hyman method computes a monotonic cubic spline using Hyman filtering of the method =" fmm ", suitable for strictly monotonic inputs (added in R 2.15.2.)"

+6
source

I would suggest using loess for this type of monotonically increasing function.

Studying the derivative of a spline, we see that in some cases it is negative and nontrivial:

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

If we use loess, I think this problem will be less serious.

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

Then, checking the derivative, we get:

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

This is essentially 0. Near 0, we sometimes get a trivially smaller negative value.

Here is an example of the loess fit above. enter image description here

Not sure if this will be done in all cases, but it seems to be better than spline.

0
source

To do this, you can use splines with a shape constraint, for example. using the scam package:

 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") 

enter image description here

Or, if you want to use L1 loss as opposed to L2 loss, which is less sensitive to emissions, you can also use the cobs package to do this ...

The advantage of this method compared to the above solution is that it also works if the source data may not be 100% monotonous due to noise ...

0
source

Source: https://habr.com/ru/post/1200926/


All Articles