Multinomial Logit

mnlogit <- function(data, formula) {
  
  mf <- model.frame(formula, data, na.action=na.exclude)
  y <- model.response(mf)
  X <- model.matrix(formula, mf)
  
  N <- nrow(X)
  K <- ncol(X)
  levels <- unique(y) |> sort()
  M <- length(levels)
  
  Y <- matrix(N*M, nrow=N, ncol=M)
  for (m in 1:M) {
    Y[,m] <- ifelse(y==levels[m], 1, 0)
  }
  b <- numeric(K*(M-1))
  
  mnlogitLL <- function(param) {
    
    b <- matrix(param, nrow=K, ncol=M-1)
    Xb <- cbind(rep(0, N), X %*% b)
    lli <- numeric(N)
    
    for (m in 1:M) {
      lli <- lli + Y[,m]*Xb[,m] - Y[,m]*log(rowSums(exp(Xb)))
    }
    
    return(-sum(lli))
    
  }
  
  out <- optim(b, mnlogitLL, method="BFGS")
  est <- matrix(out$par, nrow=K, ncol=M-1)
  rownames(est) <- colnames(X)
  colnames(est) <- paste0(levels[1], "/", levels[2:M])
  
  return(est)
  
}

Testing the function:

library(mclogit)
## Loading required package: Matrix
housing <- MASS::housing #has an ordinal outcome but we'll ignore that for our purposes
f <- Sat ~ Infl + Freq + Type

t(mblogit(f, data = housing)$coefmat)
## 
## Iteration 1 - deviance = 150.7444 - criterion = 0.5116897
## Iteration 2 - deviance = 150.511 - criterion = 0.001549817
## Iteration 3 - deviance = 150.5107 - criterion = 1.965799e-06
## Iteration 4 - deviance = 150.5107 - criterion = 3.804011e-12
## converged
##                Response categories
## Predictors          Medium         High
##   (Intercept)    1.1352190 -0.740346318
##   InflMedium     0.1291512  0.005033149
##   InflHigh      -0.4256812  0.282489556
##   Freq          -0.0501481  0.026990219
##   TypeApartment  0.8092387 -0.644372087
##   TypeAtrium    -0.4053420  0.264568900
##   TypeTerrace   -0.3689781  0.189799430
mnlogit(housing, f)
##                Low/Medium     Low/High
## (Intercept)    1.13582927 -0.740243313
## InflMedium     0.12920635  0.005028019
## InflHigh      -0.42591879  0.282447109
## Freq          -0.05017388  0.026985033
## TypeApartment  0.80963960 -0.644298089
## TypeAtrium    -0.40569533  0.264391915
## TypeTerrace   -0.36904115  0.189905490