6  EM Algorithms

Author

Longhai Li

Published

September 26, 2026

6.1 Overview of EM

6.1.1 Setup and motivation

Let \(Y\) denote the observed data and \(\theta\) the parameter, with likelihood \(L(\theta) = P(Y \mid \theta)\). In many models this quantity is itself an integral (or sum) over latent or missing data \(Z\):

\[ P(Y \mid \theta) = \int P(Y, Z \mid \theta) \, dZ . \]

The integral is what makes direct maximization awkward: it destroys the product structure that would otherwise make the log-likelihood a sum of simple terms. The EM algorithm avoids it by working with the complete-data likelihood, which retains that structure, and correcting for the fact that \(Z\) is unobserved.

Table 6.1: Fixes the notation for the observed-data and complete-data likelihoods used throughout the chapter. Observed and complete likelihoods
Likelihood Log-likelihood
Observed \(L_{\text{obs}}(\theta) = P(Y \mid \theta)\) \(\ell_{\text{obs}}(\theta) = \log P(Y \mid \theta)\)
Complete \(L_{\text{comp}}(\theta) = P(Y, Z \mid \theta)\) \(\ell_{\text{comp}}(\theta; Y, Z) = \log P(Y, Z \mid \theta)\)

6.1.2 The algorithm

Start from \(\hat\theta^{(0)}\). For \(t = 0, 1, 2, \ldots\):

E-step. Replace \(\ell_{\text{obs}}(\theta)\) by the expected complete log-likelihood,

\[ Q\!\left(\theta \mid \hat\theta^{(t)}\right) = E_{Z \mid Y, \hat\theta^{(t)}}\!\left[\ell_{\text{comp}}(\theta; Y, Z)\right]. \]

M-step. Maximize it,

\[ \hat\theta^{(t+1)} = \arg\max_{\theta} \; Q\!\left(\theta \mid \hat\theta^{(t)}\right). \]

Iterate until \(\hat\theta^{(t)}\) converges.

WarningA common misreading

\(Q\) is an average of \(\ell_{\text{comp}}(\theta; Y, Z)\) over \(P(Z \mid Y, \hat\theta^{(t)})\). It is not \(\ell_{\text{comp}}\!\left(\theta; Y, E(Z \mid Y, \hat\theta^{(t)})\right)\) — that is, EM is not “fill in the missing values with their expectations and maximize”. The two coincide only when \(\ell_{\text{comp}}\) happens to be linear in \(Z\), which is true in both examples of this chapter and false in general.

6.1.3 \(Q\) as an average of complete log-likelihoods

Fix \(\hat\theta^{(t)}\). Each draw \(Z^{(s)} \sim P(Z \mid Y, \hat\theta^{(t)})\) gives one curve \(\ell_{\text{comp}}(\theta; Y, Z^{(s)})\), and \(Q(\theta \mid \hat\theta^{(t)})\) is their expectation. The figure uses the censored Poisson model of Section 6.3 with \(\lambda^{(t)} = 1.5\).

Code
lt <- 1.5; S <- 10
Z <- replicate(S, rbinom(ncen_d, 1, lt / (1 + lt)))
curves <- sapply(1:S, function(s) sapply(lam, lcomp, z = Z[, s]))
Qexact <- sapply(lam, Qfun, lt = lt)
par(mar = c(4, 4, 1, 1))
matplot(lam, curves, type = "l", lty = 1, lwd = 1, col = "gray60",
        xlab = expression(theta), ylab = "log-likelihood",
        ylim = range(curves) + c(0, 2))
lines(lam, rowMeans(curves), lwd = 3, col = "firebrick")
lines(lam, Qexact, lwd = 3, col = "black", lty = 2)
abline(v = lt, lty = 3)
legend("bottomright", bty = "n", lwd = c(1, 3, 3), lty = c(1, 1, 2),
       col = c("gray60", "firebrick", "black"),
       legend = c(expression(l[comp](theta*";"*Y*","*Z^(s)) ~ "for 10 draws"),
                  "average of the 10 curves",
                  expression(Q(theta*"|"*hat(theta)^(t)) ~ "(exact expectation)")))
Figure 6.1: Illustrates the \(Q\) function of the EM algorithm as the expectation of the complete-data log-likelihood over the unobserved data, approximated here by averaging simulated completions. Ten complete-data log-likelihood curves, their average, and the exact \(Q\) function.

6.1.4 \(Q\) functions as tangent lower bounds

The geometric picture that explains why EM works: each \(Q(\cdot \mid \hat\theta^{(t)})\), shifted by a constant, lies below \(\ell_{\text{obs}}\) and touches it at \(\hat\theta^{(t)}\). Maximizing the bound therefore moves uphill on \(\ell_{\text{obs}}\) itself.

Code
lo <- sapply(lam, lobs); top <- max(lo)
par(mar = c(4, 4, 1, 1))
plot(lam, lo, type = "l", lwd = 3, xlab = expression(theta),
     ylab = "log-likelihood", ylim = c(top - 16, top + 2.5))
lt <- 0.5; cols <- c("firebrick", "darkorange", "forestgreen")
for (k in 1:3) {
  shift <- lobs(lt) - Qfun(lt, lt)            # make Q touch l_obs at theta^(t)
  lines(lam, sapply(lam, Qfun, lt = lt) + shift, col = cols[k], lwd = 2, lty = 2)
  points(lt, lobs(lt), pch = 19, col = cols[k])
  lt_new <- (sum(yobs_d) + ncen_d * lt / (1 + lt)) / n_d     # M-step
  segments(lt_new, top - 16, lt_new, lobs(lt_new), col = cols[k], lty = 3)
  text(lt, lobs(lt), bquote(hat(theta)^(.(k - 1))), pos = 3, col = cols[k], xpd = NA)
  lt <- lt_new
}
legend("bottomright", bty = "n", lwd = c(3, 2), lty = c(1, 2),
       legend = c(expression(l[obs](theta)),
                  expression(Q(theta*"|"*hat(theta)^(t)) + "const")))
