Print

Print


Hi all,
I wanted to let you know that over Christmas vacation I solved this problem.  
I bought Congdon's _Bayesian Statistical Modelling_ and applied the example 
code he had in Chapter 7, I think it was 7.1.  The main difference, it seems, 
was that all other MNL code I've seen uses y ~ dmulti, though Congdon's code 
uses y ~ dcat.  Another thing I like about Congdon's approach is that you 
don't have to modify data set from wide to tall, as with the other code I found.

Below is a working version, and below that is the original request.  Thank you 
all.

############################  Directory Paths  
############################
# Home
MyModelPath <- "c:/R/WinBUGS/"
# Work
#MyModelPath <- "c:/Documents and Settings/My Documents/WinBUGS/"
# Universal
MyBUGSPath <- "c:/Program Files/WinBUGS14/"
MyModelFile <- paste(MyModelPath, "model.bug", sep="")

######################  Randomly Create a Data Set  
#######################
y <- c(1:400); x02 <- c(1:400); x03 <- c(1:400)
y[1:100] <- 1
y[101:200] <- 2
y[201:300] <- 3
y[301:400] <- 4
x02[1:100] <-   rnorm(100, 25000, 2500)
x02[101:200] <- rnorm(100, 40000, 4000)
x02[201:300] <- rnorm(100, 35000, 3500)
x02[301:400] <- rnorm(100, 30000, 3000)
x03[1:100] <-   rnorm(100, 2.51, 0.25)
x03[101:200] <- rnorm(100, 2.01, 0.20)
x03[201:300] <- rnorm(100, 2.70, 0.27)
x03[301:400] <- rnorm(100, 1.66, 0.16)
MyData <- cbind(y, x02, x03)
MyData <- as.data.frame(MyData)
y.n <- NROW(y)
y.j <- length(unique(y))

###############  Center and Scale any Continuous Predictors  
##############
MyData$x02.c <- (MyData$x02 - mean(MyData$x02)) / (2 * sd(MyData$x02))
MyData$x03.c <- (MyData$x03 - mean(MyData$x03)) / (2 * sd(MyData$x03))

##################  Frequentist Multinomial Logit Model  
##################
library(nnet)
MyFMNL <- multinom(y ~ x02.c + x03.c, data=MyData)
MyFMNL
MyProbs <- predict(MyFMNL, type="probs")
MyData$FPROB_1 <- MyProbs[,1]
MyData$FPROB_2 <- MyProbs[,2]
MyData$FPROB_3 <- MyProbs[,3]
MyData$FPROB_4 <- MyProbs[,4]
MyData$F_YHAT <- predict(MyFMNL)
with(MyData, table(y, F_YHAT))

########################  Format Data for WinBUGS  
########################
MyBUGSData <- list(y=MyData$y, 
	x02=MyData$x02.c, x03=MyData$x03.c, 
	y.n=y.n, y.j=y.j)

##########################  WinBUGS Model File  
###########################
# This model code came from Congdon's BSM textbook (2006), example 7.2
library(R2WinBUGS)
model <- function()
{
### Likelihood Definition
for (i in 1:y.n)
	{
	### Random Component
	y[i] ~ dcat(p[i,1:y.j])
	### Deterministic Component and Link Function
	for (j in 1:y.j)
		{
		p[i,j]  <- phi[i,j] / sum(phi[i,])
		log(phi[i,j]) <- b[j,1] + b[j,2]*x02[i] + 
			b[j,3]*x03[i]
		}
	}
### Priors (form = b[j, n.var])
b[1,1] <- 0 #Reference category, set to zero
b[1,2] <- 0
b[1,3] <- 0
b[2,1] ~ dnorm(b.2.01.mu, b.2.01.tau)
b[2,2] ~ dnorm(b.2.02.mu, b.2.02.tau)
b[2,3] ~ dnorm(b.2.03.mu, b.2.03.tau)
b[3,1] ~ dnorm(b.3.01.mu, b.3.01.tau)
b[3,2] ~ dnorm(b.3.02.mu, b.3.02.tau)
b[3,3] ~ dnorm(b.3.03.mu, b.3.03.tau)
b[4,1] ~ dnorm(b.4.01.mu, b.4.01.tau)
b[4,2] ~ dnorm(b.4.02.mu, b.4.02.tau)
b[4,3] ~ dnorm(b.4.03.mu, b.4.03.tau)
### Hyperpriors
b.2.01.mu ~ dnorm(0.0, 1.0E-2)
b.2.02.mu ~ dnorm(0.0, 1.0E-2)
b.2.03.mu ~ dnorm(0.0, 1.0E-2)
b.3.01.mu ~ dnorm(0.0, 1.0E-2)
b.3.02.mu ~ dnorm(0.0, 1.0E-2)
b.3.03.mu ~ dnorm(0.0, 1.0E-2)
b.4.01.mu ~ dnorm(0.0, 1.0E-2)
b.4.02.mu ~ dnorm(0.0, 1.0E-2)
b.4.03.mu ~ dnorm(0.0, 1.0E-2)
b.2.01.tau <- pow(b.2.01.sigma, -2)
b.2.02.tau <- pow(b.2.02.sigma, -2)
b.2.03.tau <- pow(b.2.03.sigma, -2)
b.3.01.tau <- pow(b.3.01.sigma, -2)
b.3.02.tau <- pow(b.3.02.sigma, -2)
b.3.03.tau <- pow(b.3.03.sigma, -2)
b.4.01.tau <- pow(b.4.01.sigma, -2)
b.4.02.tau <- pow(b.4.02.sigma, -2)
b.4.03.tau <- pow(b.4.03.sigma, -2)
b.2.01.sigma ~ dunif(0, 100)
b.2.02.sigma ~ dunif(0, 100)
b.2.03.sigma ~ dunif(0, 100)
b.3.01.sigma ~ dunif(0, 100)
b.3.02.sigma ~ dunif(0, 100)
b.3.03.sigma ~ dunif(0, 100)
b.4.01.sigma ~ dunif(0, 100)
b.4.02.sigma ~ dunif(0, 100)
b.4.03.sigma ~ dunif(0, 100)
}
write.model(model, MyModelFile)
#file.show(MyModelFile)

