Gaussian Mixture Models and Expectation-Maximization › Example
Machine Learning from ScratchAll chapters Gaussian Mixture Models and Expectation-Maximization › ExampleSection view · Sections in this chapter5 / 10 ↓
Reading tools Definitions, links & notes
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
We can carry a full EM iteration by hand on four one-dimensional observations, , with two components. To keep the arithmetic transparent we fix the variances at and the weights at for the first E-step; the M-step then updates everything.
The normal density at is , where is the mean and is the variance, here and with . With the leading constant is . Starting means are and . For the squared distances are and ; dividing by gives approximately and . Evaluating the densities with the unrounded constant and exponents gives approximately and . The responsibilities follow from the ratio:
Repeating for all four points gives the E-step below. The two outer points are almost certain, while has a mixed posterior assignment, sitting at (that is, is close to but below one half, so component 2 is slightly favoured). That contested point is useful because a nearest-centroid method still assigns it deterministically, while the mixture retains both possibilities under its fitted probability model.
| 1.0 | 0.21297 | 0.00760 | 0.9656 | 0.0344 |
| 2.5 | 0.25159 | 0.06632 | 0.7914 | 0.2086 |
| 4.0 | 0.10934 | 0.21297 | 0.3392 | 0.6608 |
| 6.0 | 0.00760 | 0.21297 | 0.0344 | 0.9656 |
The log-likelihood at this parameter value is the sum of the logs of the mixture densities. For the mixture density is using unrounded densities, whose natural logarithm is approximately . Summing the four contributions gives . That is our baseline. The exact M-step cannot lower it; equality is possible at a stationary configuration. In this example we can check the strict increase numerically.
Now the M-step. Effective counts are the column sums: and . These are not integer counts. They are the total fractional membership each component has earned and provide the denominators for the M-step's weighted averages. The new mean of component 1 is the responsibility-weighted average of the observations,
and similarly , where we used the fact that the two weighted sums must add to the total . The variances use the same weights applied to squared deviations:
giving , and the same calculation for component 2 gives , so . The weights become and .
The test of the whole procedure is whether the likelihood improved. Recomputing the mixture density at the new parameters gives , which is larger than . The log-likelihood increases by about in this step, consistent with the nondecrease guarantee for this exact update. The contested point at has also moved: its responsibility for component 2 increases from about to . Both means move closer to this point. The posterior change depends on the updated weights and variances as well as the means; distances to the means alone do not determine it.
The cell below reproduces the hand calculation with the same formulas, so we can confirm the arithmetic and inspect the responsibilities directly.
PythonIn [3]Expand
x_ex = np.array([1.0, 2.5, 4.0, 6.0])
mu_ex = np.array([2.0, 5.0])
var_ex = np.array([2.25, 2.25])
pi_ex = np.array([0.5, 0.5])
# log component density for every (point, component) pair
log_dens = -0.5 * np.log(2 * np.pi * var_ex)[None, :] - (
x_ex[:, None] - mu_ex[None, :]
) ** 2 / (2 * var_ex[None, :])
log_joint = log_dens + np.log(pi_ex)[None, :]
ll_ex = logsumexp(log_joint, axis=1)
resp_ex = np.exp(log_joint - ll_ex[:, None])ConsoleOut [4]Expand
responsibilities (rows = observations): [[0.9656 0.0344] [0.7914 0.2086] [0.3392 0.6608] [0.0344 0.9656]] total log-likelihood before the M-step: -8.074
PythonIn [5]Expand
# one M-step
Nk = resp_ex.sum(axis=0)
mu_new = (resp_ex * x_ex[:, None]).sum(axis=0) / Nk
var_new = (resp_ex * (x_ex[:, None] - mu_new) ** 2).sum(axis=0) / Nk
pi_new = Nk / x_ex.size
log_dens_new = -0.5 * np.log(2 * np.pi * var_new)[None, :] - (
x_ex[:, None] - mu_new[None, :]
) ** 2 / (2 * var_new[None, :])
ll_new = logsumexp(log_dens_new + np.log(pi_new)[None, :], axis=1).sum()ConsoleOut [6]Expand
effective counts: [2.1306 1.8694] updated means: [2.116 4.81 ] updated variances: [1.428 1.826] updated weights: [0.533 0.467] log-likelihood after: -7.897 improvement: +0.177
The printed numbers agree with the rounded hand calculation to three decimal places, and the log-likelihood strictly increased. Further exact EM steps cannot lower it, but that alone does not guarantee a finite limiting fit. Our later implementation uses a small-change stopping rule and explicitly checks for a material likelihood decrease. The example therefore demonstrates the full rhythm of EM: infer soft labels, turn them into weighted estimates, and check that the objective moved in the promised direction.
Comments
Add to the conversation
A question, a correction, or an example from your own work.
No comments yet. Be the first to share your thoughts!