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. > # >