I will use bond data from Chapter2 of Littell et al. (2006) as a example.

#Load Packages

library(lme4)
## Loading required package: Matrix
## 
## Attaching package: 'Matrix'
## The following objects are masked from 'package:tidyr':
## 
##     expand, pack, unpack
library(optimization)
## Loading required package: Rcpp

1 Create Dataframe df.bond

df.bond <- data.frame(ingot = rep(1:7,each = 3),
                      metal = rep(c("n","i","c"),7),
                      pres = c(67,71.9,72.2,
                               67.5,68.8,66.4,
                               76,82.6,74.5,
                               72.7,78.1,67.3,
                               73.1,74.2,73.2,
                               65.8,70.8,68.7,
                               75.6,84.9,69))
df.bond$ingot <- factor(df.bond$ingot)
df.bond
##    ingot metal pres
## 1      1     n 67.0
## 2      1     i 71.9
## 3      1     c 72.2
## 4      2     n 67.5
## 5      2     i 68.8
## 6      2     c 66.4
## 7      3     n 76.0
## 8      3     i 82.6
## 9      3     c 74.5
## 10     4     n 72.7
## 11     4     i 78.1
## 12     4     c 67.3
## 13     5     n 73.1
## 14     5     i 74.2
## 15     5     c 73.2
## 16     6     n 65.8
## 17     6     i 70.8
## 18     6     c 68.7
## 19     7     n 75.6
## 20     7     i 84.9
## 21     7     c 69.0

2 Linear mixed model by maximum likelihood estimation

First we build linear mixed model by lme4 package with MLE method. Then we compare the parameter estimations by using equations from Some important proof of Mixed Model Equations and REML via optimization package.

lmm.bond <- lmer( pres ~ metal + (1|ingot),REML = FALSE,data = df.bond)
summary(lmm.bond)
## Linear mixed model fit by maximum likelihood  ['lmerMod']
## Formula: pres ~ metal + (1 | ingot)
##    Data: df.bond
## 
##      AIC      BIC   logLik deviance df.resid 
##    125.7    130.9    -57.9    115.7       16 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -1.45505 -0.81901  0.08048  0.52228  1.96114 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  ingot    (Intercept) 9.812    3.132   
##  Residual             8.890    2.982   
## Number of obs: 21, groups:  ingot, 7
## 
## Fixed effects:
##             Estimate Std. Error t value
## (Intercept)  70.1857     1.6346  42.939
## metali        5.7143     1.5937   3.585
## metaln        0.9143     1.5937   0.574
## 
## Correlation of Fixed Effects:
##        (Intr) metali
## metali -0.488       
## metaln -0.488  0.500
anova(lmm.bond)
## Analysis of Variance Table
##       npar Sum Sq Mean Sq F value
## metal    2  131.9   65.95  7.4186

For linear mixed model

\[\begin{equation} \boldsymbol{Y} = \boldsymbol{X\beta} + \boldsymbol{Zu} + \boldsymbol{e} \end{equation}\]

\[\begin{equation} \begin{pmatrix} \boldsymbol{u}\\ \boldsymbol{e} \end{pmatrix} \sim \mathcal{N} \begin{pmatrix} \begin{pmatrix} \boldsymbol{0}\\ \boldsymbol{0} \end{pmatrix}, \begin{pmatrix} \boldsymbol{G} & \boldsymbol{0}\\ \boldsymbol{0} & \boldsymbol{R} \end{pmatrix} \end{pmatrix} \end{equation}\]

Design matrix \(\boldsymbol{X}\) is

matrix.x <- model.matrix(lmm.bond)
matrix.x
##    (Intercept) metali metaln
## 1            1      0      1
## 2            1      1      0
## 3            1      0      0
## 4            1      0      1
## 5            1      1      0
## 6            1      0      0
## 7            1      0      1
## 8            1      1      0
## 9            1      0      0
## 10           1      0      1
## 11           1      1      0
## 12           1      0      0
## 13           1      0      1
## 14           1      1      0
## 15           1      0      0
## 16           1      0      1
## 17           1      1      0
## 18           1      0      0
## 19           1      0      1
## 20           1      1      0
## 21           1      0      0
## attr(,"assign")
## [1] 0 1 1
## attr(,"contrasts")
## attr(,"contrasts")$metal
## [1] "contr.treatment"
## 
## attr(,"msgScaleX")
## character(0)