#############################  WinBUGS Model  
#############################
system.time(
MyModel <- bugs(MyBUGSData, inits=NULL,
	model.file=MyModelFile, 
	parameters.to.save=c("b"), 
	n.chains=3, n.iter=2000, n.burnin=1000, n.thin=2, codaPkg=TRUE,
	bugs.directory = MyBUGSPath, working.directory=MyModelPath, 
debug=TRUE)
# Saved draws = ((n.iter - n.burnin) / n.thin) * n.chains
)
############################  MCMC Diagnostics  
###########################
library(coda)
MyHBMNL <- read.bugs(MyModel)
summary(MyHBMNL)
gelman.diag(MyHBMNL, transform=TRUE) #Increase iterations if not below 1.10
par(ask=TRUE); gelman.plot(MyHBMNL, ylim=c(1,1.2))
par(ask=TRUE); plot(MyHBMNL, density=FALSE)
par(ask=TRUE); plot(MyHBMNL, trace=FALSE, col="red")
par(ask=TRUE); autocorr.plot(MyHBMNL, col="red")
effectiveSize(MyHBMNL) #Autocorrelation effectively reduced draws to this
par(ask=TRUE); cumuplot(MyHBMNL, col="red") #Cumulative quantile plots

##########################  Posterior Data Set  
###########################
Chain1 <- MyHBMNL[[1]]; Chain1 <- as.data.frame(Chain1)
Chain2 <- MyHBMNL[[2]]; Chain2 <- as.data.frame(Chain2)
Chain3 <- MyHBMNL[[3]]; Chain3 <- as.data.frame(Chain3)
PosteriorDraws <- rbind(Chain1, Chain2, Chain3)
rm(Chain1, Chain2, Chain3)
#edit(PosteriorDraws)

##########################  Posterior Inference  
##########################
par(ask=TRUE); boxplot(PosteriorDraws[,1:9], col="red", xlab="Parameters", 
	ylab="Posterior Densities");	abline(h=0, col="blue")
mean(PosteriorDraws[,2] > 0)
mean(PosteriorDraws[,2] > PosteriorDraws[,3])

