I’m exploring the idea of adding a function or set of functions to the simstudy package that would make it possible to easily generate non-linear data. One way to do this would be using B-splines. Typically, one uses splines to fit a curve to data, but I thought it might be useful to switch things around a bit to use the underlying splines to generate data. This would facilitate exploring models where we know the assumption of linearity is violated. It would also make it easy to explore spline methods, because as with any other simulated data set, we would know the underlying data generating process.
B-splines
A B-spline is a linear combination of a set of basis functions that are determined by the number and location of specified knots or cut-points, as well as the (polynomial) degree of curvature. A degree of one implies a set of straight lines, degree of two implies a quadratic curve, three a cubic curve, etc. This nice quick intro provides much more insight into issues B-splines than I can provide here. Or if you want even more detail, check out this book. It is a very rich topic.
Within a cut-point region, the sum of the basis functions always equals 1. This is easy to see by looking at a plot of basis functions, several of which are provided below. The definition and shape of the basis functions do not in any way depend on the data, only on the degree and cut-points. Of course, these functions can be added together in infinitely different ways using weights. If one is trying to fit a B-spline line to data, those weights can be estimated using regression models.
Splines in R
The bs function in the splines package, returns values from these basis functions based on the specification of knots and degree of curvature. I wrote a wrapper function that uses the bs function to generate the basis function, and then I do a linear transformation of these functions by multiplying the vector parameter theta, which is just a vector of coefficients. The linear combination at each value of \(x\) (the support of the basis functions) generates a value (which I call \(y.spline\)) on the desired curve. The wrapper returns a list of objects, including a data.table that includes \(x\) and \(y.spline\), as well as the basis functions, and knots.
library(splines)
library(data.table)
library(ggplot2)
library(broom)
genSpline