Figure 6.2: Illustrates why EM increases the likelihood: each iteration maximizes a lower bound that touches the observed log-likelihood at the current estimate. Three EM iterations viewed as successive tangent minorants of the observed log-likelihood.

6.1.5 The ascending property

Write \(h(Y, Z \mid \theta) = P(Y, Z \mid \theta)\), \(g(Y \mid \theta) = \int h(Y, Z \mid \theta) \, dZ\), and \(K(Z \mid Y, \theta) = h / g\).

NoteTheorem

\(\ell_{\text{obs}}\!\left(\hat\theta^{(t+1)}\right) \ \ge\ \ell_{\text{obs}}\!\left(\hat\theta^{(t)}\right)\) at every iteration.

Key identity. Since \(\log g(Y \mid \theta) = \log h(Y, Z \mid \theta) - \log K(Z \mid Y, \theta)\) holds for every \(Z\), taking \(E_{Z \mid Y, \theta_0}\) of both sides gives, for any \(\theta_0\),

\[ \ell_{\text{obs}}(\theta) = \underbrace{E_{Z \mid Y, \theta_0}\!\left[\log h(Y, Z \mid \theta)\right]}_{Q(\theta \mid \theta_0)} - \underbrace{E_{Z \mid Y, \theta_0}\!\left[\log K(Z \mid Y, \theta)\right]}_{H(\theta \mid \theta_0)} . \]

The left side does not depend on \(Z\), so the expectation leaves it unchanged; this is the whole content of the step.

Proof. Set \(\theta_0 = \hat\theta^{(t)}\) and subtract the identity evaluated at \(\theta = \hat\theta^{(t)}\) from the one evaluated at \(\theta = \hat\theta^{(t+1)}\):

\[ \begin{aligned} \ell_{\text{obs}}\!\left(\hat\theta^{(t+1)}\right) - \ell_{\text{obs}}\!\left(\hat\theta^{(t)}\right) &= \underbrace{\left[Q\!\left(\hat\theta^{(t+1)} \mid \hat\theta^{(t)}\right) - Q\!\left(\hat\theta^{(t)} \mid \hat\theta^{(t)}\right)\right]}_{\ge\, 0 \text{ by the M-step}} \\ &\quad - \underbrace{\left[H\!\left(\hat\theta^{(t+1)} \mid \hat\theta^{(t)}\right) - H\!\left(\hat\theta^{(t)} \mid \hat\theta^{(t)}\right)\right]}_{\le\, 0 \text{ by Jensen, below}} . \end{aligned} \]

The \(H\) term. We need \(H(\theta \mid \hat\theta^{(t)}) \le H(\hat\theta^{(t)} \mid \hat\theta^{(t)})\) for every \(\theta\), that is

\[ E_{Z \mid Y, \hat\theta^{(t)}}\!\left[\log \frac{K(Z \mid Y, \theta)}{K(Z \mid Y, \hat\theta^{(t)})}\right] \le 0 . \]

Because \(\log\) is concave, Jensen’s inequality gives \(E[\log W] \le \log E[W]\), so

\[ \begin{aligned} E_{Z \mid Y, \hat\theta^{(t)}}\!\left[\log \frac{K(Z \mid Y, \theta)}{K(Z \mid Y, \hat\theta^{(t)})}\right] &\le \log \int \frac{K(Z \mid Y, \theta)}{K(Z \mid Y, \hat\theta^{(t)})} \, K(Z \mid Y, \hat\theta^{(t)}) \, dZ \\ &= \log \int K(Z \mid Y, \theta) \, dZ = \log 1 = 0 . \qquad \blacksquare \end{aligned} \]

The quantity on the left is \(-\mathrm{KL}\!\left(K(\cdot \mid Y, \hat\theta^{(t)}) \,\|\, K(\cdot \mid Y, \theta)\right)\). Note carefully what the theorem does and does not say: the observed likelihood never decreases, but that guarantees convergence only to a stationary point, which may be a local maximum or even a saddle point.

6.1.6 EM as alternating optimization

There is a second formulation that makes the algorithm’s structure clearer and generalizes better. Let \(\tilde P(\cdot)\) be any distribution on the hidden data \(Z\), and define

\[ F\!\left(\tilde P, \theta\right) = \int \tilde P(z) \log P(Y, z \mid \theta) \, dz - \int \tilde P(z) \log \tilde P(z) \, dz . \]

Using \(P(Y, z \mid \theta) = P(Y \mid \theta) \, P(z \mid Y, \theta)\),

\[ F\!\left(\tilde P, \theta\right) = \ell_{\text{obs}}(\theta) - \mathrm{KL}\!\left(\tilde P \,\|\, P(\cdot \mid Y, \theta)\right), \qquad \mathrm{KL}(P \| q) = \int P(z) \log \frac{P(z)}{q(z)} \, dz \; \ge\; 0 . \]

Both steps of EM are now coordinate ascent on the single function \(F\):

  • E-step maximizes \(F\) over \(\tilde P\) with \(\theta = \hat\theta^{(t)}\) fixed. Since \(\mathrm{KL} \ge 0\) with equality if and only if \(\tilde P = P(\cdot \mid Y, \hat\theta^{(t)})\), the E-step sets \(\tilde P\) to the conditional distribution of \(Z\).
  • M-step maximizes \(F\) over \(\theta\) with \(\tilde P\) fixed. The entropy term is free of \(\theta\), so this is \(\arg\max_\theta Q(\theta \mid \hat\theta^{(t)})\).

