Mk model

What it does. The Mk model (named for Markov-k states) describes the evolution of a discrete character on a phylogeny as a continuous-time Markov chain. At its simplest, it has two states and one or two rate parameters: the equal-rates (ER) version assumes all transitions have the same rate; the all-rates-different (ARD) version gives each ordered pair of states its own rate. The model is fit by maximizing the likelihood of the observed tip states given the tree, branch lengths, and rate matrix Q. The ape::ace function provides ML estimates for simple models; corHMM extends Mk to hidden-rate classes and ordered models.

When to use it.

When NOT to use it.

Worked example

library(ape)
library(corHMM)

# tree: ape phylo object (ultrametric preferred)
# x: named character vector of states ("XY", "XO") with names = tip labels

# ---- Option A: ape::ace — fast, 2-state ER or ARD ----

# Equal-rates model
fit.er <- ace(x, tree, type = "discrete", model = "ER")
fit.er$rates        # single q
fit.er$lik.anc      # matrix: nodes x states, marginal probabilities

# All-rates-different model
fit.ard <- ace(x, tree, type = "discrete", model = "ARD")
fit.ard$rates       # q01 and q10

# Likelihood-ratio test: ER vs ARD
LRT_stat <- 2 * (fit.ard$loglik - fit.er$loglik)
pchisq(LRT_stat, df = 1, lower.tail = FALSE)

# ---- Option B: corHMM — hidden rates, ordered models ----

# Build rate category matrix (1 = observed state A, 2 = observed state B)
rate_mat <- getStateMat4Dat(data.frame(sp = names(x), state = x))$rate.mat

# Fit a two-rate-class hidden Markov model
fit.hmm <- corHMM(phy = tree,
                  data = data.frame(sp = names(x), state = x),
                  rate.cat = 2,           # 2 hidden rate classes
                  rate.mat = rate_mat,
                  node.states = "marginal")
fit.hmm$loglik
fit.hmm$solution   # rate matrix with hidden states

# Compare 1-class (standard Mk) to 2-class (hidden rates)
fit.mk  <- corHMM(phy = tree,
                  data = data.frame(sp = names(x), state = x),
                  rate.cat = 1,
                  rate.mat = rate_mat,
                  node.states = "marginal")
# AIC comparison
AIC(fit.mk)
AIC(fit.hmm)

Gotchas we’ve hit

Key papers that use this method in the lab

Question copied. Paste it into the NotebookLM tab.