Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make monotonic (increasing) smooth spline with smooth.spline() function?

Tags:

r

spline

I have data that are strictly increasing and would like to fit a smoothing spline that is monotonically increasing as well with the smooth.spline() function if possible, due to the ease of use of this function.

For example, my data can be effectively reproduced with the 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 is not necessarily increasing everywhere. Any suggestions?

like image 919
Michael Clinton Avatar asked Aug 22 '14 13:08

Michael Clinton


People also ask

How do you show that a function is monotonic increasing?

To tell if a function is monotonically increasing, simply find its derivative and see if it is always positive on its domain. If the derivative of a function is always positive (or greater than or equal to zero), then the function is monotonically increasing.

What does smooth spline do in R?

Smoothing splines are a powerful approach for estimating functional relationships between a predictor X and a response Y. Smoothing splines can be fit using either the smooth. spline function (in the stats package) or the ss function (in the npreg package).

What is cubic spline smoothing?

Cubic smoothing splines embody a curve fitting technique which blends the ideas of cubic splines and curvature minimization to create an effective data modeling tool for noisy data.

What is lambda in spline?

Here, \lambda is the smoothing parameter guiding the trade-off fitting the data and roughness of function. To estimate the. we perform the generalized cross-validation or restricted marginal likelihood. No smoothing, the spline converges to interpolating spline.


2 Answers

You could use shape-constrained splines for this, e.g. 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 would like to use L1 loss as opposed to L2 loss, which is less sensitive to outliers, you could also use the cobs package for this...

Advantage of this method compared to the solution above is that it also works if the original data perhaps are not 100% monotone due to the presence of noise...

like image 74
Tom Wenseleers Avatar answered Sep 22 '22 06:09

Tom Wenseleers


This doesn't use smooth.spline() but the splinefun(..., method="hyman") will fit a monotonically increasing spline and is also easy to use. So 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")

Yields the following figure (red are the values from the monotonically increasing spline) enter image description here

From the help file of splinefun: "Method "hyman" computes a monotone cubic spline using Hyman filtering of an method = "fmm" fit for strictly monotonic inputs. (Added in R 2.15.2.)"

like image 40
Nicholas G Reich Avatar answered Sep 20 '22 06:09

Nicholas G Reich