The ascending property is then immediate: alternating maximization of a single objective cannot decrease it. This view also explains the variational methods used when the E-step is intractable — restrict \(\tilde P\) to a manageable family and accept a bound rather than an equality.

For completeness, \(\mathrm{KL} \ge 0\) follows from \(\log x \le x - 1\):

\[ \mathrm{KL}(P \| q) = -\int P(z) \log \frac{q(z)}{P(z)} \, dz \;\ge\; -\int P(z) \left(\frac{q(z)}{P(z)} - 1\right) dz = -\int \left[q(z) - P(z)\right] dz = 0 . \]

6.2 Example 1: Two-Component Normal Mixture

6.2.1 Model and likelihoods

\[ Z_i \sim \text{Bern}(p), \qquad Y_i \mid Z_i = 1 \sim N(\mu_1, 1), \qquad Y_i \mid Z_i = 0 \sim N(\mu_0, 1) . \]

Observed: \(y_1, \ldots, y_n\). Hidden: \(z_1, \ldots, z_n\). Parameter \(\theta = (\mu_0, \mu_1, p)\).

Complete likelihood

\[ P(y, z \mid \theta) = \prod_{i=1}^{n} P(y_i \mid z_i, \theta) \, P(z_i \mid \theta) = \prod_{i=1}^{n} \varphi(y_i \mid \mu_{z_i}, 1) \, p^{z_i} (1-p)^{1-z_i} . \]

Observed likelihood, summing out each \(z_i\),

\[ P(y \mid \theta) = \prod_{i=1}^{n}\left[\varphi(y_i \mid \mu_1, 1)\, p + \varphi(y_i \mid \mu_0, 1)(1 - p)\right] . \]

The sum inside the product is what makes direct maximization awkward.

Code
par(mar = c(4, 4, 1, 1)); mu0 <- 0; mu1 <- 4; p <- 0.3
curve((1 - p) * dnorm(x, mu0), -3.5, 7.5, lwd = 2, col = "steelblue",
      ylab = "density", xlab = "y", ylim = c(0, 0.3))
curve(p * dnorm(x, mu1), add = TRUE, lwd = 2, col = "firebrick")
curve((1 - p) * dnorm(x, mu0) + p * dnorm(x, mu1), add = TRUE, lwd = 3)
legend("topright", bty = "n", lwd = c(2, 2, 3),
       col = c("steelblue", "firebrick", "black"),
       legend = c(expression((1-p)*phi(y*"|"*mu[0])),
                  expression(p*phi(y*"|"*mu[1])),
                  expression(f(y*"|"*theta) == "sum")))
Figure 6.3: Introduces the two-component normal mixture model by showing that its density is the weighted sum of the two component densities. The observed density is a sum of two weighted normal components.

The marginal density may be bimodal or unimodal depending on \(p\) and \(|\mu_1 - \mu_0|\) — a point worth keeping in mind, since the unimodal case is where EM struggles most.

Code
par(mfrow = c(1, 3), mar = c(4, 4, 2, 1))
mix <- function(x, mu0, mu1, p) (1 - p) * dnorm(x, mu0) + p * dnorm(x, mu1)
for (s in list(c(0, 4, 0.5), c(0, 4, 0.15), c(0, 1.5, 0.5))) {
  curve(mix(x, s[1], s[2], s[3]), -4, 7, lwd = 3, xlab = "y", ylab = "density",
        main = bquote(mu[0] == .(s[1]) ~ "," ~ mu[1] == .(s[2]) ~ "," ~ p == .(s[3])))
  y <- ifelse(rbinom(200, 1, s[3]) == 1, rnorm(200, s[2]), rnorm(200, s[1]))
  rug(y, col = "gray40")
}
Figure 6.4: Shows that a mixture density can look unimodal or bimodal depending on its parameters, which affects how easily those parameters can be estimated. Separation and mixing proportion determine whether the mixture is visibly bimodal.

6.2.2 Complete log-likelihood

With \(\log \varphi(y \mid \mu, 1) = -\tfrac{1}{2}(y - \mu)^2 - \log\sqrt{2\pi}\),

\[ \begin{aligned} \ell_{\text{comp}}(\theta; y, z) &= \sum_{i=1}^{n}\left[z_i \log p + (1 - z_i)\log(1-p) - \tfrac{1}{2}(y_i - \mu_{z_i})^2\right] + C \\ &= \left(\sum_{i=1}^{n} z_i\right) \log \frac{p}{1-p} + n \log(1-p) \\ &\quad - \frac{1}{2}\sum_{i=1}^{n}\left[z_i (y_i - \mu_1)^2 + (1 - z_i)(y_i - \mu_0)^2\right] + C . \end{aligned} \]

Two features drive everything that follows. The expression is linear in each \(z_i\), so the E-step needs only \(E(Z_i \mid y_i, \hat\theta^{(t)})\) rather than the full conditional distribution. And given \(z\), the parameters separate: \(p\) is a Bernoulli proportion while \(\mu_1\) and \(\mu_0\) are group means.

6.2.3 E-step: soft classification

Given \(\hat\theta^{(t)} = (\hat\mu_0^{(t)}, \hat\mu_1^{(t)}, \hat p^{(t)})\), Bayes’ rule gives

