5
$\begingroup$

I have data from two eyes that have been repeatedly measured across time (5 time points) for their intraocular pressure (IOP). Various measurements were taken including categorical and continuous data. Not all patients have both eyes eligible for the study, so there is a mixture of patients, some with 1 and some with 2 eyes. Covariates assesed at baseline include age, gender, corneal thickness and other parameters that vary between eyes of each participant.

I have formatted the data so that there are additional rows for each eye and rows for each measurement across time. I also want to investigate the interaction effect between CornealThickness and Time, as well as Gender and Time.

Is the following the correct specification of the model in R, specifically unsure how nesting should be specified:

lmer(IOP ~ Age + Gender + CornealThickness + as.factor(Time) + Gender*as.factor(Time) + CornealThickness*as.factor(Time) + (1|ID/Eye), data=data)

Alternatively, would it be the following:

lmer(IOP ~ Age + Gender + CornealThickness + as.factor(Time) + Gender*as.factor(Time) + CornealThickness*as.factor(Time) + (as.factor(Time)|ID/Eye), data=data)

UPDATE: I have tried to run the mmrm model on this dataset:

 m1 <-  mmrm::mmrm( formula = IOP ~ age + eye_visit +diabetes_duration+ us(eye_visit | id), data = data, control = mmrm_control(method = "Kenward-Roger") )

However I get the following error message:

Problem with these data entries: y_vector 5 Error in fit_single_optimizer(formula = formula, data = data, weights = weights, : Only numeric matrices, vectors, arrays, factors, lists or length-1-characters can be interfaced

What does this mean?

Thank you!

$\endgroup$
15
  • $\begingroup$ Is there some reason why you are treating Time as a factor instead of continuous? $\endgroup$
    – EdM
    Commented Oct 13, 2023 at 14:15
  • 1
    $\begingroup$ Longitudinal data are often best handled using serial correlation models and not random effects so here you have an ideal case for having random effects for patients (assuming exchangeability of eyes) and a serial correlation structure for the longitudinal part, e.g., generalized least squares or a Markov model. A Bayesian random effects Markov model would be especially of interested. See here. $\endgroup$ Commented Oct 13, 2023 at 14:23
  • $\begingroup$ @FrankHarrell, doesn't the second model also allow for (unstructured) correlation over time? At least, given the choice between these two, I would certainly prefer the latter. The nesting hierarchy should not matter because each subject should only have one of each eye (per timepoint), so the choice is between 2 N*N blocks or N 2*2 blocks. $\endgroup$
    – PBulls
    Commented Oct 13, 2023 at 15:15
  • 1
    $\begingroup$ @FrankHarrell , Some participants may have 2 eyes studied, depending on eligibility of the eye. So we have at most 2 eyes measured per person over 5 time points. $\endgroup$
    – s.stats
    Commented Oct 13, 2023 at 16:10
  • 1
    $\begingroup$ Correlation structures like autoregressive, especially AR(1) over time tend to be terrible in terms of how they behave. They usually overestimate correlation of near-by observation and then - usually wrongly decide that observations that are sufficiently far apart are totally independent (when the data usually clearly contradicts that). $\endgroup$
    – Björn
    Commented Nov 20, 2023 at 12:21

2 Answers 2

3
+50
$\begingroup$

Another approach you can take is to look at observations from separate eyes as if they were at different times and let the data largely determine the appropriate correlations (and levels of variability) between observations from the two eyes. E.g. using the mmrm R package (assuming everything you want to be a factor is already a factor, and where eye_visit is a factor that's a concatenation of eye and visit, such as "left_week4", "right_week4", "left_week8" etc.):

mmrm::mmrm(
  formula = IOP ~ 0 + eye_visit + ...other model terms... + us(eye_visit | id),
  data = data,
  control = mmrm_control(method = "Kenward-Roger")
)

(see here for an introduction to the package).

The advantages of this approach include that

  1. you don't assume the variability at each visit/for each eye is the same over time (often variability goes up over time), and
  2. you flexibly estimate how correlated different timepoints (and the eyes in the same person) are from the data without imposing something like a AR(1) structure (that tends to be very wrong for any real data, but if you assumed a more structured covariance structure that is appropriate you might have a gain in efficiency).

Additionally, you can think about what variables should have an interaction with time and/or eye (e.g. a baseline starting assessment would usually be allowed to interact with the factor for time). However, that's possible in any of the models that were already mentioned.

Example:

library(tidyverse)
library(mmrm)

set.seed(42)
example <- tibble(eye=rep(c("left", "right"), 30),
                  visit=rep(rep(c("Week0", "Week4", "Week8"), each=2), 10),
                  id=rep(1L:10L, each=6),
                  random_subject_effect = rnorm(n=10, mean=0, sd=10)[id],
                  age = sample(18:85, size=10, replace=T)[id],
                  IOP = rnorm(n=60, 
                              mean=random_subject_effect+10-(eye=="left")*3+as.integer(str_extract(visit, "[0-8]+")), 
                              sd=5)) %>%
  dplyr::select(-random_subject_effect) %>%
  mutate(eye_visit = factor(paste0(eye, "_", visit)),
         id=factor(id))

mmrmfit1 <- mmrm::mmrm(
  formula = IOP ~ 0 + eye_visit + age + us(eye_visit | id),
  data = example,
  method = "Kenward-Roger")

mmrmfit1 %>%
  summary()
$\endgroup$
20
  • $\begingroup$ I tried to run the model however I am getting the following error message: "Problem with these data entries: y_vector 5 Error in fit_single_optimizer(formula = formula, data = data, weights = weights, : Only numeric matrices, vectors, arrays, factors, lists or length-1-characters can be interfaced". I have added this as an update to the question. Thanks! $\endgroup$
    – s.stats
    Commented Nov 23, 2023 at 21:20
  • $\begingroup$ I've added an example, which runs fine for me. I'm not 100% sure what triggers that error message you show, but have you checked 1) that the input you provide is a data.frame or tibble, (2) that the key variables you need to be factors are factors (e.g. id and eye_visit), (3) that there's nothing funny about other columns (e.g. IOP, age and diabetes_duration should be numeric columns and not have anything like, say, list entries)? $\endgroup$
    – Björn
    Commented Nov 24, 2023 at 9:11
  • $\begingroup$ Thanks very much for the example, it was very helpful! Setting eye_visit and id to factors didn't work. But my dependent variable was actually a labelled numeric, after setting this to numeric, the code ran! $\endgroup$
    – s.stats
    Commented Nov 24, 2023 at 15:56
  • $\begingroup$ Also, why add the "0" to the formula ? Thanks $\endgroup$
    – s.stats
    Commented Nov 24, 2023 at 15:58
  • $\begingroup$ It doesn't really matter either way when you fit a model using some form of maximum likelihood, the inference is just the same if you have an intercept or not (as long as you form your contrasts appropriately from the fit model using e.g. emmeans::emmeans()). 1+eye_visit (same as eye_visit) makes the eye_visit coefficients refer to how much any eye-visit combination deviates from the intercept (which refers to the reference category), while 0+eye_visit omits the intercept so that each is kind of the absolute level for each eye-visit (kind of, bc there's of course other covariates). $\endgroup$
    – Björn
    Commented Nov 24, 2023 at 22:01
