rsplinecubic-spline

Is there a function for not-a-knot cubic splines?


I need to use the "not-a-knot" cubic spline for interpolation in my R scripts.

Although there are some R packages for splines, none of them seem to consider the "not-a-knot" type, even if it is said to be a rather "popular" type of cubic spline, and it is available in Matlab.

I fear that there is another name for "not-a-knot" cubic splines. It is a cubic spline where the two extra conditions are about the third derivative continuity in the second and before-last knots (instead of fixing the first derivatives at the endpoint knots, as natural cubic splines do, or other choices).


Solution

  • By digging a little bit, it seems that this is implemented in pracma::interp1

    From ?pracma::interp1

    Interpolation to find ‘yi’, the values of the underlying function at the points in the vector ‘xi’. ... Method `spline' uses the spline approach by Moler et al., and is identical with the Matlab option of the same name, but slightly different from R's spline function.

    This doesn't mention "not-a-knot", but I got there by using sos::findFn("not-a-knot"), which brought me to gsignal::pulstran(). That function's "spline" method is described as "Spline interpolation using not-a-knot end conditions"; the method= argument is passed directly to pracma::interp1.

    Here is an example comparing:

    library(splines)
    library(pracma)
    x <- 1:6
    y <- c(16, 18, 21, 17, 15, 12)
    xi0 <- seq(1, 6, by = 0.1)
    xi1 <- seq(1, 7, by = 0.1)
    ys1 <- interp1(x, y, xi0, method = "spline")
    ys2 <- predict(interpSpline(x, y), xi1)$y
    ys3 <- spline(x, y, xout  = xi1)$y
    ys4 <- pracma:::.ml.spline(x, y, xi1)
    ys5 <- scan("octave_out.mat", comment = "#") ## see below
    
    png("spline2.png")
    par(las=1, bty = "l", cex = 1.5, lwd = 2)
    plot(x,y, xlim = range(xi1), ylim = range(ys4),
         pch = 16, col = "gray")
    cvec <- c(palette()[c(1,2,4,6)],
      ## make last color semi-transparent so we can see the overlay
              adjustcolor(palette()[5], alpha.f = 0.4))
    matlines(xi1, cbind(ys2,ys3,ys4, ys5) , col = cvec[1:4], lwd = 2)
    lines(xi0, ys1, lwd = 3, col = cvec[5])
    legend("bottomleft",
           lty = c(1:4, 1),
           col = cvec,
           legend = c("interpSpline", "spline", ".ml.spine", "octave", "interp1"))
    dev.off()
    

    enter image description here


    Octave code (run in a separate shell)

    x = 1:6;
    y = [16, 18, 21, 17, 15, 12];
    xi1 = linspace(1, 7, 61);
    pp = interp1(x, y, 'spline', 'pp');
    yy = ppval(pp, xi1);
    save octave_out.mat yy