\[ \hat p_i^{(t)} \equiv P\!\left(Z_i = 1 \mid y_i, \hat\theta^{(t)}\right) = \frac{\varphi\!\left(y_i \mid \hat\mu_1^{(t)}, 1\right) \hat p^{(t)}} {\varphi\!\left(y_i \mid \hat\mu_0^{(t)}, 1\right)\!\left(1 - \hat p^{(t)}\right) + \varphi\!\left(y_i \mid \hat\mu_1^{(t)}, 1\right) \hat p^{(t)}} , \]

and therefore

\[ \begin{aligned} Q\!\left(\theta \mid \hat\theta^{(t)}\right) &= \left(\sum_i \hat p_i^{(t)}\right) \log \frac{p}{1-p} + n \log(1-p) \\ &\quad - \frac{1}{2}\sum_i \left[\hat p_i^{(t)} (y_i - \mu_1)^2 + \left(1 - \hat p_i^{(t)}\right)(y_i - \mu_0)^2\right] . \end{aligned} \]

Computationally, \(\hat p_i^{(t)}\) must be formed on the log scale. Writing \(a_i = \log \varphi(y_i \mid \hat\mu_1^{(t)}, 1) + \log \hat p^{(t)}\) and \(b_i = \log \varphi(y_i \mid \hat\mu_0^{(t)}, 1) + \log(1 - \hat p^{(t)})\), we have \(\hat p_i^{(t)} = \exp\{a_i - \operatorname{lse}(a_i, b_i)\}\) where \(\operatorname{lse}\) is the log-sum-exp function of the chapter on computer arithmetic. Forming the ratio directly underflows as soon as an observation sits far from both means.

Code
par(mfrow = c(1, 2), mar = c(4, 4, 1, 1)); mu0 <- 0; mu1 <- 4; p <- 0.3
f0 <- function(x) (1 - p) * dnorm(x, mu0)
f1 <- function(x) p * dnorm(x, mu1)
curve(f0, -3.5, 7.5, lwd = 2, col = "steelblue", ylab = "weighted density",
      xlab = "y", ylim = c(0, 0.3))
curve(f1, add = TRUE, lwd = 2, col = "firebrick")
yi <- c(-0.5, 1.8, 3.2)
for (y in yi) {
  segments(y, 0, y, f0(y), col = "steelblue", lwd = 4)
  segments(y, f0(y), y, f0(y) + f1(y), col = "firebrick", lwd = 4)
  text(y, f0(y) + f1(y), sprintf("%.2f", f1(y) / (f0(y) + f1(y))), pos = 3, cex = 0.9)
}
legend("topright", bty = "n", lwd = 2, col = c("steelblue", "firebrick"),
       legend = c(expression((1-hat(p))*phi(y*"|"*hat(mu)[0])),
                  expression(hat(p)*phi(y*"|"*hat(mu)[1]))))
curve(f1(x) / (f0(x) + f1(x)), -3.5, 7.5, lwd = 3, xlab = "y",
      ylab = expression(P(Z[i] == 1*"|"*y[i]*","*hat(theta)^(t))))
abline(h = c(0, 1), lty = 3); points(yi, f1(yi) / (f0(yi) + f1(yi)), pch = 19)
Figure 6.5: Illustrates the E-step of EM for a mixture: the responsibility of a component is the posterior probability that an observation came from it. Left: the responsibility at each \(y_i\) is the red share of the total height. Right: responsibility as a function of \(y\).

6.2.4 M-step: weighted proportions and means

\(Q\) separates into one term in \(p\) and two in \(\mu_1\), \(\mu_0\), each maximized in closed form.

Table 6.2: Derives the M-step updates for the mixture model, showing that each is a weighted version of the complete-data MLE. M-step updates for the two-component mixture
Update Stationary equation \(\Longrightarrow\) solution
\(p\) \(\dfrac{\partial Q}{\partial p} = \dfrac{\sum_i \hat p_i^{(t)}}{p(1-p)} - \dfrac{n}{1-p} = 0 \;\Longrightarrow\; \hat p^{(t+1)} = \dfrac{1}{n}\sum_{i=1}^{n} \hat p_i^{(t)}\)
\(\mu_1\) \(\dfrac{\partial Q}{\partial \mu_1} = \sum_i \hat p_i^{(t)}(y_i - \mu_1) = 0 \;\Longrightarrow\; \hat\mu_1^{(t+1)} = \dfrac{\sum_i \hat p_i^{(t)} y_i}{\sum_i \hat p_i^{(t)}}\)
\(\mu_0\) weights \(1 - \hat p_i^{(t)}\): \(\;\hat\mu_0^{(t+1)} = \dfrac{\sum_i \left(1 - \hat p_i^{(t)}\right) y_i}{\sum_i \left(1 - \hat p_i^{(t)}\right)}\)

In words: the M-step is the complete-data MLE with each observation split between the two groups in proportion to its soft classification. Return to the E-step with \(\hat\theta^{(t+1)}\) and recompute the responsibilities.

6.2.5 Implementation

Code
log_sum_exp <- function(log_x) {
    max_log_x <- max(log_x)
    max_log_x + log(sum(exp(log_x - max_log_x)))
}

### observed log-likelihood, theta = (p, mu1, mu0)
log_like_obs <- function(theta, Y) {
    log_joint <- cbind(log(theta[1])     + dnorm(Y, theta[2], 1, log = TRUE),
                       log(1 - theta[1]) + dnorm(Y, theta[3], 1, log = TRUE))
    sum(apply(log_joint, 1, log_sum_exp))
}

### E-step: responsibilities P(Z_i = 1 | y_i, theta)
e_step <- function(theta, Y) {
    l1 <- dnorm(Y, theta[2], 1, log = TRUE) + log(theta[1])
    l0 <- dnorm(Y, theta[3], 1, log = TRUE) + log(1 - theta[1])
    exp(l1 - apply(cbind(l1, l0), 1, log_sum_exp))
}

