R/gamBiCopFit.R
gamBiCopFit.RdThis function estimates the parameter(s) of a Generalized Additive model
(gam) for the copula parameter or Kendall's tau.
It solves the maximum penalized likelihood estimation for the copula families
supported in this package by reformulating each Newton-Raphson iteration as
a generalized ridge regression, which is solved using
the mgcv package.
gamBiCopFit(
data,
formula = ~1,
family = 1,
tau = TRUE,
method = "FS",
tol.rel = 0.001,
n.iters = 10,
verbose = FALSE,
...
)A list, data frame or matrix containing the model responses, (u1,u2) in [0,1]x[0,1], and covariates required by the formula.
A gam formula (see gam,
formula.gam and gam.models
from mgcv).
A copula family: 1 Gaussian,
2 Student t,
5 Frank,
301 Double Clayton type I (standard and rotated 90 degrees),
302 Double Clayton type II (standard and rotated 270 degrees),
303 Double Clayton type III (survival and rotated 90 degrees),
304 Double Clayton type IV (survival and rotated 270 degrees),
401 Double Gumbel type I (standard and rotated 90 degrees),
402 Double Gumbel type II (standard and rotated 270 degrees),
403 Double Gumbel type III (survival and rotated 90 degrees),
404 Double Gumbel type IV (survival and rotated 270 degrees).
FALSE (default) for a calibration function specified for
the Copula parameter or TRUE for a calibration function specified
for Kendall's tau.
'NR' for Newton-Raphson
and 'FS' for Fisher-scoring (default).
Relative tolerance for 'FS'/'NR' algorithm.
Maximal number of iterations for
'FS'/'NR' algorithm.
TRUE if informations should be printed during the
estimation and FALSE (default) for a silent version.
gamBiCopFit returns a list consisting of
S4 gamBiCop-class object.
'FS' for Fisher-scoring (default) and
'NR' for Newton-Raphson.
relative tolerance for 'FS'/'NR' algorithm.
maximal number of iterations for
'FS'/'NR' algorithm.
the estimation procedure's trace.
0 if the algorithm converged and 1 otherwise.
gamBiCop and gamBiCopSimulate.
require(copula)
require(mgcv)
#> Loading required package: mgcv
#> Loading required package: nlme
#> This is mgcv 1.9-1. For overview type 'help("mgcv-package")'.
set.seed(0)
## Simulation parameters (sample size, correlation between covariates,
## Gaussian copula family)
n <- 5e2
rho <- 0.5
fam <- 1
## A calibration surface depending on three variables
eta0 <- 1
calib.surf <- list(
calib.quad <- function(t, Ti = 0, Tf = 1, b = 8) {
Tm <- (Tf - Ti) / 2
a <- -(b / 3) * (Tf^2 - 3 * Tf * Tm + 3 * Tm^2)
return(a + b * (t - Tm)^2)
},
calib.sin <- function(t, Ti = 0, Tf = 1, b = 1, f = 1) {
a <- b * (1 - 2 * Tf * pi / (f * Tf * pi +
cos(2 * f * pi * (Tf - Ti))
- cos(2 * f * pi * Ti)))
return((a + b) / 2 + (b - a) * sin(2 * f * pi * (t - Ti)) / 2)
},
calib.exp <- function(t, Ti = 0, Tf = 1, b = 2, s = Tf / 8) {
Tm <- (Tf - Ti) / 2
a <- (b * s * sqrt(2 * pi) / Tf) * (pnorm(0, Tm, s) - pnorm(Tf, Tm, s))
return(a + b * exp(-(t - Tm)^2 / (2 * s^2)))
}
)
## Display the calibration surface
par(mfrow = c(1, 3), pty = "s", mar = c(1, 1, 4, 1))
u <- seq(0, 1, length.out = 100)
sel <- matrix(c(1, 1, 2, 2, 3, 3), ncol = 2)
jet.colors <- colorRamp(c(
"#00007F", "blue", "#007FFF", "cyan", "#7FFF7F",
"yellow", "#FF7F00", "red", "#7F0000"
))
jet <- function(x) rgb(jet.colors(exp(x / 3) / (1 + exp(x / 3))),
maxColorValue = 255
)
for (k in 1:3) {
tmp <- outer(u, u, function(x, y)
eta0 + calib.surf[[sel[k, 1]]](x) + calib.surf[[sel[k, 2]]](y))
persp(u, u, tmp,
border = NA, theta = 60, phi = 30, zlab = "",
col = matrix(jet(tmp), nrow = 100),
xlab = paste("X", sel[k, 1], sep = ""),
ylab = paste("X", sel[k, 2], sep = ""),
main = paste("eta0+f", sel[k, 1],
"(X", sel[k, 1], ") +f", sel[k, 2],
"(X", sel[k, 2], ")",
sep = ""
)
)
}
## 3-dimensional matrix X of covariates
covariates.distr <- mvdc(normalCopula(rho, dim = 3),
c("unif"), list(list(min = 0, max = 1)),
marginsIdentical = TRUE
)
X <- rMvdc(n, covariates.distr)
## U in [0,1]x[0,1] with copula parameter depending on X
U <- condBiCopSim(fam, function(x1, x2, x3) {
eta0 + sum(mapply(function(f, x)
f(x), calib.surf, c(x1, x2, x3)))
}, X[, 1:3], par2 = 6, return.par = TRUE)
## Merge U and X
data <- data.frame(U$data, X)
names(data) <- c(paste("u", 1:2, sep = ""), paste("x", 1:3, sep = ""))
## Display the data
dev.off()
#> null device
#> 1
plot(data[, "u1"], data[, "u2"], xlab = "U1", ylab = "U2")
## Model fit with a basis size (arguably) too small
## and unpenalized cubic spines
pen <- FALSE
basis0 <- c(3, 4, 4)
formula <- ~ s(x1, k = basis0[1], bs = "cr", fx = !pen) +
s(x2, k = basis0[2], bs = "cr", fx = !pen) +
s(x3, k = basis0[3], bs = "cr", fx = !pen)
system.time(fit0 <- gamBiCopFit(data, formula, fam))
#> user system elapsed
#> 0.097 0.001 0.098
## Model fit with a better basis size and penalized cubic splines (via min GCV)
pen <- TRUE
basis1 <- c(3, 10, 10)
formula <- ~ s(x1, k = basis1[1], bs = "cr", fx = !pen) +
s(x2, k = basis1[2], bs = "cr", fx = !pen) +
s(x3, k = basis1[3], bs = "cr", fx = !pen)
system.time(fit1 <- gamBiCopFit(data, formula, fam))
#> user system elapsed
#> 0.479 1.568 0.338
## Extract the gamBiCop objects and show various methods
(res <- sapply(list(fit0, fit1), function(fit) {
fit$res
}))
#> [[1]]
#> Gaussian copula with tau(z) = (exp(z)-1)/(exp(z)+1) where
#> z ~ s(x1, k = basis0[1], bs = "cr", fx = !pen) + s(x2, k = basis0[2],
#> bs = "cr", fx = !pen) + s(x3, k = basis0[3], bs = "cr", fx = !pen)
#>
#> [[2]]
#> Gaussian copula with tau(z) = (exp(z)-1)/(exp(z)+1) where
#> z ~ s(x1, k = basis1[1], bs = "cr", fx = !pen) + s(x2, k = basis1[2],
#> bs = "cr", fx = !pen) + s(x3, k = basis1[3], bs = "cr", fx = !pen)
#>
metds <- list("logLik" = logLik, "AIC" = AIC, "BIC" = BIC, "EDF" = EDF)
lapply(res, function(x) sapply(metds, function(f) f(x)))
#> [[1]]
#> [[1]]$logLik
#> 'log Lik.' 266.8974 (df=9)
#>
#> [[1]]$AIC
#> [1] -515.7948
#>
#> [[1]]$BIC
#> [1] -477.8633
#>
#> [[1]]$EDF
#> [1] 1 2 3 3
#>
#>
#> [[2]]
#> [[2]]$logLik
#> 'log Lik.' 302.9581 (df=16.24202)
#>
#> [[2]]$AIC
#> [1] -573.4321
#>
#> [[2]]$BIC
#> [1] -504.9783
#>
#> [[2]]$EDF
#> [1] 1.000000 1.999178 7.577543 5.665301
#>
#>
## Comparison between fitted, true smooth and spline approximation for each
## true smooth function for the two basis sizes
fitted <- lapply(res, function(x) gamBiCopPredict(x, data.frame(x1 = u, x2 = u, x3 = u),
type = "terms"
)$calib)
true <- vector("list", 3)
for (i in 1:3) {
y <- eta0 + calib.surf[[i]](u)
true[[i]]$true <- y - eta0
temp <- gam(y ~ s(u, k = basis0[i], bs = "cr", fx = TRUE))
true[[i]]$approx <- predict.gam(temp, type = "terms")
temp <- gam(y ~ s(u, k = basis1[i], bs = "cr", fx = FALSE))
true[[i]]$approx2 <- predict.gam(temp, type = "terms")
}
## Display results
par(mfrow = c(1, 3), pty = "s")
yy <- range(true, fitted)
yy[1] <- yy[1] * 1.5
for (k in 1:3) {
plot(u, true[[k]]$true,
type = "l", ylim = yy,
xlab = paste("Covariate", k), ylab = paste("Smooth", k)
)
lines(u, true[[k]]$approx, col = "red", lty = 2)
lines(u, fitted[[1]][, k], col = "red")
lines(u, fitted[[2]][, k], col = "green")
lines(u, true[[k]]$approx2, col = "green", lty = 2)
legend("bottomleft",
cex = 0.6, lty = c(1, 1, 2, 1, 2),
c("True", "Fitted", "Appox 1", "Fitted 2", "Approx 2"),
col = c("black", "red", "red", "green", "green")
)
}