############################  Score Data Set  
#############################
b2_01 <- mean(PosteriorDraws[,1]); b2_02 <- mean(PosteriorDraws[,2])
b2_03 <- mean(PosteriorDraws[,3]); b3_01 <- mean(PosteriorDraws[,4])
b3_02 <- mean(PosteriorDraws[,5]); b3_03 <- mean(PosteriorDraws[,6])
b4_01 <- mean(PosteriorDraws[,7]); b4_02 <- mean(PosteriorDraws[,8])
b4_03 <- mean(PosteriorDraws[,9])
XB1 <- 0
XB2 <- (b2_01 + b2_02*MyData$x02.c + b2_03*MyData$x03.c)
XB3 <- (b3_01 + b3_02*MyData$x02.c + b3_03*MyData$x03.c)
XB4 <- (b4_01 + b4_02*MyData$x02.c + b4_03*MyData$x03.c)
MyData$phat1 <- (exp(XB1) / (exp(XB1) + exp(XB2) + exp(XB3) + exp(XB4)))
MyData$phat2 <- (exp(XB2) / (exp(XB1) + exp(XB2) + exp(XB3) + exp(XB4)))
MyData$phat3 <- (exp(XB3) / (exp(XB1) + exp(XB2) + exp(XB3) + exp(XB4)))
MyData$phat4 <- (exp(XB4) / (exp(XB1) + exp(XB2) + exp(XB3) + exp(XB4)))
rm(XB1, XB2, XB3, XB4)
MyData$yhat <- 1
MyData$yhat <- ifelse(MyData$phat2 > MyData$phat1 & 
	MyData$phat2 > MyData$phat3 & MyData$phat2 > MyData$phat4, 
	2, MyData$yhat)
MyData$yhat <- ifelse(MyData$phat3 > MyData$phat1 & 
	MyData$phat3 > MyData$phat2 & MyData$phat3 > MyData$phat4, 
	3, MyData$yhat)
MyData$yhat <- ifelse(MyData$phat4 > MyData$phat1 & 
	MyData$phat4 > MyData$phat2 & MyData$phat4 > MyData$phat3, 
	4, MyData$yhat)
Classification_Table <- with(MyData, table(y, yhat))
Pred_Accuracy <- 1:4
Pred_Accuracy[1] <- (Classification_Table[1,1] / 
	sum(Classification_Table[1,1:4]))
Pred_Accuracy[2] <- (Classification_Table[2,2] / 
	sum(Classification_Table[2,1:4]))
Pred_Accuracy[3] <- (Classification_Table[3,3] / 
	sum(Classification_Table[3,1:4]))
Pred_Accuracy[4] <- (Classification_Table[4,4] / 
	sum(Classification_Table[4,1:4]))
Pred_Accuracy_Total <- ((Classification_Table[1,1] 
	+ Classification_Table[2,2] + Classification_Table[3,3]
	+ Classification_Table[4,4])
	/ sum(Classification_Table))
Balanced_Lift <- (Pred_Accuracy_Total / 0.25) - 1
Classification_Table
Pred_Accuracy
Pred_Accuracy_Total
Balanced_Lift

