Previous: The Memory-Efficient Layout | Up: Easy Ways to Manage | Next: Adding Models and Methods |
Continuing the bivariate probit example above, we only need to modify a few lines of code to put these different schemes into effect. Using the default (memory-efficient) options, the log-likelihood is:
bivariate.probit <- function(formula, data, start.val = NULL, ...) { fml <- parse.formula(formula, model = "bivariate.probit") D <- model.frame(fml, data = data) X <- model.matrix(fml, data = D, eqn = c("mu1", "mu2")) # [1] Xrho <- model.matrix(fml, data = D, eqn = "rho") Y <- model.response(D) terms <- attr(D, "terms") start.val <- set.start(start.val, terms) start.val <- put.start(start.val, 1, terms, eqn = "rho") log.lik <- function(par, X, Y, terms) { Beta <- parse.par(par, terms, eqn = c("mu1", "mu2")) # [2] gamma <- parse.par(par, terms, eqn = "rho") rho <- (exp(Xrho %*% gamma) - 1) / (1 + exp(Xrho %*% gamma)) mu <- X %*% Beta # [3] llik <- 0 for (i in 1:nrow(mu)){ Sigma <- matrix(c(1, rho[i,], rho[i,], 1), 2, 2) if (Y[i,1]==1) if (Y[i,2]==1) llik <- llik + log(pmvnorm(lower = c(0, 0), upper = c(Inf, Inf), mean = mu[i,], corr = Sigma)) else llik <- llik + log(pmvnorm(lower = c(0, -Inf), upper = c(Inf, 0), mean = mu[i,], corr = Sigma)) else if (Y[i,2]==1) llik <- llik + log(pmvnorm(lower = c(-Inf, 0), upper = c(0, Inf), mean = mu[i,], corr = Sigma)) else llik <- llik + log(pmvnorm(lower = c(-Inf, -Inf), upper = c(0, 0), mean = mu[i,], corr = Sigma)) } return(llik) } res <- optim(start.val, log.lik, method = "BFGS", hessian = TRUE, control = list(fnscale = -1), X = X, Y = Y, terms = terms, ...) fit <- model.end(res, D) class(fit) <- "bivariate.probit" fit }
If you find that the default (memory-efficient) method isn't the best way to run your model, you can use either the intuitive option or the computationally-efficient option by changing just a few lines of code as follows:
X <- model.matrix(fml, data = D, shape = "stacked", eqn = c("mu1", "mu2"))and at Comment [2],
Beta <- parse.par(par, terms, shape = "vector", eqn = c("mu1", "mu2"))The line at Comment [3] remains the same as in the original version.
X <- model.matrix(fml, data = D, shape = "array", eqn = c("mu1", "mu2"))At Comment [2]:
Beta <- parse.par(par, terms, shape = "vector", eqn = c("mu1", "mu2"))At Comment [3]:
mu <- apply(X, 3, '%*%', Beta)
Even if your optimizer calls a C or FORTRAN routine, you can use
combinations of model.matrix() and parse.par() to set up
the data structures that you need to obtain the linear predictor (or
your model's equivalent) before passing these data structures to your
optimization routine.