### M-step: closed-form weighted updates
m_step <- function(w, Y) {
    c(mean(w),
      sum(Y * w) / sum(w),
      sum(Y * (1 - w)) / sum(1 - w))
}

em_mixnorm <- function(theta0, Y, no_iters) {
    out <- matrix(NA_real_, no_iters + 1, 4,
                  dimnames = list(NULL, c("p", "mu1", "mu0", "log_lik")))
    theta <- theta0
    out[1, ] <- c(theta, log_like_obs(theta, Y))
    for (i in seq_len(no_iters)) {
        theta <- m_step(e_step(theta, Y), Y)
        out[i + 1, ] <- c(theta, log_like_obs(theta, Y))
    }
    out
}
Code
gen_mixnorm <- function(theta, n) {
    Z <- rbinom(n, 1, theta[1])
    Y <- rnorm(n, mean = ifelse(Z == 1, theta[2], theta[3]), sd = 1)
    plot(Y, Z, col = cm.colors(2)[Z + 1], pch = 19,
         ylab = "component label Z")
    Y
}

set.seed(812)
data <- gen_mixnorm(c(0.3, 0, 3), 200)
Figure 6.6: Shows the simulated data used to demonstrate EM for a mixture; the colours reveal the component labels, which are unobserved in practice and must be inferred. Simulated mixture data, coloured by the (normally unobserved) component label.

A well-chosen start converges quickly:

Code
round(em_mixnorm(c(0.5, 0, 3), data, 10), 4)
           p    mu1    mu0   log_lik
 [1,] 0.5000 0.0000 3.0000 -375.3490
 [2,] 0.3377 0.2695 3.0137 -361.6709
 [3,] 0.3242 0.2319 2.9768 -361.3077
 [4,] 0.3154 0.1956 2.9584 -361.1388
 [5,] 0.3094 0.1694 2.9463 -361.0581
 [6,] 0.3054 0.1513 2.9380 -361.0202
 [7,] 0.3026 0.1389 2.9323 -361.0026
 [8,] 0.3007 0.1306 2.9285 -360.9945
 [9,] 0.2995 0.1249 2.9258 -360.9908
[10,] 0.2986 0.1211 2.9240 -360.9891
[11,] 0.2980 0.1185 2.9228 -360.9884

The monotone increase of the last column is the ascending property in action; it is the single most useful diagnostic when debugging an EM implementation, since any decrease indicates an error in the E- or M-step.

6.2.6 Shinylive App for the EM Algorithm for a Normal Mixture

There is a shinylive app to let you watch the EM algorithm fit a two-component normal mixture, showing how the estimates and the likelihood evolve from iteration to iteration.

6.2.7 Comparison with general-purpose optimizers

EM is not the only way to maximize the observed likelihood. Applying a general-purpose optimizer directly requires attention to the parameter space: \(p\) must lie in \((0,1)\), so we reparameterize with the logit.

Code
neg_loglike_obs <- function(theta, Y) -log_like_obs(theta, Y)

### transformed parameterization: ttheta[1] = logit(p)
neg_loglike_obs_transf <- function(ttheta, Y) {
    theta <- ttheta
    theta[1] <- 1 / (1 + exp(-ttheta[1]))
    neg_loglike_obs(theta, Y)
}

lp0 <- log(0.3 / 0.7)

### Newton-type, untransformed: p can leave (0, 1)
try(nlm(neg_loglike_obs, p = c(0.3, 0, 3), Y = data)$estimate)
[1] 0.2968473 0.1131871 2.9203484
Code
try(nlm(neg_loglike_obs, p = c(0.5, -10, 5), Y = data)$estimate)
[1]  5.869764e-06 -1.000004e+01  4.038014e+00
Code
### Newton-type, transformed
try(nlm(neg_loglike_obs_transf, p = c(lp0, 0, 3), Y = data)$estimate)
[1] -0.8623555  0.1131868  2.9203483
Code
try(nlm(neg_loglike_obs_transf, p = c(0, -10, 5), Y = data)$estimate)
[1] -16.604291  -9.996458   2.087049
Code
### Nelder-Mead
try(optim(c(lp0, 0, 3), neg_loglike_obs_transf, Y = data, method = "Nelder-Mead")$par)
[1] -0.8623197  0.1132163  2.9203325
Code
try(optim(c(0, -10, 5), neg_loglike_obs_transf, Y = data, method = "Nelder-Mead")$par)
[1] -0.8622804  0.1131101  2.9206253
Code
### Conjugate gradient
try(optim(c(0, 0, 3), neg_loglike_obs_transf, Y = data, method = "CG")$par)
[1] -0.8623543  0.1131880  2.9203502
Code
try(optim(c(0, -10, 5), neg_loglike_obs_transf, Y = data, method = "CG")$par)
[1] -6.090903 -9.998146  2.080878

Applied to the observed log-likelihood, these algorithms are more fragile than EM when the initial values are poorly chosen: the untransformed runs can step outside \(p \in (0,1)\) and produce NaN, and the gradient-based methods can stall in the flat region that a distant start creates. Nelder–Mead is the most stable of the three here, at the cost of many more function evaluations.

Table 6.3: Helps decide between EM and a general-purpose optimizer by listing the strengths and weaknesses of each. EM compared with direct numerical maximization
EM General optimizer on \(\ell_{\text{obs}}\)
Constraints Respected automatically by the M-step Require reparameterization
Monotonicity Guaranteed; a decrease signals a coding error None; a bad step can be accepted
Derivatives None needed Gradient helpful, Hessian better
Convergence rate Linear, rate set by the missing information Superlinear or quadratic near the optimum
Standard errors Not produced; need Louis’ method or a bootstrap Hessian available directly
Behaviour from poor starts Slow but stable Can fail outright