4
$\begingroup$

Is the following the correct specification of the model in R, specifically unsure how nesting should be specified:

lmer(IOP ~ Age + Gender + CornealThickness + as.factor(Time) + Gender*as.factor(Time) + CornealThickness*as.factor(Time) + (1|ID/Eye), data=data)

Alternatively, would it be the following:

lmer(IOP ~ Age + Gender + CornealThickness + as.factor(Time) + Gender*as.factor(Time) + CornealThickness*as.factor(Time) + (as.factor(Time)|ID/Eye), data=data)

The only difference between these models is that in the latter one, random slopes for each time point are specified.

Either model could be appropriate, but consider these issues:

  • Serial correlation of residuals within subjects. The model fitted by lmer assumes that residuals are independent and identically distributed. However, as mentioned by Frank Harrell in the question comments, this type of study (longitudinal) should be expected to involve serial correlation. That is, the residuals are expected to feature a serial correlation structure in which the correlation between two measurements on the same subject decreases as the time gap widens. The lmer function cannot handle this so if would be a good idea to consider using nlme instead which does offer various correlation structures such as AR(1). Alternatively, again as mentioned by Frank Harrell, a Discrete Time Markov Model or a Generalised Least Squares model should be considered. See here for an excellent introduction to Markov Models for longitudinal data.

  • The presence of random slopes in the second model is reasonable if we expect that the effect of each Time point to vary by subject, though be aware that this sometimes causes a difficulty in fitting leading to a singular model.

  • Nesting structure: |ID/Eye says that Eye is nested within ID, which appears to be correct. @PBulls makes an interesting point about not needing the random intercepts for Eye, however I'm not sure that I fully agree. I would suggest fitting the nested model and a simpler model with random intercepts for just ID and compare the results.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.