Introduction to splines2

Wenjie Wang

2023-01-13

The R package splines2 is intended to be a comprehensive, efficient supplement to the base package splines. It provides functions constructing a variety of regression spline basis functions that are not available from splines. Most functions have a very similar user interface with the function splines::bs(). To be more specific, it provides functions to construct basis matrices of

along with their integrals (except C-splines) and derivatives of given order by closed-form recursive formulas.

Compared to the package splines, the package splines2 allows piecewise constant basis functions for B-splines and provides a more user-friendly interface for their derivatives with consistent handling on NA’s. Most of the implementations had been (re)written in C++ with the help of Rcpp and RcppArmadillo since v0.3.0, which boosted the computational performance.

In the remaining of this vignette, we illustrated the basic usage of most functions in the package through examples. See the package manual for the details of function usage.

B-splines with their integrals and derivatives

Function bSpline() provides B-spline basis matrix and allows degree = 0 for piece-wise constant basis function, which extends the bs() function in package splines with a better computational performance. One example of linear B-splines with three internal knots is given as follows:

library(splines2)
knots <- c(0.3, 0.5, 0.6)
x <- seq(0, 1, 0.01)
bsMat <- bSpline(x, knots = knots, degree = 1, intercept = TRUE)
matplot(x, bsMat, type = "l", ylab = "y")
abline(v = knots, lty = 2, col = "gray")

B-splines of degree one with three internal knots placed at 0.3, 0.5, and 0.6.

The closed-form recursive formula of B-spline integrals and derivatives given by De Boor (1978) is implemented in function ibs() and dbs(), respectively. Two toy examples are given as follows:

ibsMat <- ibs(x, knots = knots, degree = 1, intercept = TRUE)
par(mfrow = c(1, 2))
matplot(x, bsMat, type = "l", ylab = "y")
abline(v = knots, h = 1, lty = 2, col = "gray")
matplot(x, ibsMat, type = "l", ylab = "y")
abline(v = knots, h = c(0.15, 0.2, 0.25), lty = 2, col = "gray")

Piecewise linear B-splines (left) and their integrals (right).

bsMat <- bSpline(x, knots = knots, intercept = TRUE)
dbsMat <- dbs(x, knots = knots, intercept = TRUE)
par(mfrow = c(1, 2))
matplot(x, bsMat, type = "l", ylab = "y")
abline(v = knots, lty = 2, col = "gray")
matplot(x, dbsMat, type = "l", ylab = "y")
abline(v = knots, lty = 2, col = "gray")

Cubic B-spline (left) and their first derivative (right).

We may also obtain the derivatives easily by the deriv() method as follows:

is_equivalent <- function(a, b) {
    all.equal(a, b, check.attributes = FALSE)
}
stopifnot(is_equivalent(dbsMat, deriv(bsMat)))

M-splines using mSpline()

M-splines (Ramsay 1988) are considered the normalized version of B-splines with unit integral within boundary knots. An example given by Ramsay (1988) was a quadratic M-splines with three internal knots placed at 0.3, 0.5, and 0.6. The default boundary knots are the range of x, and thus 0 and 1 in this example.

msMat <- mSpline(x, knots = knots, degree = 2, intercept = TRUE)
matplot(x, msMat, type = "l", ylab = "y")
abline(v = knots, lty = 2, col = "gray")

Quadratic M-spline with three internal knots placed at 0.3, 0.5, and 0.6.

The derivative of the given order of M-splines can be obtained by specifying a positive integer to argument dervis of mSpline(). Also, for an existing mSpline object generated by mSpline(), the deriv() method can be used conveniently. For example, the first derivative of the M-splines given in the previous example can be obtained equivalently as follows:

dmsMat1 <- mSpline(x, knots = knots, degree = 2, intercept = TRUE, derivs = 1)
dmsMat2 <- deriv(msMat)
stopifnot(is_equivalent(dmsMat1, dmsMat2))

Periodic M-Splines

The function mSpline() produces periodic splines based on M-spline basis functions when periodic = TRUE is specified. The Boundary.knots defines the cyclic interval. The construction follows periodic B-splines discussed in Piegl and Tiller (1997, chap. 12).

x1 <- seq.int(0, 3, 0.01)
pmsMat <- mSpline(x1, knots = knots, degree = 3, intercept = TRUE,
                  periodic = TRUE, Boundary.knots = c(0, 1))
matplot(x1, pmsMat, type = "l", xlab = "x", ylab = "Periodic Basis")
abline(v = seq.int(0, 3), lty = 2, col = "gray")

Cubic periodic M-splines.

We may still specify the argument derivs in mSpline() or use the corresponding deriv() method to obtain the derivatives when periodic = TRUE.

dpmsMat <- deriv(pmsMat)
matplot(x1, dpmsMat, type = "l", xlab = "x", ylab = "The 1st derivatives")
abline(v = seq.int(0, 3), lty = 2, col = "gray")