The last row is the practical trade. EM rarely fails and rarely needs tuning, which is why it dominates in mixture and latent-variable modelling; it is also slow near the optimum and gives no standard errors, which is why a hybrid — EM to get close, then a Newton step to polish and to obtain the Hessian — is common in production code.

6.3 Example 2: Censored Poisson Data

6.3.1 Truncated distributions in brief

Let \(X \sim f(x)\) and \(Y = I(X > c)\). Then \(Y \sim \text{Bern}\{P(X > c)\}\), and the conditional distribution of \(X\) given \(Y\) is \(f\) restricted to one side of \(c\) and renormalized:

\[ f(x \mid Y = 1) = \frac{f(x)\, I(x > c)}{\int_c^{\infty} f(t)\,dt}, \qquad f(x \mid Y = 0) = \frac{f(x)\, I(x \le c)}{\int_{-\infty}^{c} f(t)\,dt} . \]

For discrete \(X\) the integrals are sums. This is exactly the distribution the E-step needs when an observation is known only to lie on one side of \(c\).

Code
par(mfrow = c(1, 2), mar = c(4, 4, 2, 1)); cc <- 1
curve(dnorm, -3.5, 3.5, lwd = 3, xlab = "x", ylab = "density",
      main = "f(x) with cut point c")
xs <- seq(cc, 3.5, length.out = 100)
polygon(c(xs, rev(xs)), c(dnorm(xs), rep(0, 100)),
        col = adjustcolor("firebrick", 0.3), border = NA)
xs <- seq(-3.5, cc, length.out = 100)
polygon(c(xs, rev(xs)), c(dnorm(xs), rep(0, 100)),
        col = adjustcolor("steelblue", 0.3), border = NA)
abline(v = cc, lty = 2); text(cc, 0.38, "c", pos = 4)
text(1.8, 0.05, "P(X > c)", col = "firebrick")
text(-1, 0.1, expression(P(X <= c)), col = "steelblue")
curve(dnorm(x) * (x > cc) / pnorm(cc, lower.tail = FALSE), -3.5, 3.5, lwd = 3,
      col = "firebrick", n = 1001, xlab = "x", ylab = "density",
      main = "conditional densities", ylim = c(0, 1.6))
curve(dnorm(x) * (x <= cc) / pnorm(cc), add = TRUE, lwd = 3, col = "steelblue", n = 1001)
abline(v = cc, lty = 2)
legend("topleft", bty = "n", lwd = 3, col = c("steelblue", "firebrick"),
       legend = c("f(x | Y = 0)", "f(x | Y = 1)"))
Figure 6.7: Illustrates the conditional distributions needed in the E-step when an observation is only known to lie on one side of a cut point. A density split at a cut point, and the two renormalized conditional densities.

6.3.2 Data and likelihoods

Let \(y_i \overset{iid}{\sim} \text{Pois}(\lambda)\) for \(i = 1, \ldots, n\). The first \(m\) values are observed exactly; for \(i > m\) we know only that \(y_i < 2\), recorded as \(x_i = I(y_i < 2) = 1\).

Observed data: \(y_1, \ldots, y_m\) together with \(x_{m+1} = \cdots = x_n = 1\). Missing: \(y_{m+1}, \ldots, y_n\).

Complete likelihood

\[ \prod_{i=1}^{n} f^{\text{Pois}}(y_i \mid \lambda) \cdot \prod_{i=m+1}^{n} I(y_i < 2) . \]

Observed likelihood

\[ \prod_{i=1}^{m} f^{\text{Pois}}(y_i \mid \lambda) \cdot \prod_{i=m+1}^{n} P(y_i < 2 \mid \lambda), \qquad P(y_i < 2 \mid \lambda) = e^{-\lambda}(1 + \lambda) . \]

Taking logarithms and dropping constants,

\[ \ell_{\text{obs}}(\lambda) = m \bar y_{1:m} \log \lambda - n \lambda + (n - m)\log(1 + \lambda) . \]

The second factor makes the MLE nonlinear in \(\lambda\); EM sidesteps it.

6.3.3 E-step

\[ \ell_{\text{comp}}(\lambda) = -n\lambda + (\log \lambda) \sum_{i=1}^{m} y_i + (\log \lambda) \underbrace{\sum_{i=m+1}^{n} y_i}_{\text{missing}} - \sum_{i=1}^{n} \log(y_i!) . \]

For \(i > m\) we have \(y_i \in \{0, 1\}\), and the Poisson pmf truncated to that set given \(\lambda^{(t)}\) is

\[ P\!\left(y_i = 0 \mid x_i = 1\right) = \frac{1}{1 + \lambda^{(t)}}, \qquad P\!\left(y_i = 1 \mid x_i = 1\right) = \frac{\lambda^{(t)}}{1 + \lambda^{(t)}} , \]

so that

\[ \hat y^{(t)} \equiv E\!\left(y_i \mid x_i = 1, \lambda^{(t)}\right) = \frac{\lambda^{(t)}}{1 + \lambda^{(t)}} . \]

Since \(y_i! = 1\) for \(y_i \in \{0, 1\}\), the \(\log(y_i!)\) term is a known constant and no further expectation is needed.

Code
par(mfrow = c(1, 2), mar = c(4, 4, 2, 1)); lt <- 1.5; k <- 0:6
barplot(dpois(k, lt), names.arg = k,
        col = c("firebrick", "firebrick", rep("gray80", 5)),
        xlab = "y", ylab = "probability",
        main = bquote("Pois(" * lambda^(t) == .(lt) * ")"))
