How do I code a piecewise mixed-model in lme in R? - r

I followed this example for running a piecewise mixed model using lmer, and it works very well. However, I am having trouble translating the model to lme because I need to deal with heteroscedasticity, and lmer doesn’t have that ability.
Code to reproduce the problem is here. I included details about the experimental design in the code if you think it’s necessary to answer the question.
Here is the model without the breakpoint:
linear <- lmer(mass ~ lat + (1 | pop/line), data = df)
And here is how I run it with the breakpoint:
bp = 30
b1 <- function(x, bp) ifelse(x < bp, x, 0)
b2 <- function(x, bp) ifelse(x < bp, 0, x)
breakpoint <- lmer(mass ~ b1(lat, bp) + b2(lat, bp) + (1 | pop/line), data = df)
The problem is that I have pretty severe heteroscedasticity. As far as I understand, that means I should be using lme from the nlme package. Here is the linear model in lme:
ctrl <- lmeControl(opt='optim')
linear2 <- lme(mass ~ lat , random=~1|pop/line, na.action = na.exclude, data=df, control = ctrl, weights=varIdent(form=~1|pop))
And this is the breakpoint model that is, well, breaking:
breakpoint2 <- lme(mass ~ b1(lat, bp) + b2(lat, bp), random=~1|pop/line, na.action = na.exclude, data=df, control = ctrl, weights=varIdent(form=~1|pop))
Here is the error message:
Error in model.frame.default(formula = ~pop + mass + lat + bp + line, : variable lengths differ (found for 'bp')
How can I translate this lovely breakpoint model from lmer to lme? Thank you!

Looks like lme doesn't like it when you use variables in your formula that aren't in the data.frame you are fitting your model on. One option would be to build your formula first then pass it to lme. For example
myform <- eval(substitute(mass ~ b1(lat, bp) + b2(lat, bp), list(bp=bp)))
breakpoint2 <- lme(myform, random=~1|pop/line, na.action = na.exclude, data=df, control = ctrl, weights=varIdent(form=~1|pop))
The eval()/substitute() is just to swap out the bp in your formula with the value of the variable bp
Or if bp were always 30, you would just put that directly in the formula
breakpoint2 <- lme(mass ~ b1(lat, 30) + b2(lat, 30), random=~1|pop/line, na.action = na.exclude, data=df, control = ctrl, weights=varIdent(form=~1|pop))
and that would work as well.

Related

how do i write this exponential model as a function in R?

For y = B0 + B1x, I can write it as lm(y ~ x). However I am not sure how to write y = B0eB1x into a model function in R.
I have tried lm(log(y) ~ x), lm(y ~ exp(x)), lm(y ~ log(x)), and lm(log(y) ~ log(x)), but I am not sure which is correct. I get different results for each model.
The two ways that you can do this that are actually faithful to the original statistical model (Gaussian errors with constant variance) are:
glm(y ~ x, family = gaussian(link = "log"), data = ...)
(but you'll have to exponentiate the intercept parameter) or
nls(y ~ b0*exp(b1*x), start = ..., data = ...)
(but you'll have to provide starting values in the form list(b0 = 1, b1 = 1) (for some sensible values).
y = b0*exp(b1*x) implies log(y) = log(b0) + b1*x, but transforming the response variable in this way will change the statistical model ... so lm(log(y) ~ x, data = ...) will give you similar but not identical answers to the preceding two recipes.

Nonlinear mixed model without random effects structure specification

I would like to fit a nonlinear model just with the fixed structure specification using nlme R package.
model <- nlme(y ~ Asym/(1+exp((xmid-x)/scal)),
data = data,
fixed = list(Asym + xmid + scal ~ treatment))
#random = Asym ~ 1|subject)
However I am getting the following error:
Error in parse(text = paste("~", paste(nVal, collapse = "/"))) :
<text>:2:0: unexpected end of input
1: ~
^
Is there a way to circunvent this issue? Any advice is more than welcome.
I believe you want the gnls() function (also from the nlme package) with the params= argument rather than fixed=. Try this:
model <- gnls(y ~ Asym/(1+exp((xmid-x)/scal)),
data = data,
params = list(Asym + xmid + scal ~ treatment),
start= ...)
FWIW, if you're really fitting a logistic (and this isn't just a simplified example of what you want to do), fitting might be faster/more robust with the SSlogis() self-starting function in place of your explicit formula ...

Syntax for glmer function for use with glmulti?

Using glmer, I can run a logistic regression mixed model just fine. But when I try to do the same using glmulti, I get errors (described below). I think the problem is with the function I am specifying for use in glmulti. I want a function that specifies a logistic regression model for data containing continuous fixed covariates and categorical random effects, using a logit link. The response variable is a binary 0/1.
Sample data:
library(lme4)
library(rJava)
library(glmulti)
set.seed(666)
x1 = rnorm(1000) # some continuous variables
x2 = rnorm(1000)
x3 = rnorm(1000)
r1 = rep(c("red", "blue"), times = 500) #categorical random effects
r2 = rep(c("big", "small"), times = 500)
z = 1 + 2*x1 + 3*x2 +2*x3
pr = 1/(1+exp(-z))
y = rbinom(1000,1,pr) # bernoulli response variable
df = data.frame(y=y,x1=x1,x2=x2, x3=x3, r1=r1, r2=r2)
A single glmer logistic regression works just fine:
model1<-glmer(y~x1+x2+x3+(1|r1)+(1|r2),data=df,family="binomial")
But errors occur when I try to use the same model structure through glmulti:
# create a function - I think this is where my problem is
glmer.glmulti<-function(formula, data, family=binomial(link ="logit"), random="", ...){
glmer(paste(deparse(formula),random),data=data,...)
}
# run glmulti models
glmulti.logregmixed <-
glmulti(formula(glmer(y~x1+x2+x3+(1|r1)+(1|r2), data=df), fixed.only=TRUE), #error w/o fixed.only=TRUE
data=df,
level = 2,
method = "g",
crit = "aicc",
confsetsize = 128,
plotty = F, report = F,
fitfunc = glmer.glmulti,
family = binomial(link ="logit"),
random="+(1|r1)","+(1|r2)", # possibly this line is incorrect?
intercept=TRUE)
#Errors returned:
singular fit
Error in glmulti(formula(glmer(y ~ x1 + x2 + x3 + (1 | r1) + (1 | r2), :
Improper call of glmulti.
In addition: Warning message:
In glmer(y ~ x1 + x2 + x3 + (1 | r1) + (1 | r2), data = df) :
calling glmer() with family=gaussian (identity link) as a shortcut to lmer() is deprecated; please call lmer() directly
I've tried various changes to the function, and within the formula and fitfunc portion of the glmulti code. I've tried substituting lmer for glmer and I guess I don't understand the error. I'm also afraid that calling lmer may change the model structure, as during one of my attempts the summary() of the model stated "Linear mixed model fit by REML ['lmerMod']." I need the glmulti models to be the same as what I'm obtaining with model1 using glmer (ie summary(model1) gives "Generalized linear mixed model fit by maximum likelihood (Laplace Approximation) ['glmerMod']"
Many similar questions remain unanswered. Thanks in advance!
Credit:
sample data set created with help from here:
https://stats.stackexchange.com/questions/46523/how-to-simulate-artificial-data-for-logistic-regression
glmulti code adapted from here:
Model selection using glmulti

Intercept of random effect - library(sommer)

When I run this mixed model, I get all of the statistics I need.
library(sommer)
data(example)
#Model without intercept - OK
ans1 <- mmer2(Yield~Env,
random= ~ Name + Env:Name,
rcov= ~ units,
data=example, silent = TRUE)
summary(ans1)
ans1$u.hat #Random effects
However if I try to get the intercept to random effects, like in the R library lme4, I get a error like:
Error in dimnames(x) <- dn :
length of 'dimnames' [2] not equal to array extent
#Model with intercept
ans2 <- mmer2(Yield~Env,
random= ~ 1+Name + Env:Name,
rcov= ~ units,
data=example, silent = TRUE)
summary(ans2)
ans2$u.hat #Random effects
How can I overcome that?
Your model:
ans1 <- mmer2(Yield~Env,
random= ~ Name + Env:Name,
rcov= ~ units,
data=example, silent = TRUE)
is equivalent to:
ans1.lmer <- lmer(Yield~Env + (1|Name) + (1|Env:Name),
data=example)
using lme4. Please notice that lme4 uses the notation (x|y) to specify if there is for example different intercepts (x term) for each level of the second term (y term) which is a random regression model. If you specify:
ans2.lmer <- lmer(Yield~Env + (Env|Name),
data=example)
you get three variance components, one for each of the 3 levels in the Env term. The equivalent in sommer is not a random regression but a heterogeneous variance model using the diag() functionality:
ans2 <- mmer2(Yield~Env,
random= ~ diag(Env):Name,
rcov= ~ units,
data=example, silent = TRUE)
## or in sommer >=3.7
ans2 <- mmer(Yield~Env,
random= ~ vs(ds(Env),Name),
rcov= ~ units,
data=example, silent = TRUE)
The first 2 models above are equivalent because both models assume there's no different intercepts, whereas the last two models tackle the same problem but with two different approaches that are not exactly the same; random regression versus heterogeneous variance model.
In short, sommer doesn't have random regression implemented yet so you cannot use random intercepts in sommer like you do in lme4, but instead use a heterogeneous variance models.
Cheers,
I know it is not an elegant solution, but how about adding intercept to the data, so you can easily use it in the model?
What I mean is:
example <- cbind(example, inter=1)
ans2 <- mmer2(Yield~Env,
random= ~ Name + Env:Name + inter, #here inter are 1's
rcov= ~ units,
data=example, silent = TRUE)
summary(ans2)
ans2$u.hat

glmulti with a fractional logit model

I want to fit a fractional logit model with the command:
glmfit <- glm(tr1 ~ period + male + stib+ income,
family = quasibinomial(link = "logit"), data=mydata)
Where tr1 is a variable that lies between zero and one (including some zeros).
I now want to choose the model with the smallest QAIC value (i.e. testing possible combinations of the independent variables and checking the resulting QAIC values). To do that, I tried to apply the glmulti command in R:
require("glmulti")
glmulti.out <- glmulti(tr1 ~ period + male + stib+ income,
data = mydata,crit = "qaic",
confsetsize = 5, fitfunction = "glm",
family = quasibinomial(link = "logit"))
However, I constantly get the following error and I can't see why:
Error in lesCrit[sel] = cricri : replacement has length zero
Does anyone know how I could overcome this problem?
For me this worked:
library(bbmle)
qaicmod = function (fit) qAIC(fit, dispersion=with(fit,sum((weights * residuals^2)[weights > 0])/df.residual) )
glmulti.out <- glmulti(tr1 ~ period + male + stib+ income,
data = mydata,crit = "qaicmod",
confsetsize = 5, fitfunction = "glm",
family = binomial(link = "logit"))
This uses a regular binomial GLM but calculates the QAIC based on the estimated dispersion coefficient.
In the dispersion argument of the qaicmod function you could also put the estimated dispersion coefficient of a full quasibinomial GLM with all variables included (some statisticions I have seen recommend this), i.e. to use instead
disp <<- summary(fullmodel)$dispersion
qaicmod = function (fit) qAIC(fit, dispersion=disp)
Finally, I also tried using
library(MuMIn)
x.quasibinomial <<- function(...) {
res <- quasibinomial(...)
res$aic <- binomial(...)$aic
res
}
qaicmod <<- function (fit) QAIC(update(fit, family = x.quasibinomial), chat = deviance(fit) / df.residual(fit))
glmulti.out <- glmulti(tr1 ~ period + male + stib+ income,
data = mydata,crit = "qaicmod",
confsetsize = 5, fitfunction = "glm",
family = binomial(link = "logit"))
but that returns the error "Error in eval(expr, envir, enclos) : could not find function "fitfunc"" - not sure how I can fix that...
(The idea would be that this solution would properly refit the model as a quasibinomial GLM and then return the QAIC from that)
First solution above should be OK though I think...

Resources