>
> I am new to R, WinBUGS, and email lists, but ask for your help.  I am 
> using the R2WinBUGS package in R to use WinBUGS.  I am building small, 
> simple versions of models, trying to get them right, and then build in 
complexity, of course.
> I've had great success using WinBUGS to replicate a frequentist binary 
> logit model in R.  Now, I'm trying to do the same thing with a 
> multinomial logit, but my results are very different.  I am convinced 
> that the problem must be in the model specification.
>
> The data set is randomly generated (so I'm obviously just learning, 
> not trying to solve a real problem with it), and the continuous 
> predictors have been centered and scaled (techinically not 
> standardized) according to Gelman's
> (2007) book.
>
> Here is an example of how the WinBUGS MNL model is not predicting the 
> same as the frequentist MNL model from R:
>
> Frequentist MNL using multinom() in R
> Classification Table
>    yhat
> y    1  2  3
>   1 80  1 19
>   2  0 98  2
>   3 23  1 76
>
> WinBUGS MNL
> Classification Table
>
> PS: Although I am only using 3,000 iterations, the problem is the same 
> even with 50,000.
>
> Here is the entire code:
>
> ############################  Directory Paths 
> ############################ # Home MyModelPath <- 
> "c:/Compound/R/WinBUGS/"
> # Work
> MyModelPath <- "c:/Documents and Settings/My Documents/WinBUGS/"
> # Universal
> MyBUGSPath <- "c:/Program Files/WinBUGS14/"
> MyModelFile <- paste(MyModelPath, "model.bug", sep="")
>
> ######################  Randomly Create a Data Set 
> ####################### y <- c(1:300); x02 <- c(1:300); x03 <- 
> c(1:300); x04 <- c(1:300) y[1:100] <- 1 y[101:200] <- 2 y[201:300] <- 
> 3 x02[1:100] <- round(runif(100, 0, 1)) x02[101:200] <- 
> round(runif(100, 0.3, 1)) x02[201:300] <- round(runif(100, -0.5, 1)) 
> x03[1:100] <- rnorm(100,-40,10) x03[101:200] <- rnorm(100,10,10) 
> x03[201:300] <- rnorm(100,-30,10) x04[1:100] <- rnorm(100,0,2) 
> x04[101:200] <- rnorm(100,1,2) x04[201:300] <- rnorm(100,2,2) MyData 
> <- cbind(y, x02, x03, x04) MyData <- as.data.frame(MyData)
>
> ###############  Center and Scale any Continuous Predictors 
> ############## MyData$x03.c <- (MyData$x03 - mean
(MyData$x03)) / (2 * 
> sd(MyData$x03)) MyData$x04.c <- (MyData$x04 - mean(MyData$x04)) / (2 
* 
> sd(MyData$x04))
>
> ##################  Frequentist Multinomial Logit Model 
> ##################
> library(nnet)
> MyFMNL <- multinom(y ~ x02 + x03.c + x04.c
> 	, data=MyData)
> MyFMNL
> MyProbs <- predict(MyFMNL, type="probs")
> MyData$FPROB_1 <- MyProbs[,1]
> MyData$FPROB_2 <- MyProbs[,2]
> MyData$FPROB_3 <- MyProbs[,3]
> MyData$F_YHAT <- predict(MyFMNL)
> with(MyData, table(y, F_YHAT))
>
> #####################  Convert DV from Wide to Tall 
> ###################### y <- MyData$y y.new <- 
> as.numeric(as.vector(outer(sort(unique(y)), y, "=="))) y.k <- 
> length(unique(y)) #Num. of Categories of y y.n <- NROW(y)
>
> ######################  Format Data for WinBUGS 
> ########################## MyBUGSData <- 
> list(y=structure(.Data=y.new,.Dim=c(y.n,y.k)),
> 	x02=MyData$x02, x03=MyData$x03.c, x04=MyData$x04.c,
> 	numberofobservations=y.n, numberofchoices=y.k)
>
> ############  WinBUGS Bayesian Multinomial Logit Model File 
> ##############
> library(R2WinBUGS)
> model <- function()
> {
> ### Likelihood Definition
> for (i in 1:numberofobservations) 
> 	{
> 	### Random Component
> 	y[i, 1:numberofchoices] ~ dmulti(p[i, 1:numberofchoices], 1)
> 	### Deterministic Component and Link Function
> 	for (j in 1:numberofchoices)
> 		{
> 		p[i,j] <- phi[i,j] / sum(phi[i,])
> 		log(phi[i,j]) <- (b[j,1] + b[j,2]*x02[i] + b[j,3]*x03[i] + 
> 			b[j,4]*x04[i])
> 		}
> 	}
> ### Priors: (b[DVcat,ParamNum])
> # The first DV category is the reference category, and is set to zero.
> # Every other prior is assigned a normal distribution.
> b[1,1] <- 0
> b[2,1] ~ dnorm(0, .01)
> b[3,1] ~ dnorm(0, .01)
> b[1,2] <- 0
> b[2,2] ~ dnorm(0, .01)
> b[3,2] ~ dnorm(0, .01)
> b[1,3] <- 0
> b[2,3] ~ dnorm(0, .01)
> b[3,3] ~ dnorm(0, .01)
> b[1,4] <- 0
> b[2,4] ~ dnorm(0, .01)
> b[3,4] ~ dnorm(0, .01)
> }
> write.model(model, MyModelFile)
> #file.show(MyModelFile)
>
> #############################  WinBUGS Model 
> ############################# system.time( MyModel <- bugs
(MyBUGSData, 
> inits=NULL,
> 	model.file=MyModelFile, 
> 	parameters.to.save=c("b"), 
> 	n.chains=3, n.iter=3000, n.burnin=1500, n.thin=5, codaPkg=TRUE,
> 	bugs.directory = MyBUGSPath, working.directory=MyModelPath,
> debug=TRUE)
> # Saved draws = ((n.iter - n.burnin) / n.thin) * n.chains
> )
> ############################  MCMC Diagnostics 
> ###########################
> library(coda)
> MyHBMNL <- read.bugs(MyModel)
> summary(MyHBMNL)
> gelman.diag(MyHBMNL, transform=TRUE) #Increase iterations if not below 
> 1.10 par(ask=TRUE); gelman.plot(MyHBMNL, ylim=c(1,1.2)) par(ask=TRUE); 
> plot(MyHBMNL, density=FALSE) par(ask=TRUE); plot(MyHBMNL, 
trace=FALSE, 
> col="red") par(ask=TRUE); autocorr.plot(MyHBMNL, col="red")
> effectiveSize(MyHBMNL) #Autocorrelation effectively reduced draws to 
> this par(ask=TRUE); cumuplot(MyHBMNL, col="red") #Cumulative quantile 
> plots
>
> ##########################  Posterior Data Set 
> ###########################
> Chain1 <- MyHBMNL[[1]]; Chain1 <- as.data.frame(Chain1)
> Chain2 <- MyHBMNL[[2]]; Chain2 <- as.data.frame(Chain2)
> Chain3 <- MyHBMNL[[3]]; Chain3 <- as.data.frame(Chain3) PosteriorDraws 
> <- rbind(Chain1, Chain2, Chain3) rm(Chain1, Chain2, Chain3)
> #edit(PosteriorDraws)
>
> ##########################  Posterior Inference 
> ########################## par(ask=TRUE); 
> boxplot(PosteriorDraws[,1:8], col="red", xlab="Parameters",
> 	ylab="Posterior Densities");	abline(h=0, col="blue")
> mean(PosteriorDraws[,2] > 0)
> mean(PosteriorDraws[,2] > PosteriorDraws[,3])
>
> ############################  Score Data Set 
> #############################
> b02_1 <- mean(PosteriorDraws[,1]); b02_2 <- mean(PosteriorDraws[,2])
> b02_3 <- mean(PosteriorDraws[,3]); b02_4 <- mean(PosteriorDraws[,4])
> b03_1 <- mean(PosteriorDraws[,5]); b03_2 <- mean(PosteriorDraws[,6])
> b03_3 <- mean(PosteriorDraws[,7]); b03_4 <- mean(PosteriorDraws[,8])
> MyData$phat1 <- (exp(0) / (exp(0) + 
> 	exp(b02_1 + b02_2*MyData$x02 + b02_3*MyData$x03.c + 
> 		b02_4*MyData$x04.c) + 
> 	exp(b03_1 + b03_2*MyData$x02 + b03_3*MyData$x03.c + 
> 		b03_4*MyData$x04.c)))
> MyData$phat2 <- (exp(b02_1 + b02_2*MyData$x02 + b02_3*MyData$x03.c 
+ 
> 		b02_4*MyData$x04.c) / (exp(0) + 
> 	exp(b02_1 + b02_2*MyData$x02 + b02_3*MyData$x03.c + 
> 		b02_4*MyData$x04.c) + 
> 	exp(b03_1 + b03_2*MyData$x02 + b03_3*MyData$x03.c + 
> 		b03_4*MyData$x04.c)))
> MyData$phat3 <- (exp(b03_1 + b03_2*MyData$x02 + b03_3*MyData$x03.c 
+ 
> 		b03_4*MyData$x04.c) / (exp(0) + 
> 	exp(b02_1 + b02_2*MyData$x02 + b02_3*MyData$x03.c + 
> 		b02_4*MyData$x04.c) + 
> 	exp(b03_1 + b03_2*MyData$x02 + b03_3*MyData$x03.c + 
> 		b03_4*MyData$x04.c)))
> MyData$yhat <- 1
> MyData$yhat <- ifelse(MyData$phat2 > MyData$phat1 & 
> 	MyData$phat2 > MyData$phat3, 2, MyData$yhat) MyData$yhat <- 
> ifelse(MyData$phat3 > MyData$phat1 &
> 	MyData$phat3 > MyData$phat2, 3, MyData$yhat) 
Classification_Table <- 
> with(MyData, table(y, yhat)) Pred_Accuracy <- 1:3 Pred_Accuracy[1] <- 
> (Classification_Table[1,1] /
> 	sum(Classification_Table[1,1:3]))
> Pred_Accuracy[2] <- (Classification_Table[2,2] / 
> 	sum(Classification_Table[2,1:3]))
> Pred_Accuracy[3] <- (Classification_Table[3,3] / 
> 	sum(Classification_Table[3,1:3]))
> Pred_Accuracy_Total <- ((Classification_Table[1,1] 
> 	+ Classification_Table[2,2] + Classification_Table[3,3])
> 	/ sum(Classification_Table))
> Balanced_Lift <- (Pred_Accuracy_Total / 0.33) - 1 Classification_Table 
> Pred_Accuracy Pred_Accuracy_Total Balanced_Lift
>
> # End
>
> Any thoughts are appreciated.  Thanks.

-------------------------------------------------------------------
This list is for discussion of modelling issues and the BUGS software.
For help with crashes and error messages, first mail [log in to unmask]
To mail the BUGS list, mail to [log in to unmask]
Before mailing, please check the archive at www.jiscmail.ac.uk/lists/bugs.html
Please do not mail attachments to the list.
To leave the BUGS list, send LEAVE BUGS to [log in to unmask]
If this fails, mail [log in to unmask], NOT the whole list