Design matrix \(\boldsymbol{Z}\) is

df.z <- read.csv("files/Z.csv", header = FALSE)
matrix.z <- as.matrix(df.z)
colnames(matrix.z) <- paste0("ingot:",1:7)
matrix.z
##       ingot:1 ingot:2 ingot:3 ingot:4 ingot:5 ingot:6 ingot:7
##  [1,]       1       0       0       0       0       0       0
##  [2,]       1       0       0       0       0       0       0
##  [3,]       1       0       0       0       0       0       0
##  [4,]       0       1       0       0       0       0       0
##  [5,]       0       1       0       0       0       0       0
##  [6,]       0       1       0       0       0       0       0
##  [7,]       0       0       1       0       0       0       0
##  [8,]       0       0       1       0       0       0       0
##  [9,]       0       0       1       0       0       0       0
## [10,]       0       0       0       1       0       0       0
## [11,]       0       0       0       1       0       0       0
## [12,]       0       0       0       1       0       0       0
## [13,]       0       0       0       0       1       0       0
## [14,]       0       0       0       0       1       0       0
## [15,]       0       0       0       0       1       0       0
## [16,]       0       0       0       0       0       1       0
## [17,]       0       0       0       0       0       1       0
## [18,]       0       0       0       0       0       1       0
## [19,]       0       0       0       0       0       0       1
## [20,]       0       0       0       0       0       0       1
## [21,]       0       0       0       0       0       0       1

Define matrix \(\boldsymbol{G}\) as

\[\boldsymbol{G}_{7 \times 7} = \boldsymbol{I} \sigma^2_{\text{ingot}}\]

Define matrix \(\boldsymbol{R}\) as

\[\boldsymbol{R}_{21 \times 21} = \boldsymbol{I} \sigma^2_{\text{residual}}\]

Use equation(4.9) and equation (6.1) from Some important proof of Mixed Model Equations and REML

\[\begin{equation} \tilde{\boldsymbol{\beta}} = (\boldsymbol{X}^T \boldsymbol{V}^{-1} \boldsymbol{X})^{-1} \boldsymbol{X}^T \boldsymbol{V}^{-1} \boldsymbol{Y} \tag{4.9} \end{equation}\]

\[\begin{equation} -2\ell(\boldsymbol{\theta};\boldsymbol{Y}) = \text{log}|\tilde{\boldsymbol{V}}(\boldsymbol{\theta})| + (\boldsymbol{Y}-\boldsymbol{X}\tilde{\boldsymbol{\beta}}(\boldsymbol{\theta}))^T \tilde{\boldsymbol{V}}(\boldsymbol{\theta})^{-1} (\boldsymbol{Y}-\boldsymbol{X}\tilde{\boldsymbol{\beta}}(\boldsymbol{\theta})) \tag{6.1} \end{equation}\]

Estimation of covariance parameters

loglikef <- function(x) {
  vector.Y <- as.vector(df.bond$pres)
  matrix.G <- x[1] * diag(1,nrow = 7)
  matrix.R <- x[2] * diag(1,nrow = 21)
  matrix.V <- matrix.z %*% matrix.G %*% t(matrix.z) + matrix.R
  vector.Beta <- solve(t(matrix.x) %*% solve(matrix.V) %*% matrix.x) %*% t(matrix.x) %*% solve(matrix.V) %*% vector.Y
  loglike <- log(det(matrix.V)) + t(vector.Y - matrix.x %*% vector.Beta) %*% solve(matrix.V) %*% (vector.Y - matrix.x %*% vector.Beta)
  return(c(loglike))
}

optim_nm(fun = loglikef, k = 2, start = c(1,1),maximum= FALSE, tol = 0.0000000000001)$par
##                   
## 9.812383 8.889932
hat.cov.para <- optim_nm(fun = loglikef, k = 2, start = c(1,1),maximum= FALSE, tol = 0.0000000000001)$par

We have that

\[\sigma^2_{\text{ingot}} = 9.812383 \text{ and } \sigma^2_{\text{residual}} = 8.889932\] This is identical to estimations from lme4.

