A Short Introduction to splines2

Wenjie Wang

2025-02-27


1 Introduction

The R package splines2 is intended to be a user-friendly supplementary package to the base package splines. It provides functions to construct 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(). More specifically, splines2 allows users to construct the basis functions of

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

Compared to splines, the package splines2 provides convenient interfaces for spline derivatives with consistent handling on NA’s. Most of the implementations are in C++ with the help of Rcpp and RcppArmadillo since v0.3.0, which boosted the computational performance.

In the remainder of this vignette, we illustrate the basic usage of most functions in the package through examples. We refer readers to Wang and Yan (2021) for a more formal introduction to the package with applications to shape-restricted regression. See the package manual for more details about function usage.

library(splines2)
packageVersion("splines2")
## [1] '0.5.4'


2 B-splines

2.1 B-spline Basis Functions

The bSpline() function generates the basis matrix for B-splines and extends the function bs() of the package splines by providing 1) the piece-wise constant basis functions when degree = 0, 2) the derivatives of basis functions for a positive derivs, 3) the integrals of basis functions if integral = TRUE, 4) periodic basis functions based on B-splines if periodic = TRUE.

One example of linear B-splines with three internal knots is as follows:

knots <- c(0.3, 0.5, 0.6)
x <- seq(0, 1, 0.01)
bsMat <- bSpline(x, knots = knots, degree = 1, intercept = TRUE)
plot(bsMat, mark_knots = "all")
B-splines of degree one with three internal knots placed at 0.3, 0.5, and 0.6.
B-splines of degree one with three internal knots placed at 0.3, 0.5, and 0.6.

2.2 Integrals and Derivatives of B-splines

For convenience, the package also provides functions ibs() and dbs() for constructing the B-spline integrals and derivatives, respectively. Two toy examples are as follows:

ibsMat <- ibs(x, knots = knots, degree = 1, intercept = TRUE)
op <- par(mfrow = c(1, 2))
plot(bsMat, mark_knots = "internal")
plot(ibsMat, mark_knots = "internal")
abline(h = c(0.15, 0.2, 0.25), lty = 2, col = "gray")
Piecewise linear B-splines (left) and their integrals (right).
Piecewise linear B-splines (left) and their integrals (right).
bsMat <- bSpline(x, knots = knots, intercept = TRUE)
dbsMat <- dbs(x, knots = knots, intercept = TRUE)
plot(bsMat, mark_knots = "internal")
plot(dbsMat, mark_knots = "internal")
Cubic B-spline (left) and their first derivative (right).
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)))

2.3 Periodic B-splines

The function bSpline() produces periodic spline basis functions following Piegl and Tiller (1997, chap. 12) when periodic = TRUE is specified. Different from the regular basis functions, the x is allowed to be placed outside the boundary and the Boundary.knots defines the cyclic interval. For instance, one may obtain the periodic cubic B-spline basis functions with cyclic interval (0, 1) as follows:

px <- seq(0, 3, 0.01)
pbsMat <- bSpline(px, knots = knots, Boundary.knots = c(0, 1),
                  intercept = TRUE, periodic = TRUE)
ipMat <- ibs(px, knots = knots, Boundary.knots = c(0, 1),
             intercept = TRUE, periodic = TRUE)
dp1Mat <- deriv(pbsMat)
dp2Mat <- deriv(pbsMat, derivs = 2)
par(mfrow = c(1, 2))
plot(pbsMat, ylab = "Periodic B-splines", mark_knots = "boundary")
plot(ipMat, ylab = "The integrals", mark_knots = "boundary")

plot(dp1Mat, ylab = "The 1st derivatives", mark_knots = "boundary")
plot(dp2Mat, ylab = "The 2nd derivatives", mark_knots = "boundary")

0Y03bWTmf0Mdrr+55y8KLfjWXtl/Kxm+qAyCI `JWIM}9sLE+YTm99r/f1l+MUmgRRSl+Va4KstQQOi309crhh0CRePPZvb9t3eoP2wrR8w+EnilUJQ䒶܁opVXf8Ul/e74Rά11CiKYevk2gYiQ8Sj3s+L3WA0+s5ksE0a900KUz/0O+QhI5jyYSTy62LOYIOnzNnDpSwk+1sthuml2RYx5LQ0nKD4b5sX37/9ta1tSSYSkWMrs`/p2HYZRgj2W7aair5Pb5ECQYpHJjhlnr+f9sp6NB756s7/r6lPdhqHGJKanKvGYT1pko5QAQDqHHjGKzHLBIgV1s7e73XWMdFS0sn/7kkkVlRUOlvjktGle4dInz0GHPTw4h9f6PTAcd2QgFxe/Pmc+PcgACEweK+PJmAiD綀 `6f5VdV1u4g(jp88bVظrA7/r6KLktj6fp5flm7gk/6fuWQDql2K+KzBAtIdXdo0n41zhv50d/C+eN7/7kkkVqkmOlFZYZ/7kkZVqkLOlFZYZypQpDzj(LGTouqk72lsnnQXoiFNo5ICh8+DXjlc2lwZwwJjcdA5MR5/d54JNaYmARjQFSYQbV#AhܔBQXDyIGNMY1Q2GLCIR9M73YOZh(bq/gG6yq tVm5suhՒJJuU0MIiu6eGgG6y5s9dYMnAVNIccGxOY8vfCQtl՟x7O9OVTBő'dfCQVt+4dp70dFNo+ TYNHTcepuvm(dRTXZ21y4XAMzbj6TJPIAPVSKUpdz8jMzPQjjz8OHz5sb2/v7e3t7u5Op9MpFIpAICgqKsrLy7O1tV26Ux8FHn6bVEa521yl7/Rh1d7LAVORA>3sBDI8w |5cl5d/RtP7f6r+mtze70dAHLtS5jcMXR]cc8t+62UWRCg5RA7e39f5QTKvGYSRHAC7NZMMBSRL^MdZTMLMg9MORtCsQLMg9f%gм(3XYALT559BBVj5ZLa9q6BBVj5ZLa8q6e/Z5m7TTCS0s44v2uNc OPQwll+1fl+1f 1d7Pw+tNC0QM4O\ETRG1d 3H/W8Lnэ΃BMORw=g4PYChtikIMG4jl"cJp02r6CDs5t+0p2n+f/+s+i~6g5fq6L1RU5UL02r13c6d#xslVUJCMNY+Pvi6r~v AUL0sFEng 6br00fq7 RRETRGZ9dBSXtgpAt+0q鄄p5Z34WT5ep/HGOQOORZBYXSRUYOYO9RU5BZRhP70eq7fj7q5gA3d9gWLLRV5aE4EISTjs3d5gi6TTOOIZ34f/d2fJ0eYF0dh7 DR2IN9efefnnVx9s/e+6TTOIYRQSFNSO6f5 LYDclk}8bJZ