It looks like you came from one of my previous answer in 2016: mgcv: How to set number and / or locations of knots for splines, borrowing my code snippet:
my_knots <- myfit$smooth[[1]]$xp
plot(x, y, col= "grey", main = "my knots");
lines(x, myfit$linear.predictors, col = 2, lwd = 2)
abline(v = my_knots, lty = 2)
In that answer, my demonstration was made with cubic regression spline (bs = 'cr'
), where knot placement is simple to do. But for B-splines, things are more complicated. So take this answer as a complement to that answer.
For B-spline classes in mgcv, i.e., 'bs'
being "bs" (?b.spline
), "ps" (?p.spline
) or "ad" (?adaptive.smooth
), the argument k
is the number of B-splines, not the number of knots. And the first take-home message is: the number of B-splines is NOT equal to the number of knots.
Knot placement for B-splines is a dirty work. Usually you only specify k
and mgcv will place knots automatically for you (see for example, Extract knots, basis, coefficients and predictions for P-splines in adaptive smooth). If you want to control knot placement yourself, the number of knots you provide must be compatible with k
. This can cause great confusion if you don't well understand B-splines.
I highly recommend your reading the Appendix (page 33-34) of one of my work: General P-splines for Non-uniform B-splines, to know some fundamental stuff of B-splines. Make sure you understand what are the domain, interior knots and auxiliary boundary knots. In the following, I will just show you how to use these knowledge to write the correct code.
Here is how to place knots for your example.
## degree of spline
deg <- 3
## domain
a <- min(x)
#[1] 5.86
b <- max(x)
#[1] 24.16
## interior knots (must be between a and b)
xs <- c(6, 20)
#[1] 6 20
## domain knots
xd <- c(a, xs, b)
#[1] 5.86 6.00 20.00 24.16
## clamped auxiliary boundary knots
left.aux <- rep(a, deg)
#[1] 5.86 5.86 5.86
right.aux <- rep(b, deg)
#[1] 24.16 24.16 24.16
## complete B-spline knots
my.knots <- c(left.aux, xd, right.aux)
#[1] 5.86 5.86 5.86 5.86 6.00 20.00 24.16 24.16 24.16 24.16
Here is how to specify k
for your example.
my.k <- length(xs) + deg + 1
#[1] 6
Now we can work with mgcv.
myfit <- gam(y ~ s(x, bs = 'bs', k = my.k),
knots = list(x = my.knots))
#Family: gaussian
#Link function: identity
#
#Formula:
#y ~ s(x, bs = "bs", k = my.k, m = deg)
#
#Estimated degrees of freedom:
#3.81 total = 4.81
The knots you passed in are stored here (which agree with my.knots
):
## For B-spline classes, knots are stored in $knots instead of $xp
myfit$smooth[[1]]$knots
#[1] 5.86 5.86 5.86 5.86 6.00 20.00 24.16 24.16 24.16 24.16
Accompanying General P-splines for Non-uniform B-splines are R packages gps and gps.mgcv. The latter package introduces a new "gps" class to mgcv, where bs = 'ps'
and bs = 'bs'
are special cases of bs = 'gps'
. The new "gps" class makes knot placement easier, because it automatically places auxiliary boundary knots for you and you only need to provide interior knots.
## The package stays on GitHub for the moment
## but will be on CRAN in the future.
## You may need to first install package 'devtools' from CRAN.
devtools::install_github("ZheyuanLi/gps")
devtools::install_github("ZheyuanLi/gps.mgcv")
library(gps.mgcv)
## as same as using 'bs = 'bs''
myfit <- gam(y ~ s(x, bs = 'gps', k = my.k, xt = list(derivative = TRUE)),
knots = list(x = xs)) ## provide interior knots
## the novel general P-spline
gpsfit <- gam(y ~ s(x, bs = 'gps', k = my.k),
knots = list(x = xs)) ## provide interior knots
Construction information (domain, interior knots, etc) are stored in myfit$smooth[[1]]$xt
and gpsfit$smooth[[1]]$xt
.
ld: warning: directory not found for option '-L/usr/local/gfortran/lib/gcc/x86_64-apple-darwin18/8.2.0' ld: warning: directory not found for option '-L/usr/local/gfortran/lib' ld: library not found for -lgfortran clang: error: linker command failed with exit code 1 (use -v to see invocation)
Any ideas on how can I resolve it? – Explication