Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constrained Spline Fit using Scipy in Python

I was wondering if UnivariateSpline lets you do constrain spline fitting? For example, consider the following data:

 x         y
13    2.404070
12    1.588134
11    1.760112
10    1.771360
09    1.860087
08    1.955789
07    1.910408
06    1.655911
05    1.778952
04    2.624719
03    1.698099
02    3.022607
01    3.303135    

The discussion on the choice and role of smoothing function can be found in an earlier post here. However, if we impose a constrain that spline needs to be monotonically decreasing, any ideas on how should we go about fitting the spline?

Thanks for your help!.

EDIT: The spline need not exactly fit all the points. It should however satisfy the constrain (monotonically decreasing).

like image 745
Prakhar Mehrotra Avatar asked Oct 21 '22 04:10

Prakhar Mehrotra


2 Answers

A monotonicity constraint can be imposed by using integrated splines as basis functions and constraining the OLS coefficients to be non-negative. The non-negativity constraint makes computing a solution more difficult than fitting an ordinary smoothing spline. It is likely your scipy package does not have the necessary functionality.

Mary Meyer suggests using some interesting properties of the parameter space in this problem to facilitate computation. She provides R code in her paper. See Meyer (2008, AoAS), Inference using shape-restricted regression splines, at 1031.

like image 130
kalu Avatar answered Oct 24 '22 12:10

kalu


  • Reading the question you linked, I think you only need x to be monotonic. If your data is a Series with x as the index, then just do UnivariateSpline(s.sort()). If your data is a DataFrame, do UnivariateSpline(df.set_index('x')['y'].sort()).

  • Perhaps you actually want a monotonic spline, in spite of the fact that y(x) does not seem to be monotonic. I know of no way to introduce constraints to UnivariateSpline directly, but we can constrain the data before we fit the spline. Generate a "forced monotonically decreasing" variant of your data like this:

    pd.expanding_min(s.sort())
    

    Each element will be replaced with the smallest element seen so far, suppressing any increases. Any spline from such data should also be monotonic.

  • Finally, in general, for curve fitting with constraints, checkout lmfit. It adds some features onto the nonlinear least-squared curve fitter scipy.optimize, and it's saved me a lot of hassle.

like image 41
Dan Allan Avatar answered Oct 24 '22 12:10

Dan Allan