barplot(c(1, lt) / (1 + lt), names.arg = 0:1, col = "firebrick",
        xlab = "y", ylab = "probability",
        main = expression("truncated to {0, 1}: " * P(y[i]*"|"*x[i] == 1)))
Figure 6.8: Illustrates the E-step for censored Poisson counts: the missing count follows the Poisson distribution restricted to the values consistent with the censoring information. The conditional distribution of a censored count is the Poisson pmf restricted to \(\{0,1\}\) and renormalized.

6.3.4 M-step and the EM update

\[ Q\!\left(\lambda \mid \lambda^{(t)}\right) = -n\lambda + (\log \lambda)\left[\sum_{i=1}^{m} y_i + (n - m)\,\hat y^{(t)}\right] + C^{(t)} , \]

\[ \frac{\partial Q}{\partial \lambda} = -n + \frac{1}{\lambda}\left[\sum_{i=1}^{m} y_i + (n - m)\,\hat y^{(t)}\right] = 0 , \]

\[ \Longrightarrow \quad \lambda^{(t+1)} = \frac{m\, \bar y_{1:m} + (n - m)\dfrac{\lambda^{(t)}}{1 + \lambda^{(t)}}}{n} . \]

The update is the ordinary Poisson MLE — the sample mean — with each censored value replaced by its conditional expectation. As warned in the overview, this works only because \(\ell_{\text{comp}}\) is linear in the missing \(y_i\).

6.3.5 Implementation

Code
### observed log-likelihood, up to an additive constant
##   m    : number of exactly observed counts
##   ybar : their mean
##   ncen : number of counts known only to be < 2
loglik_obs_pois <- function(m, ybar, ncen, lambda) {
    m * ybar * log(lambda) - (m + ncen) * lambda + ncen * log(1 + lambda)
}

em_censored_poisson <- function(m, ybar, ncen,
                                lambda0 = (m * ybar + ncen) / (m + ncen),
                                iterations = 20) {
    out <- matrix(NA_real_, iterations + 1, 2,
                  dimnames = list(NULL, c("lambda", "log_lik")))
    lambda <- lambda0
    out[1, ] <- c(lambda, loglik_obs_pois(m, ybar, ncen, lambda))
    for (i in seq_len(iterations)) {
        y_mis  <- lambda / (1 + lambda)                       # E-step
        lambda <- (m * ybar + ncen * y_mis) / (m + ncen)       # M-step
        out[i + 1, ] <- c(lambda, loglik_obs_pois(m, ybar, ncen, lambda))
    }
    out
}
Code
set.seed(812)
y    <- rpois(200, 3)
ncen <- sum(y < 2)
m    <- length(y) - ncen
ybar <- mean(y[y >= 2])
c(m = m, ncen = ncen, ybar_observed = ybar)
            m          ncen ybar_observed 
   157.000000     43.000000      3.528662 

Discarding the censored observations and averaging the rest gives an estimate clearly above the true mean of \(3\): conditioning on \(y \ge 2\) removes the small counts and biases the mean upward. EM recovers them.

Code
round(em_censored_poisson(m, ybar, ncen, lambda0 = 100, iterations = 10), 5)
         lambda      log_lik
 [1,] 100.00000 -17250.28553
 [2,]   2.98287     68.31091
 [3,]   2.93102     68.40282
 [4,]   2.93031     68.40284
 [5,]   2.93030     68.40284
 [6,]   2.93030     68.40284
 [7,]   2.93030     68.40284
 [8,]   2.93030     68.40284
 [9,]   2.93030     68.40284
[10,]   2.93030     68.40284
[11,]   2.93030     68.40284
Code
round(em_censored_poisson(m, ybar, ncen, lambda0 = ybar, iterations = 10), 5)
       lambda  log_lik
 [1,] 3.52866 57.76492
 [2,] 2.93752 68.40109
 [3,] 2.93040 68.40284
 [4,] 2.93030 68.40284
 [5,] 2.93030 68.40284
 [6,] 2.93030 68.40284
 [7,] 2.93030 68.40284
 [8,] 2.93030 68.40284
 [9,] 2.93030 68.40284
[10,] 2.93030 68.40284
[11,] 2.93030 68.40284

Both starting values reach the same limit, and the log-likelihood increases monotonically from each. Note how slowly the run from \(\lambda^{(0)} = 100\) descends at first — a single-parameter illustration of the same slow-drift behaviour seen in the mixture app.

6.3.6 Comparison with general-purpose optimizers

Code
neg_loglik_pois <- function(lambda, m, ybar, ncen) {
    -loglik_obs_pois(m, ybar, ncen, lambda)
}

try(nlm(neg_loglik_pois, p = ybar, m = m, ybar = ybar, ncen = ncen)$estimate)
[1] 2.930295
Code
try(nlm(neg_loglik_pois, p = 100,  m = m, ybar = ybar, ncen = ncen)$estimate)
[1] 2.930295
Code
try(optim(ybar, neg_loglik_pois, method = "CG",
          m = m, ybar = ybar, ncen = ncen)$par)
[1] 2.930297
Code
try(optim(100,  neg_loglik_pois, method = "CG",
          m = m, ybar = ybar, ncen = ncen)$par)
[1] 2.930297

With one parameter and a smooth concave objective this is an easy problem for any method; the contrast with the mixture example is instructive, since there the multimodality and the constraint on \(p\) were what made the general optimizers fragile.

6.4 More Complex Applications

6.4.1 Model-based clustering

\[ Z_i \sim \text{Categorical}(\pi_1, \ldots, \pi_K), \qquad Y_i \mid Z_i = k \sim N_d(\mu_k, \Sigma_k) . \]

