2

A common situation in ecology is a survival model with a binary outcome (0=die, 1=survive) where individuals (for this example think of individual nesting attempts by birds) differ in the number of days they are exposed to risk of mortality. To account for this, we use a modified logistic regression which incorporates the # of exposure days into the link function.
As described by Shaffer (2004):

“The daily survival rate is modeled in terms of x through the choice of an appropriate predictor function, which in our case should yield values between zero and one. As is done in logistic regression, we use the S-shaped logistic function:

enter image description here

The systematic component of our generalized linear model is then [s(x)]t. 
Next, we consider the function:

enter image description here

The above function is monotonic and differentiable with respect to θ, and it can be shown that g(θ) = β0 + β1x, which satisfies the criteria for a link function in a generalized linear model. Those three components: the binomial response distribution, the predictor function given in Expression 1, and the link function given in Expression 2, completely specify our generalized linear model. The model (hereafter “the logistic-exposure model”) is similar to the logistic regression model but differs in the form of the link function. The logistic-exposure link function contains an exponent (1/t) in the numerator and denominator that is not present in the logistic-regression link function. The exponent is necessary to account for the fact that probability of surviving an interval depends on interval length.”

Code for this link function is available on the web, and is also one of the example link functions described in R if you type "help(family)":

logexp <- function(days = 1)
{
linkfun <- function(mu) qlogis(mu^(1/days))
linkinv <- function(eta) plogis(eta)^days
mu.eta <- function(eta) days * plogis(eta)^(days-1) *
  .Call("logit_mu_eta", eta, PACKAGE = "stats")
valideta <- function(eta) TRUE
link <- paste("logexp(", days, ")", sep="")
structure(list(linkfun = linkfun, linkinv = linkinv,
               mu.eta = mu.eta, valideta = valideta, name = link),
          class = "link-glm")
}

It works just fine in a model such as this:

glm(survive ~ date, family=binomial(link=logexp(days=dat$Days)),data=dat)

The problem I run into is when trying to use this custom link function in a GLMER model with the addition of a random effect (I have found one example online of this method being implemented here: http://rstudio-pubs-static.s3.amazonaws.com/4082_51aa699bd9f041c7b3f7cf7b9252f60c.html).

In our case we would like to include site as a random effect. Models are formulated the same way as the GLMs from before:

glmer(survive ~ date + (1|site), family=binomial(link=logexp(days=dat$Days)),data=dat)

However, now I get an error message:

Error in famType(glmFit$family) : unknown link: ‘logexp(3)’unknown link: ‘logexp(4)’unknown link: ‘logexp(3)’unknown link: ‘logexp(2)’unknown link: ‘logexp(3)’unknown link: ‘logexp(3)’unknown link: ‘logexp(4)’unknown link: ‘logexp(3)’unknown link: ‘logexp(2)’unknown link: ‘logexp(1)’unknown link: ‘logexp(4)’unknown link: ‘logexp(5)’unknown link: ‘logexp(4)’unknown link: ‘logexp(3)’unknown link: ‘logexp(4)’unknown link: ‘logexp(5)’unknown link: ‘logexp(3)’unknown link: ‘logexp(4)’unknown link: ‘logexp(3)’unknown link: ‘logexp(3)’unknown link: ‘logexp(3)’unknown link: ‘logexp(3)’unknown link: ‘logexp(3)’unknown link: ‘logexp(3)’unknown link: ‘logexp(3)’unknown link: ‘logexp(3)’unknown link: ‘logexp(3)’unknown link: ‘logexp(2)’unknown link: ‘logexp(1)’unknown link: ‘logexp(3)’unknown link: ‘logexp(1)’unknown link: ‘logexp(1)’unknown link: ‘logexp(1)’unknown link: ‘logexp(1)’unkn In addition: Warning message: In if (!(lTyp <- match(family$link, linkNms, nomatch = 0))) stop(gettextf("unknown link: %s", : the condition has length > 1 and only the first element will be used

The error message lists an unknown link for every row of data with the numbers corresponding to the exposure days for that nest visit (or row of data).

ex: The first 'logexp(3)' corresponds to the first row of data which has 3 exposure days.

Has anyone else been able to use this custom link function in a GLMER model? Or if not does anyone have an idea about what’s causing the error?

######UPDATE######

Many thanks to Ben Bolker for solving this problem. I updated to 3.0.2 and the latest version of lme4 and used the link function Ben's R related post (https://www.rpubs.com/bbolker/logregexp), which is this one:

library(MASS)
logexp <- function(exposure = 1)
{
linkfun <- function(mu) qlogis(mu^(1/exposure))
## FIXME: is there some trick we can play here to allow
##   evaluation in the context of the 'data' argument?
linkinv <- function(eta)  plogis(eta)^exposure
mu.eta <- function(eta) exposure * plogis(eta)^(exposure-1) *
  .Call(stats:::C_logit_mu_eta, eta, PACKAGE = "stats")
valideta <- function(eta) TRUE
link <- paste("logexp(", deparse(substitute(exposure)), ")",
               sep="")
structure(list(linkfun = linkfun, linkinv = linkinv,
               mu.eta = mu.eta, valideta = valideta, 
               name = link),
          class = "link-glm")
}
Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
ktalent1
  • 69
  • 1
  • 7

1 Answers1

3

You need to use a more recent version of the lme4 package, e.g. the 1.0-4 version that has just gone up on CRAN. Earlier versions did not allow user-specified link functions.

Also, note that the code you posted above is not what appears in recent versions of ?family, where the (obsolete) .Call("logit_mu_eta", eta, PACKAGE = "stats") is replaced by a pure-R implementation:

logexp <- function(days = 1)
     {
         linkfun <- function(mu) qlogis(mu^(1/days))
         linkinv <- function(eta) plogis(eta)^days
         mu.eta <- function(eta) days * plogis(eta)^(days-1) * binomial()$mu_eta
         valideta <- function(eta) TRUE
         link <- paste0("logexp(", days, ")")
         structure(list(linkfun = linkfun, linkinv = linkinv,
                        mu.eta = mu.eta, valideta = valideta, name = link),
                   class = "link-glm")
     }

The link you specified above does in fact have an example of such a model (but it does require a recent version of lme4).

Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
  • 1
    Thanks for the prompt response, and sorry for some of the confusion on the post. You are right that the code wasn't directly from help(family). I do have 1-0.4 version of lme4 and I am still getting an error when I use the code above. I have tried it on our actual data, as well as (poorly) simulated data. The error message is this: **Error in get(name, envir = asNamespace(pkg), inherits = FALSE) : object '.setDummyField' not found** – ktalent1 Sep 25 '13 at 19:12
  • 1
    That is a known problem with using CRAN-built binaries on R version 3.0.0; it doesn't affect any version before or after that (i.e. R up to 2.15.3 or after 3.0.1). The very newest version of R, 3.0.2, was announced today, but hasn't made it to CRAN (even the main http://cran.r-project.org site) yet. You can build from source, or install 3.0.1 now, or wait a little bit for 3.0.2 ... – Ben Bolker Sep 25 '13 at 19:18
  • 1
    Thanks so much! Updated to 3.0.2, which came out today for Mac, and used the link function posted here: http://rpubs.com/bbolker/4082. Worked like a charm - victory beer is in order! – ktalent1 Sep 25 '13 at 19:43