Then estimate fix effect \(\boldsymbol{\beta}\)

hat.beta <- function(x) {
  vector.Y <- as.vector(df.bond$pres)
  matrix.G <- x[1] * diag(1,nrow = 7)
  matrix.R <- x[2] * diag(1,nrow = 21)
  matrix.V <- matrix.z %*% matrix.G %*% t(matrix.z) + matrix.R
  vector.Beta <- solve(t(matrix.x) %*% solve(matrix.V) %*% matrix.x) %*% t(matrix.x) %*% solve(matrix.V) %*% vector.Y
  return(vector.Beta)
}
round(hat.beta(x = hat.cov.para),4)
##                [,1]
## (Intercept) 70.1857
## metali       5.7143
## metaln       0.9143

We have that \[\boldsymbol{\beta} = \begin{bmatrix} \beta_0\\ \beta_1\\ \beta_2 \end{bmatrix} = \begin{bmatrix} 70.1857\\ 5.7143\\ 0.9143 \end{bmatrix}\]

Again, this is identical to estimations from lme4.

3 Linear mixed model by REML

Same as section 3, firstly we build linear mixed model by lme4 package with REML option. Then we compare โ€˜handโ€™ calculated estimations with estimations from lme4.

relmm.bond <- lmer( pres ~ metal + (1|ingot),REML = TRUE,data = df.bond)
summary(relmm.bond)
## Linear mixed model fit by REML ['lmerMod']
## Formula: pres ~ metal + (1 | ingot)
##    Data: df.bond
## 
## REML criterion at convergence: 107.8
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -1.34712 -0.75825  0.07451  0.48354  1.81566 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  ingot    (Intercept) 11.45    3.383   
##  Residual             10.37    3.220   
## Number of obs: 21, groups:  ingot, 7
## 
## Fixed effects:
##             Estimate Std. Error t value
## (Intercept)  70.1857     1.7655  39.754
## metali        5.7143     1.7214   3.320
## metaln        0.9143     1.7214   0.531
## 
## Correlation of Fixed Effects:
##        (Intr) metali
## metali -0.488       
## metaln -0.488  0.500

Using equation(7.3) from Some important proof of Mixed Model Equations and REML

\[\begin{equation} -2\ell_{REML}(\boldsymbol{\theta};\boldsymbol{Y}) = \text{log} |\tilde{\boldsymbol{V}}(\boldsymbol{\theta})| + \text{log} |\boldsymbol{X}^T \tilde{\boldsymbol{V}}^{-1} \boldsymbol{X}| + (\boldsymbol{Y} - \boldsymbol{X}\tilde{\boldsymbol{\beta}}(\boldsymbol{\theta}))^T \tilde{\boldsymbol{V}}^{-1} (\boldsymbol{Y} - \boldsymbol{X}\tilde{\boldsymbol{\beta}}(\boldsymbol{\theta})) \tag{7.3} \end{equation}\]

reloglikef <- function(x) {
  vector.Y <- as.vector(df.bond$pres)
  matrix.G <- x[1] * diag(1,nrow = 7)
  matrix.R <- x[2] * diag(1,nrow = 21)
  matrix.V <- matrix.z %*% matrix.G %*% t(matrix.z) + matrix.R
  vector.Beta <- solve(t(matrix.x) %*% solve(matrix.V) %*% matrix.x) %*% t(matrix.x) %*% solve(matrix.V) %*% vector.Y
  loglike <- log(det(matrix.V)) + log(det(t(matrix.x) %*% solve(matrix.V) %*% matrix.x)) + t(vector.Y - matrix.x %*% vector.Beta) %*% solve(matrix.V) %*% (vector.Y - matrix.x %*% vector.Beta)
  return(c(loglike))
}

optim_nm(fun = reloglikef, k = 2, start = c(5,6),maximum= FALSE, tol = 0.0000000000001)$par
##                   
## 11.44778 10.37159

Again, parameter estimations are close enough.

References

Littell et al. (2006)

Littell, Ramon C., George A. Milliken, Walter W. Stroup, Russell D. Wolfinger, and Schabenberber Oliver. 2006. SAS for Mixed Models, Second Edition. SAS Publishing.