We start with a sequence of knots to divide the real line into intervals. A spline of order k is a polynomial of degree k in each interval, but with the property that at the knots the spline has continuous derivatives of degree k-1. A B-spline of order k has the additional property that it is non-zero in only k+1 consecutive intervals. B-splines take values between zero and one, and their integral over the real line is one.
B-splines of arbitrary degree are normally computed using convenient and stable recursion formulas, but we give code for some explicit computation of low-order B-splines below. First we define some constants.
set.seed(12345)
knots <- sort(rnorm(20))
knots
## [1] -1.8180 -0.9193 -0.8864 -0.7505 -0.4535 -0.3316 -0.2842 -0.2762
## [9] -0.1162 -0.1093 0.2987 0.3706 0.5202 0.5855 0.6059 0.6301
## [17] 0.7095 0.8169 1.1207 1.8173
grid <- seq(-1.5, 1.5, length = 1001)
## Loading required package: downloader
## Loading fonts...
## Loading fonts finished
A B-spline of degree zero is a step function which is zero everywhere, except on one of the intervals, where it is one.
ZbSpline <- function(x, knots, k = 1) {
ZbSplineSingle <- function(x, knots, k = 1) {
k0 <- knots[k]
k1 <- knots[k + 1]
if ((x >= k0) && (x < k1)) {
return(1)
}
return(0)
}
return(sapply(x, function(z) ZbSplineSingle(z, knots, k)))
}
par(mar = rep(3, 4), bg = "white")
for (k in 1:20) {
plot(grid, ZbSpline(grid, knots, k = k), type = "l", cex = 2, col = "RED",
ylab = "spline", lwd = 3)
}
A B-spline of degree one is a continuous piecewise linear function which is non-zero on two intervals. In the first interval it increases from zero to its maximum, in the second interval it decreases from the its maximum to zero.
LbSpline <- function(x, knots, k = 1) {
LbSplineSingle <- function(x, knots, k = 1) {
k0 <- knots[k]
k1 <- knots[k + 1]
k2 <- knots[k + 2]
f1 <- function(x) (x - k0)/(k1 - k0)
f2 <- function(x) (k2 - x)/(k2 - k1)
if ((x >= k0) && (x < k1)) {
return(f1(x))
}
if ((x >= k1) && (x < k2)) {
return(f2(x))
}
return(0)
}
return(sapply(x, function(z) LbSplineSingle(z, knots, k)))
}
par(mar = rep(3, 4), bg = "white")
for (k in 1:19) {
plot(grid, LbSpline(grid, knots, k = k), type = "l", cex = 2, col = "RED",
ylab = "spline", lwd = 3)
}
A B-spline of degree two is piecewise quadratic. It is non-zero on three intervals and it is continuously differentiable at the corresponding four knots. It increases from knot one to knot two, starting at zero. Then it attains its maximum between knots two and three, and it decreases to zero from knot three to knot four.
QbSpline <- function(x, knots, k = 1) {
QbSplineSingle <- function(x, knots, k = 1) {
k0 <- knots[k]
k1 <- knots[k + 1]
k2 <- knots[k + 2]
k3 <- knots[k + 3]
f1 <- function(x) ((x - k0)^2)/((k2 - k0) * (k1 - k0))
f2 <- function(x) {
term1 <- ((x - k0) * (k2 - x))/((k2 - k0) * (k2 - k1))
term2 <- ((x - k1) * (k3 - x))/((k3 - k1) * (k2 - k1))
return(term1 + term2)
}
f3 <- function(x) ((k3 - x)^2)/((k3 - k1) * (k3 - k2))
if ((x >= k0) && (x < k1)) {
return(f1(x))
}
if ((x >= k1) && (x < k2)) {
return(f2(x))
}
if ((x >= k2) && (x < k3)) {
return(f3(x))
}
return(0)
}
return(sapply(x, function(z) QbSplineSingle(z, knots, k)))
}
par(mar = rep(3, 4), bg = "white")
for (k in 1:18) {
plot(grid, QbSpline(grid, knots, k = k), type = "l", cex = 2, col = "RED",
ylab = "spline", lwd = 3)
}