This is the multivariate, \(K\)-component generalization of Section 6.2. The E-step computes soft cluster memberships \(P(Z_i = k \mid y_i, \hat\theta^{(t)})\); the M-step returns weighted means, covariances and proportions. The mclust package implements this with a family of constrained covariance structures.

Code
par(mar = c(4, 4, 1, 1))
ctr <- rbind(c(0, 0), c(4, 3), c(1, 5))
Sig <- list(diag(2) * 0.8, matrix(c(1, 0.7, 0.7, 1), 2), diag(c(1.2, 0.4)))
cols <- c("steelblue", "firebrick", "forestgreen")
ang <- seq(0, 2 * pi, length.out = 100)
plot(NA, xlim = c(-3, 7), ylim = c(-3, 8),
     xlab = expression(y[1]), ylab = expression(y[2]))
for (k in 1:3) {
  R <- chol(Sig[[k]])
  pts <- matrix(rnorm(120), 60) %*% R + rep(ctr[k, ], each = 60)
  points(pts, col = adjustcolor(cols[k], 0.6), pch = 19, cex = 0.8)
  ell <- (cbind(cos(ang), sin(ang)) * 2.1) %*% R + rep(ctr[k, ], each = 100)
  lines(ell, col = cols[k], lwd = 2)
  points(ctr[k, 1], ctr[k, 2], pch = 4, lwd = 3, col = cols[k])
}
Figure 6.9: Illustrates model-based clustering, the multivariate extension of the normal mixture model, in which EM assigns observations to clusters of different shapes. Three-component multivariate normal mixture with unequal covariances.

6.4.2 Hidden Markov models

Hidden states \(h_1 \to h_2 \to \cdots \to h_n\) form a Markov chain, and each observation depends only on its own state:

\[ P(y_{1:n} \mid h_{1:n}, \theta) = \prod_{i=1}^{n} P(y_i \mid h_i, \theta) . \]

The E-step is the forward–backward algorithm, which computes \(P(h_i \mid y_{1:n}, \hat\theta^{(t)})\) and \(P(h_i, h_{i+1} \mid y_{1:n}, \hat\theta^{(t)})\) without enumerating all \(K^n\) state sequences; the M-step produces weighted transition and emission estimates. The combination is known as the Baum–Welch algorithm, and it is the clearest example of an E-step that is itself a nontrivial computation.

Code
par(mar = c(4, 4, 1, 1)); N <- 120
Pm <- matrix(c(0.95, 0.05, 0.1, 0.9), 2, byrow = TRUE)
h <- integer(N); h[1] <- 1
for (i in 2:N) h[i] <- sample(1:2, 1, prob = Pm[h[i - 1], ])
yy <- rnorm(N, mean = c(0, 3)[h])
plot(yy, type = "n", xlab = "i", ylab = expression(y[i]))
r <- rle(h); e <- cumsum(r$lengths); s <- c(1, head(e, -1) + 1)
rect(s - 0.5, par("usr")[3], e + 0.5, par("usr")[4],
     col = adjustcolor(c("steelblue", "firebrick")[r$values], 0.15), border = NA)
lines(yy, col = "gray30")
points(yy, pch = 19, col = c("steelblue", "firebrick")[h], cex = 0.7)
legend("topright", bty = "n", pch = 19, col = c("steelblue", "firebrick"),
       legend = c(expression(h[i] == 1), expression(h[i] == 2)), horiz = TRUE)
Figure 6.10: Illustrates a hidden Markov model, whose unobserved state sequence generates the data, as a further example to which EM applies. A two-state hidden Markov chain with normal emissions; background shading shows the hidden state.

6.4.3 Factor analysis and the common pattern

\[ y_i = \Gamma x_i + \varepsilon_i, \qquad x_i \sim N_q(0, I) \text{ hidden}, \qquad \varepsilon_i \sim N_d(0, \Psi) . \]

The E-step uses the fact that \(x_i \mid y_i, \hat\theta^{(t)}\) is normal with closed-form mean and covariance; the M-step is a regression of \(y\) on the expected factors.

Across all these applications the recipe is the same:

  1. Introduce a hidden variable that makes the complete-data model tractable.
  2. E-step: compute the conditional distribution of the hidden data, or just the expected sufficient statistics if \(\ell_{\text{comp}}\) is linear in them.
  3. M-step: compute the complete-data MLE with those expected sufficient statistics in place of the unobserved ones.

The art is entirely in step 1. The same observed-data model often admits several choices of \(Z\), and they lead to EM algorithms with quite different convergence rates — faster when the augmentation adds little information, slower when the missing information is a large fraction of the total.

6.5 Summary

  • EM maximizes \(\ell_{\text{obs}}\) by alternating between forming \(Q(\theta \mid \hat\theta^{(t)}) = E_{Z \mid Y, \hat\theta^{(t)}}[\ell_{\text{comp}}]\) and maximizing it.
  • Every iteration weakly increases \(\ell_{\text{obs}}\). Equivalently, EM is coordinate ascent on \(F(\tilde P, \theta) = \ell_{\text{obs}}(\theta) - \mathrm{KL}(\tilde P \,\|\, P(Z \mid Y, \theta))\).
  • When \(\ell_{\text{comp}}\) is linear in sufficient statistics of \(Z\), the E-step reduces to computing their conditional expectations. Otherwise the full conditional distribution is required, and “plug in the expectation” is wrong.
  • Convergence is linear, often slow, and only to a stationary point. Run from several starting values and compare the attained log-likelihoods.
  • Standard errors are not a by-product. Use Louis’ identity, the SEM algorithm, a bootstrap, or a final Newton step.