Warning lme4: Model failed to converge with max|grad| - r

I have to run a lmer with a log transformed response variable, a continuous variable as fixed effect and and a nested random effect:
first<-lmer(logterrisize~spm + (1|studyarea/teriid),
data = Data_table_for_analysis_Character_studyarea,
control=lmerControl(optimizer="Nelder_Mead",
optCtrl=list(maxfun=1e4)))
I got this error message: Error in length(value <- as.numeric(value)) == 1L :
Downdated VtV is not positive definite
I tried this with bobyqa() as optimization argument and got this warning messages:
1: In checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, :
Model failed to converge with max|grad| = 0.753065 (tol = 0.002, component
1) 2: In checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv,:
Model is nearly unidentifiable: very large eigenvalue-Rescale variables?
my summary looks like this:
Linear mixed model fit by REML ['lmerMod']
Formula: logterrisize ~ spm + (1 studyarea/teriid) Data: Data_table_for_analysis_Character_studyareaControl: lmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 10000)) REML criterion at convergence: -6079.6Scaled residuals:
Min 1Q Median 3Q Max
-3.639e-07 -4.962e-08 3.310e-09 5.293e-08 9.725e-07
Random effects:
Groups Name Variance Std.Dev.
teriid:studyarea (Intercept) 1.291e-01 3.593e-01
studyarea (Intercept) 1.944e-02 1.394e-01
Residual 4.506e-15 6.712e-08
Number of obs: 273, groups: teriid:studyarea, 66; studyarea, 22
Fixed effects:
Estimate Std. Error t value
(Intercept) 1.480e+00 5.631e-02 26.28
spm -5.785e-16 8.507e-10 0.00
Correlation of Fixed Effects:
(Intr) spm 0.000 convergence code: 0
Model failed to converge with max|grad| = 0.753065 (tol = 0.002, component1)
Model is nearly unidentifiable: very large eigenvalue - Rescale variables?
my data looks like following:
show(logterrisize) [1] 1.3317643 1.3317643 1.3317643 0.1295798 0.1295798 1.5051368 1.5051368 1.5051368 1.5051368 [10] 1.5051368 1.5051368 1.5051368 1.5051368 1.5051368 1.5051368 1.5051368 1.5051368 1.5051368 [19] 1.5051368 1.5051368 1.5051368 1.4665993 1.4665993 1.4665993 1.8282328 1.8282328 1.9252934 [28] 1.9252934 1.9252934 2.3006582 2.3006582 2.5160920 2.7774040 2.7774040 3.3398623 3.3398623 [37] 3.4759297 1.2563594 1.6061204 1.6061204 1.7835139 1.7835139 2.1669498 2.1669498 2.1669498 [46] 2.1669498 0.7264997 0.7458155 0.8380524 0.8380524 0.8380524 0.8380524 0.8380524 0.8380524
show(spm) [1] 18.461538 22.641509 35.172414 10.418006 15.611285 3.482143 3.692308 4.483986 4.821429 [10] 6.000000 6.122449 6.176471 6.220736 6.260870 6.593407 7.010309 9.200000 9.473684 [19] 9.600000 12.600000 14.200000 16.146179 28.125000 30.099010 13.731343 14.432990 11.089109 [28] 17.960526 32.903226 8.955224 33.311688 8.800000 11.578947 20.000000 14.455446 18.181818 [37] 28.064516 25.684211 17.866667 23.142857 18.208955 20.536913 11.419355 11.593220 12.703583 [46] 20.000000 3.600000 11.320755 6.200000 6.575342 12.800000 19.109589 20.124224 22.941176 [55] 4.600000 6.600000 6.771160 8.000000 19.200000 19.400000 22.773723 3.333333 4.214047
Studyarea are character names and teriID represents continuous numbers of the study sites.
My data frame looks like this:
Did I forget anything to include to the equation while using a log transformed variable?
Thanks!
EDIT:
I used ?convergence to check on convergence errors. I tried this:
## 3. recompute gradient and Hessian with Richardson extrapolation
devfun <- update(first, devFunOnly=TRUE)
if (isLMM(first)) {
pars <- getME(first,"theta")
} else {## GLMM: requires both random and fixed parameters
pars <- getME(first, c("theta","fixef"))
}
if (require("numDeriv")) {
cat("hess:\n"); print(hess <- hessian(devfun, unlist(pars)))
cat("grad:\n"); print(grad <- grad(devfun, unlist(pars)))
cat("scaled gradient:\n")
print(scgrad <- solve(chol(hess), grad))}
and got this answer:
hess:
[,1] [,2]
[1,] 147.59157 -14.37956
[2,] -14.37956 120.85329
grad:
[1] -222.1020 -108.1038
scaled gradient:
[1] -19.245584 -9.891077
Unfortunately I donĀ“t know what the answer should tell me.
2nd EDIT:
I tried numerous optimizer and while using this:
first<-lmer(logterrisize~spm + (1|studyarea/teriid),REML=FALSE,
data = Data_table_for_analysis_Character_studyarea,
control=lmerControl(optimizer="optimx",
optCtrl=list(method='nlminb')))
I only got one warning: In optwrap(optimizer, devfun, getStart(start, rho$lower, rho$pp), :
convergence code 1 from optimx
now my summary looks like this:
Linear mixed model fit by maximum likelihood ['lmerMod']
Formula: logterrisize ~ spm + (1 | studyarea/teriid)
Data: Data_table_for_analysis_Character_studyarea
Control: lmerControl(optimizer = "optimx", optCtrl = list(method ="nlminb"))
AIC BIC logLik deviance df.resid
-3772.4 -3754.3 1891.2 -3782.4 268
Scaled residuals:
Min 1Q Median 3Q Max
-1.523e-04 -1.693e-05 1.480e-06 1.436e-05 3.332e-04
Random effects:
Groups Name Variance Std.Dev.
teriid:studyarea (Intercept) 8.219e-02 0.2866882
studyarea (Intercept) 7.478e-02 0.2734675
Residual 3.843e-10 0.0000196
Number of obs: 273, groups: teriid:studyarea, 66; studyarea, 22
Fixed effects:
Estimate Std. Error t value
(Intercept) 1.551e+00 7.189e-02 21.58
spm 3.210e-11 2.485e-07 0.00
Correlation of Fixed Effects:
(Intr)spm 0.000
convergence code: 1
So may I able to turn a blind eye on this warning message or will this be a huge mistake?

tl;dr every observation on a territory shares the same territory size, so your random effect of territory ID is essentially explaining everything and leaving no variation at all for either the log(terrsize) fixed effect or the residual variance. Leaving the random effect of territory ID out of the model seems to give reasonable answers; a simulated data set replicates this pathology pretty well, but suggests that you'll end up with an underestimate of the spm effect ...
read data and plot
library(readxl)
library(dplyr)
dd <- (read_excel("lme4_terr_dataset.xlsx")
%>% rename(spm="scans per min",
studyarea="Study areaID",
teriid="TerritoryID",
terrsize="Territory_Size")
)
library(ggplot2); theme_set(theme_bw())
library(ggalt)
(ggplot(dd, aes(spm,terrsize,colour=studyarea))
+geom_point()
+geom_encircle(aes(group=teriid))
+theme(legend.position="none")
+ scale_y_log10()
)
This plot, with its horizontal lines of values from the same territory ID, is what helped me diagnose the problem. Confirming that every territory ID has a single territory size for all observations:
tt <- with(dd,table(terrsize,teriid))
all(rowSums(tt>0)==1) ## TRUE
model fitting
library(lme4)
m1 <- lmer(log(terrsize) ~ spm + (1|studyarea/teriid), dd)
## replicate warnings
m2 <- lmer(log(terrsize) ~ spm + (1|studyarea), dd)
## no warnings
now simulate similar-looking data
set.seed(101)
## experimental design: rep within f2 (terr_id) within f1 (study area)
ddx <- expand.grid(studyarea=factor(letters[1:10]),
teriid=factor(1:4),rep=1:5)
## study-area, terr_id effects, and spm
b_studyarea <- rnorm(10)
b_teriid <- rnorm(40)
ddx <- within(ddx, {
int <- interaction(studyarea,teriid)
spm <- rlnorm(nrow(ddx), meanlog=1,sdlog=1)
})
## compute average spm per terr/id
## (because response will be identical across id)
spm_terr <- aggregate(spm~int, data=ddx, FUN=mean)[,"spm"]
ddx <- within(ddx, {
mu <- 1+0.2*spm_terr[int]+b_studyarea[studyarea] + b_teriid[int]
tsize <- rlnorm(length(levels(int)), meanlog=mu, sdlog=1)
terrsize <- tsize[int]
})
gg1 %+% ddx
fit simulated data
This gives similar behaviour to the real data:
lmer(log(terrsize) ~ spm + (1|studyarea/teriid), ddx)
We can avoid the warnings by dropping teriid:
m1 <- lmer(log(terrsize) ~ spm + (1|studyarea), ddx)
But the true effect of spm (0.2) will be underestimated (because of the ignored noise from teriid ...)
round(confint(m1, parm="beta_"),3)
## 2.5 % 97.5 %
## (Intercept) 1.045 2.026
## spm 0.000 0.070
aggregating
On the basis of this single simulation, it looks like aggregating to the level of the territory (as recommended e.g. by Murtaugh 2007, "Simplicity and complexity in ecological data analysis" Ecology) and weighting by number of samples per territory gives a reasonable estimate of the true spm effect ...
ddx_agg <- (ddx
%>% group_by(studyarea,terrsize,teriid)
%>% summarise(spm=mean(spm),
n=n())
)
library(nlme)
m3x <- lme(log(terrsize) ~ spm, random=~1|studyarea, data=ddx_agg,
weights=varFixed(~I(1/n)))
round(summary(m3x)$tTab,3)
Value Std.Error DF t-value p-value
(Intercept) 0.934 0.465 29 2.010 0.054
spm 0.177 0.095 29 1.863 0.073

Related

Robust standard errors for negative binomial regression in R do not match those from Stata

I am replicating a negative binomial regression model in R. When calculating robust standard errors, the output does not match Stata output of standard errors.
The original Stata code is
nbreg displaced eei lcostofwar cfughh roadskm lpopdensity ltkilled, robust nolog
I have attempted both manual calculation and vcovHC from sandwich. However, neither produces the same results.
My regression model is as follows:
mod1 <- glm.nb(displaced ~ eei + costofwar_log + cfughh + roadskm + popdensity_log + tkilled_log, data = mod1_df)
With vcovHC I have tried every option from HC0 to HC5.
Attempt 1:
cov_m1 <- vcovHC(mod1, type = "HC0", sandwich = T)
se <- sqrt(diag(cov_m1))
Attempt 2:
mod1_rob <- coeftest(mod1, vcovHC = vcov(mod1, type = "HC0"))
The most successful has been HC0 and vcov = sandwich but no SEs are correct.
Any suggestions?
EDIT
My output is as follows (using HC0):
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.3281183 1.5441312 0.8601 0.389730
eei -0.0435529 0.0183359 -2.3753 0.017536 *
costofwar_log 0.2984376 0.1350518 2.2098 0.027119 *
cfughh -0.0380690 0.0130254 -2.9227 0.003470 **
roadskm 0.0020812 0.0010864 1.9156 0.055421 .
popdensity_log -0.4661079 0.1748682 -2.6655 0.007688 **
tkilled_log 1.0949084 0.2159161 5.0710 3.958e-07 ***
The Stata output I am attempting to replicate is:
Estimate Std. Error
(Intercept) 1.328 1.272
eei -0.044 0.015
costofwar_log 0.298 0.123
cfughh -0.038 0.018
roadskm 0.002 0.0001
popdensity_log -0.466 0.208
tkilled_log 1.095 0.209
The dataset is found here and the recoded variables are:
mod1_df <- table %>%
select(displaced, eei_01, costofwar, cfughh, roadskm, popdensity,
tkilled)
mod1_df$popdensity_log <- log(mod1_df$popdensity + 1)
mod1_df$tkilled_log <- log(mod1_df$tkilled + 1)
mod1_df$costofwar_log <- log(mod1_df$costofwar + 1)
mod1_df$eei <- mod1_df$eei_01*100
Stata uses the observed Hessian for its computations, glm.nb() uses the expected Hessian. Therefore, the default bread() employed by the sandwich() function is different, leading to different results. There are other R packages that employ the observed hessian for its variance-covariance estimate (e.g., gamlss) but these do not supply an estfun() method for the sandwich package.
Hence, below I simply set up a dedicated bread_obs() function that extracts the ML estimates from a negbin object, sets up the negative log-likelihood, computes the observed Hessian numerically via numDeriv::hessian() and computes the "bread" from it (omitting the estimate for log(theta)):
bread_obs <- function(object, method = "BFGS", maxit = 5000, reltol = 1e-12, ...) {
## data and estimated parameters
Y <- model.response(model.frame(object))
X <- model.matrix(object)
par <- c(coef(object), "log(theta)" = log(object$theta))
## dimensions
n <- NROW(X)
k <- length(par)
## nb log-likelihood
nll <- function(par) suppressWarnings(-sum(dnbinom(Y,
mu = as.vector(exp(X %*% head(par, -1))),
size = exp(tail(par, 1)), log = TRUE)))
## covariance based on observed Hessian
rval <- numDeriv::hessian(nll, par)
rval <- solve(rval) * n
rval[-k, -k]
}
With that function I can compare the sandwich() output (based on the expected Hessian) with the output using the bread_obs() (based on the observed Hessian).
s_exp <- sandwich(mod1)
s_obs <- sandwich(mod1, vcov = bread_obs)
cbind("Coef" = coef(mod1), "SE (Exp)" = sqrt(diag(s_exp)), "SE (Obs)" = sqrt(diag(s_obs)))
## Coef SE (Exp) SE (Obs)
## (Intercept) 1.328 1.259 1.259
## eei -0.044 0.017 0.015
## costofwar_log 0.298 0.160 0.121
## cfughh -0.038 0.015 0.018
## roadskm 0.002 0.001 0.001
## popdensity_log -0.466 0.135 0.207
## tkilled_log 1.095 0.179 0.208
This still has slight differences compared to Stata but these are likely numerical differences from the optimization etc.
If you create a new dedicated bread() method for negbin objects
bread.negbin <- bread_obs
then the method dispatch will use this if you do sandwich(mod1).
In R you need to manually provide a degree of freedom correction, so try this which I borrowed from this source:
dfa <- (G/(G - 1)) * (N - 1)/pm1$df.residual
# display with cluster VCE and df-adjustment
firm_c_vcov <- dfa * vcovHC(pm1, type = "HC0", cluster = "group", adjust = T)
coeftest(pm1, vcov = firm_c_vcov)
Here G is the number of Panels in your data set, N is the number of observations and pm1 is your model estimated. Obviously, you could drop the clustering.

Recreate spss GEE regression table in R

I have the (sample) dataset below:
round<-c( 0.125150, 0.045800, -0.955299, -0.232007, 0.120880, -0.041525, 0.290473, -0.648752, 0.113264, -0.403685)
square<-c(-0.634753, 0.000492, -0.178591, -0.202462, -0.592054, -0.583173, -0.632375, -0.176673, -0.680557, -0.062127)
ideo<-c(0,1,0,1,0,1,0,0,1,1)
ex<-data.frame(round,square,ideo)
When I ran the GEE regression in SPSS I took this table as a result.
I used packages gee and geepack in R to run the same analysis and I took these results:
#gee
summary(gee(ideo ~ square + round,data = ex, id = ideo,
corstr = "independence"))
Coefficients:
Estimate Naive S.E. Naive z Robust S.E. Robust z
(Intercept) 1.0541 0.4099 2.572 0.1328 7.937
square 1.1811 0.8321 1.419 0.4095 2.884
round 0.7072 0.5670 1.247 0.1593 4.439
#geepack
summary(geeglm(ideo ~ square + round,data = ex, id = ideo,
corstr = "independence"))
Coefficients:
Estimate Std.err Wald Pr(>|W|)
(Intercept) 1.054 0.133 63.00 2.1e-15 ***
square 1.181 0.410 8.32 0.0039 **
round 0.707 0.159 19.70 9.0e-06 ***
---
I would like to recreate exactly the table of SPSS(not the results as I use a subset of the original dataset)but I do not know how to achieve all these results.
A tiny bit of tidyverse magic can get the same results - more or less.
Get the information from coef(summary(geeglm())) and compute the necessary columns:
library("tidyverse")
library("geepack")
coef(summary(geeglm(ideo ~ square + round,data = ex, id = ideo,
corstr = "independence"))) %>%
mutate(lowerWald = Estimate-1.96*Std.err, # Lower Wald CI
upperWald=Estimate+1.96*Std.err, # Upper Wald CI
df=1,
ExpBeta = exp(Estimate)) %>% # Transformed estimate
mutate(lWald=exp(lowerWald), # Upper transformed
uWald=exp(upperWald)) # Lower transformed
This produces the following (with the data you provided). The order and the names of the columns could be modified to suit your needs
Estimate Std.err Wald Pr(>|W|) lowerWald upperWald df ExpBeta lWald uWald
1 1.0541 0.1328 62.997 2.109e-15 0.7938 1.314 1 2.869 2.212 3.723
2 1.1811 0.4095 8.318 3.925e-03 0.3784 1.984 1 3.258 1.460 7.270
3 0.7072 0.1593 19.704 9.042e-06 0.3949 1.019 1 2.028 1.484 2.772

R - Plm and lm - Fixed effects

I have a balanced panel data set, df, that essentially consists in three variables, A, B and Y, that vary over time for a bunch of uniquely identified regions. I would like to run a regression that includes both regional (region in the equation below) and time (year) fixed effects. If I'm not mistaken, I can achieve this in different ways:
lm(Y ~ A + B + factor(region) + factor(year), data = df)
or
library(plm)
plm(Y ~ A + B,
data = df, index = c('region', 'year'), model = 'within',
effect = 'twoways')
In the second equation I specify indices (region and year), the model type ('within', FE), and the nature of FE ('twoways', meaning that I'm including both region and time FE).
Despite I seem to be doing things correctly, I get extremely different results. The problem disappears when I do not consider time fixed effects - and use the argument effect = 'individual'.
What's the deal here? Am I missing something? Are there any other R packages that allow to run the same analysis?
Perhaps posting an example of your data would help answer the question. I am getting the same coefficients for some made up data. You can also use felm from the package lfe to do the same thing:
N <- 10000
df <- data.frame(a = rnorm(N), b = rnorm(N),
region = rep(1:100, each = 100), year = rep(1:100, 100))
df$y <- 2 * df$a - 1.5 * df$b + rnorm(N)
model.a <- lm(y ~ a + b + factor(year) + factor(region), data = df)
summary(model.a)
# (Intercept) -0.0522691 0.1422052 -0.368 0.7132
# a 1.9982165 0.0101501 196.866 <2e-16 ***
# b -1.4787359 0.0101666 -145.450 <2e-16 ***
library(plm)
pdf <- pdata.frame(df, index = c("region", "year"))
model.b <- plm(y ~ a + b, data = pdf, model = "within", effect = "twoways")
summary(model.b)
# Coefficients :
# Estimate Std. Error t-value Pr(>|t|)
# a 1.998217 0.010150 196.87 < 2.2e-16 ***
# b -1.478736 0.010167 -145.45 < 2.2e-16 ***
library(lfe)
model.c <- felm(y ~ a + b | factor(region) + factor(year), data = df)
summary(model.c)
# Coefficients:
# Estimate Std. Error t value Pr(>|t|)
# a 1.99822 0.01015 196.9 <2e-16 ***
# b -1.47874 0.01017 -145.4 <2e-16 ***
This does not seem to be a data issue.
I'm doing computer exercises in R from Wooldridge (2012) Introductory Econometrics. Specifically Chapter 14 CE.1 (data is the rental file at: https://www.cengage.com/cgi-wadsworth/course_products_wp.pl?fid=M20b&product_isbn_issn=9781111531041)
I computed the model in differences (in Python)
model_diff = smf.ols(formula='diff_lrent ~ diff_lpop + diff_lavginc + diff_pctstu', data=rental).fit()
OLS Regression Results
==============================================================================
Dep. Variable: diff_lrent R-squared: 0.322
Model: OLS Adj. R-squared: 0.288
Method: Least Squares F-statistic: 9.510
Date: Sun, 05 Nov 2017 Prob (F-statistic): 3.14e-05
Time: 00:46:55 Log-Likelihood: 65.272
No. Observations: 64 AIC: -122.5
Df Residuals: 60 BIC: -113.9
Df Model: 3
Covariance Type: nonrobust
================================================================================
coef std err t P>|t| [0.025 0.975]
--------------------------------------------------------------------------------
Intercept 0.3855 0.037 10.469 0.000 0.312 0.459
diff_lpop 0.0722 0.088 0.818 0.417 -0.104 0.249
diff_lavginc 0.3100 0.066 4.663 0.000 0.177 0.443
diff_pctstu 0.0112 0.004 2.711 0.009 0.003 0.019
==============================================================================
Omnibus: 2.653 Durbin-Watson: 1.655
Prob(Omnibus): 0.265 Jarque-Bera (JB): 2.335
Skew: 0.467 Prob(JB): 0.311
Kurtosis: 2.934 Cond. No. 23.0
==============================================================================
Now, the PLM package in R gives the same results for the first-difference models:
library(plm) modelfd <- plm(lrent~lpop + lavginc + pctstu,
data=data,model = "fd")
No problem so far. However, the fixed effect reports different estimates.
modelfx <- plm(lrent~lpop + lavginc + pctstu, data=data, model =
"within", effect="time") summary(modelfx)
The FE results should not be any different. In fact, the Computer Exercise question is:
(iv) Estimate the model by fixed effects to verify that you get identical estimates and standard errors to those in part (iii).
My best guest is that I am miss understanding something on the R package.

Nested random effects in `lme {nlme}`

I have to fit an LMM with an interaction random effect but without the marginal random effect, using the lme command. That is, I want to fit the model in oats.lmer (see below) but using the function lme from the nlme package.
The code is
require("nlme")
require("lme4")
oats.lmer <- lmer(yield~nitro + (1|Block:Variety), data = Oats)
summary(oats.lmer)
#Linear mixed model fit by REML ['lmerMod']
#Formula: yield ~ nitro + (1 | Block:Variety)
# Data: Oats
#
#REML criterion at convergence: 598.1
#
#Scaled residuals:
# Min 1Q Median 3Q Max
#-1.66482 -0.72807 -0.00079 0.56416 1.85467
#
#Random effects:
# Groups Name Variance Std.Dev.
# Block:Variety (Intercept) 306.8 17.51
# Residual 165.6 12.87
#Number of obs: 72, groups: Block:Variety, 18
#
#Fixed effects:
# Estimate Std. Error t value
#(Intercept) 81.872 4.846 16.90
#nitro 73.667 6.781 10.86
#
#Correlation of Fixed Effects:
# (Intr)
#nitro -0.420
I started playing with this
oats.lme <- lme(yield~nitro, data = Oats, random = (~1|Block/Variety))
summary(oats.lme)
#Linear mixed-effects model fit by REML
# Data: Oats
# AIC BIC logLik
# 603.0418 614.2842 -296.5209
#
#Random effects:
# Formula: ~1 | Block
# (Intercept)
#StdDev: 14.50596
#
# Formula: ~1 | Variety %in% Block
# (Intercept) Residual
#StdDev: 11.00468 12.86696
#
#Fixed effects: yield ~ nitro
# Value Std.Error DF t-value p-value
#(Intercept) 81.87222 6.945273 53 11.78819 0
#nitro 73.66667 6.781483 53 10.86291 0
# Correlation:
# (Intr)
#nitro -0.293
#
#Standardized Within-Group Residuals:
# Min Q1 Med Q3 Max
#-1.74380770 -0.66475227 0.01710423 0.54298809 1.80298890
#
#Number of Observations: 72
#Number of Groups:
# Block Variety %in% Block
# 6 18
but the problem is that it puts also a marginal random effect for Variety which I want to omit.
The question is: how to specify the random effects in oats.lme such that oats.lme is identical (at least structurally) to oats.lmer ?
It can be as simple as following:
library(nlme)
data(Oats)
## construct an auxiliary factor `f` for interaction / nesting effect
Oats$f <- with(Oats, Block:Variety)
## use `random = ~ 1 | f`
lme(yield ~ nitro, data = Oats, random = ~ 1 | f)
#Linear mixed-effects model fit by REML
# Data: Oats
# Log-restricted-likelihood: -299.0328
# Fixed: yield ~ nitro
#(Intercept) nitro
# 81.87222 73.66667
#
#Random effects:
# Formula: ~1 | f
# (Intercept) Residual
#StdDev: 17.51489 12.86695
#
#Number of Observations: 72
#Number of Groups: 18

Unable to fit correct lme()

I would like to fit a mixed effect model that allows me to account for unequal variances across different geos. Specifically, I would like to predict response as a function of a fixed effect X with geo as the random effect.
Here are what the data look like:
X response geo
1 4 5.521461 other
2 4 5.164786 other
3 4 5.164786 other
4 6 3.401197 other
5 5 4.867534 other
6 4 5.010635 other
Unique values for the geo column:
[1] "other" "Atlanta-Sandy Springs-Marietta, GA" "Chicago-Naperville-Joliet, IL-IN-WI" "Dallas-Fort Worth-Arlington, TX"
[5] "Houston-Sugar Land-Baytown, TX" "Los Angeles-Long Beach-Santa Ana, CA" "Miami-Fort Lauderdale-Pompano Beach, FL" "Phoenix-Mesa-Glendale, AZ"
Here is the model that I've attempted:
> lme0 <- lme(response ~ factor(predictor) , random = ~1|factor(geo), data = HC_hired)
> summary(lme0)
Linear mixed-effects model fit by REML
Data: HC_hired
AIC BIC logLik
54770.69 54836.3 -27377.34
Random effects:
Formula: ~1 | factor(geo)
(Intercept) Residual
StdDev: 0.08689381 0.66802
Fixed effects: response ~ factor(predictor)
Value Std.Error DF t-value p-value
(Intercept) 4.255531 0.04410213 26918 96.49264 0.0000
factor(predictor)2 0.022986 0.03336742 26918 0.68889 0.4909
factor(predictor)3 0.166341 0.03221410 26918 5.16361 0.0000
factor(predictor)4 0.299172 0.03194177 26918 9.36618 0.0000
factor(predictor)5 0.378645 0.03249053 26918 11.65402 0.0000
factor(predictor)6 0.472583 0.03664732 26918 12.89543 0.0000
Correlation:
(Intr) fct()2 fct()3 fct()4 fct()5
factor(predictor)2 -0.660
factor(predictor)3 -0.683 0.903
factor(predictor)4 -0.689 0.912 0.945
factor(predictor)5 -0.679 0.897 0.930 0.940
factor(predictor)6 -0.603 0.795 0.824 0.832 0.819
Standardized Within-Group Residuals:
Min Q1 Med Q3 Max
-4.7047458 -0.3424262 0.1883132 0.7045260 2.1949313
Number of Observations: 26931
Number of Groups: 8
My issue is that the output does not specify a random effect for each level of geo. What is the correct model specification to do this? I've tried many permutations of the formula without luck. Any comments on the overall process are also welcome. Many thanks in advance!
RESPONSE TO COMMENT (coercing geo to factor does not change output):
HC_hired$geo <- as.factor(HC_hired$geo)
lme0 <- lme(response ~ factor(predictor) , random = ~1|factor(geo), data = HC_hired)
summary(lme0)

Resources