Hello,

I am trying to generate the design matrix associated with the tprs smooth in
R mgcv from scratch. I want to construct the matrix X = [UkDkZk | T] which
is produced from the function smoothCon following the steps provided in
Simon Wood's 2003 Thin Plate Regression Splines paper (Appendix A). I have
had a crack at it but so far I am unable to replicate the design matrix
exactly. See below for an example.

My questions are twofold. 1) What transformations are being applied to the
matrix T (with absorb.cons=FALSE) behind the scenes in smoothCon? And 2)
what transformations are being applied to UkDkZk in smoothCon (if any)?

Thanks!
Casey

######################### Libraries
library(mgcv)
library(SpatioTemporal) # uses the crossDist() function to calculate
distances (ie. r in eta_{md}(r))

######################### Generate Data
x1 <- sin(rnorm(100))
x2 <- rnorm(100)*x1
x2 <- x2[order(x1)]
x1 <- sort(x1)

######################## Use mgcv functions to get the design matrix [UkDkZk
| T]
um <- smoothCon(s(x1, x2, fx=TRUE, m=2, k=20), data=data.frame(x1=x1,
x2=x2), knots=NULL, absorb.cons=FALSE)
X1 <- um[[1]]$X

######################### Use the steps in Appendix 1 of Wood (2003) to
construct the same matrix
n <- length(x1); m=2; d=2; M <- choose(m+d-1, d); k <- 20

eta.func <- function(m, d, r){
if(d%%2 == 0){
(-1)^(m+1+d/2)/(2^(2*m-1)*pi^(d/2)*factorial(m-1)*factorial(m-d/2))*r^(2*m-d
)*log(r)
} else {
gamma(d/2-m)/(2^(2*m)*pi^(d/2)*factorial(m-1))*r^(2*m-d)
}
}

T <- cbind(rep(1, length(x1)), x1, x2)
E <- eta.func(m=m, d=d, r=crossDist(cbind(x1, x2)))
diag(E) <- 0
Ek <- eigen(E, symmetric=TRUE)
Uk <- Ek$vectors[, 1:k]
Dk <- diag(Ek$values[1:k])
Ek <- Uk%*%Dk%*%t(Uk)
tUkT <- t(Uk)%*%T
QR <- qr(tUkT)
Q <- qr.Q(QR, complete=TRUE)
Zk <- Q[, (M+1):k]
X2 <- cbind(Uk%*%Dk%*%Zk, T)

####################### Compare Basis Functions
par(mfrow=c(1,2))
plot(X1[, 1] ~ x1, type="l", ylim=range(X1))
for(i in 2:ncol(X1)){ lines(X1[, i] ~ x1, col=i) }

plot(X2[, 1] ~ x1, type="l", ylim=range(X1))
for(i in 2:ncol(X2)){ lines(X2[, i] ~ x1, col=i) }

####################### Compare Predictions (unpenalized)
y <- x1+2*x2 + rnorm(100)

mod1 <- lm(y ~ -1 + X1)
pred1 <- X1%*%coef(mod1)

mod2 <- lm(y ~ -1 + X2)
pred2 <- X2%*%coef(mod2)

mod.gam <- gam(y ~ s(x1, x2, fx=TRUE, m=2, k=20))
pred.gam <- predict(mod.gam, data.frame(x1, x2))

par(mfrow=c(1,3))
plot(pred1 ~ y, ylim=c(-3, 3))
abline(0,1)
plot(pred2 ~ y, ylim=c(-3, 3))
abline(0,1)
plot(pred.gam ~ y, ylim=c(-3, 3)) # pred.gam and pred1 are the same
abline(0,1)




	[[alternative HTML version deleted]]

