STA313 F 2004 Handout 3
Numerical MLE for the Multivariate normal with mvnLL
First, illustrate some commands.
> Ymat[1:10,] # First 10 rows of Ymat
y1 y2
[1,] 0.46950842 0.6999623
[2,] 0.75046599 0.3073191
[3,] -0.03310517 1.6231372
[4,] 1.95780725 3.3519020
[5,] 0.68899300 5.1409713
[6,] 2.95751217 2.9669962
[7,] 1.79292404 -0.5733391
[8,] -0.51203666 -0.4667499
[9,] -1.40452153 -1.9487259
[10,] -2.41753657 0.1730442
> dim(Ymat)
[1] 200 2
> Sigma
y1 y2
y1 1.8429904 0.8355763
y2 0.8355763 1.8324584
>
> siginv <- solve(Sigma) ; siginv
[,1] [,2]
[1,] 0.6840044 -0.3118968
[2,] -0.3118968 0.6879357
> Ymat[1,]
y1 y2
0.4695084 0.6999623
>
> Ymat[1,]%*%siginv
[,1] [,2]
[1,] 0.1028298 0.3350909
>
> Ymat[1,]%*%siginv%*%cbind(Ymat[1,])
[,1]
[1,] 0.2828305
>
> mean(Ymat[,1]) # Mean of col 1
[1] 1.096919
>
> apply(Ymat,2,mean)
y1 y2
1.096919 2.069276
>
> nn <- dim(Ymat)[1] ; nn
[1] 200
Here is the function definition. It's in the file mvnLL.R.
# mvnLL.R : Defines the function mvLL
# source("mvnLL.R"), probably in a program defining another function.
#
mvnLL <- function(Sigma,Ymat,check=T,centered=F)
# -2 LL for a multivariate normal: Function of the covariance matrix
{
p <- dim(Ymat)[2]
if(check)
{
p1 <- dim(Sigma)[1] ; p2 <- dim(Sigma)[2]
if(p1 != p2)
{cat(" Sigma = \n")
print(Sigma)
stop("Sigma must be square!")
}
if(p1 != p) stop("Num cols of Y must = num cols of Sigma.")
} # End checking of input
deter <- det(Sigma)
# If determinant is neg or very near zero, return +Infinity
if(deter < 4e-16) mvnLL <- Inf else
{
siginv <- solve(Sigma)
nn <- dim(Ymat)[1]
const <- nn*p*log(2*3.1415926)
sumq <- 0 # Initializing sum of quadratic forms.
for(i in 1:nn) sumq <- sumq +
as.numeric( Ymat[i,]%*%siginv%*%cbind(Ymat[i,]) )
if(! centered)
{
ybar <- cbind(apply(Ymat,2,mean)) # Y-bar is a column vector
sumq <- sumq - nn*t(ybar)%*%siginv%*%ybar
}
mvnLL <- as.numeric( nn*log(deter) + const + sumq ) # Make it a number
} # End if the determinant is okay
mvnLL
} # End of function mvnLL
Need to wrap mvnLL up in another function to minimize.
# simplecov.R
simplecov <- function(theta,datta) # For a 2x2
{
sig11 <- theta[1] ; sig12 <- theta[2] ; sig22 <- theta[3]
covmat <- rbind( c(sig11,sig12),
c(sig12,sig22) )
simplecov <- mvnLL(covmat,datta)
simplecov
} # End of simplecov
Test the functions.
> # Illustrate MLE with mvnLL
> # Simulate some data
> n <- 200 ; set.seed(9999)
> f1 <- rnorm(n,1,1) ; f2 <- rnorm(n,2,1) ; e <- rnorm(n)
> x1 <- f1+e ; x2 <- f2+e ; XX <- cbind(x1,x2)
> # Define the functions
> source("mvnLL.R") ; source("simplecov.R")
> out1 <- nlm(simplecov,c(1,0,1),datta=XX)[1:2] ; out1
Warning messages:
1: NA/Inf replaced by maximum positive value
2: NA/Inf replaced by maximum positive value
3: NA/Inf replaced by maximum positive value
$minimum
[1] 1330.040
$estimate
[1] 2.003452 1.088755 1.914238
> sig11 <- out1$estimate[1] ; sig12 <- out1$estimate[2]
> sig22 <- out1$estimate[3]
> Sigmahat <- rbind(c(sig11,sig12),
+ c(sig12,sig22))
> Sigmahat # Numerical MLE
[,1] [,2]
[1,] 2.003452 1.088755
[2,] 1.088755 1.914238
> Sighat <- (n-1)/n * var(XX)
> Sighat # Theoretical MLE
x1 x2
x1 2.003457 1.088759
x2 1.088759 1.914241
> #
> out1$minimum # Minimum value of -2LL from numerical search
[1] 1330.040
> # Now evaluate (simplified) -2LL at the the Theoretical MLE
> p <- 2 ; n*p*(1+log(2*3.14159)) + n*log(det(Sighat))
[1] 1330.04
> #
> # Now try some different starting values
> #
> testme1 <- nlm(simplecov,c(2,1,2),datta=XX)[1:2] ; testme1
Warning messages:
1: NA/Inf replaced by maximum positive value
2: NA/Inf replaced by maximum positive value
$minimum
[1] 1330.040
$estimate
[1] 2.003469 1.088770 1.914252
> testme2 <- nlm(simplecov,c(6,0,23),datta=XX)[1:2] ; testme2
There were 14 warnings (use warnings() to see them)
$minimum
[1] 1330.040
$estimate
[1] 2.003453 1.088756 1.914237
> testme3 <- nlm(simplecov,c(-1,0,3),datta=XX)[1:2] ; testme3
Warning messages:
1: NA/Inf replaced by maximum positive value
2: NA/Inf replaced by maximum positive value
3: NA/Inf replaced by maximum positive value
4: NA/Inf replaced by maximum positive value
$minimum
[1] 1.797693e+308
$estimate
[1] -1 0 3
> #
> # Starting at the identity matrix seems like a good practice for now.
> #
>