Playground
Two hidden groups in 200 ratings
This is the notebook's experiment, live. Its 200 ratings come from two kinds of viewer, but nothing says who is who. Press play to watch EM find the groups one iteration at a time, or change the data, the starting guess and the stopping rule. The pitfalls page covers the ways this can go wrong.
t = 15. Stopped at the cap of 15 iterations, still improving by 0.0293 per step (not converged).
t = 15Stopped at the cap of 15 iterations, still improving by 0.0293 per step (not converged).
- Component 1
- Component 2
- Mixture
- True mixture
Points under the axis are coloured by responsibility (teal = component 1, coral = component 2) and drawn as circles or triangles by whichever is larger.
Log-likelihood by iteration
never decreased ✓EM's guarantee: every iteration leaves the log-likelihood the same or higher. The check above runs on every trace you make.
start ℓ = -536.90 · after iteration 1 = -425.50 · last = -416.51 (plotted from iteration 1, like the notebook's convergence plot)
Explain this iterationoptional · AI · your own key
Sends this iteration's numbers (parameters before and after, responsibilities, log-likelihood, stopping rule) and a fixed description of the page and data set, with no personal data, to Anthropic, from your browser. What is sent
Parameters at t = 15
| component | π | μ | σ | matches true group |
|---|---|---|---|---|
| 1 | 0.344true 0.40 | 4.022true 4.00 | 1.249true 1.50 | Romance lovers |
| 2 | 0.656true 0.60 | 7.361true 7.50 | 1.273true 1.20 | Sci-fi lovers |
Labels switched. Component 1 ended up describing romance lovers, the group the data calls group 2. EM's numbering is arbitrary, so every comparison here first matches components to groups by their means.
Classification accuracy
- matched by mean
- 90.5%
- 95% CI 85.6% to 93.8%
- as the notebook computes it
- 90.5%
- 95% CI 85.6% to 93.8%
The notebook scores (γ₁ > 0.5) against true labels where 1 means group 2, so its number is only right when the labels have switched. Here they agree. Responsibilities are taken from the E-step of iteration 15, like the notebook's em.gamma1. The intervals are Wilson 95% intervals over the 200 ratings. This is in-sample accuracy: the same ratings fitted the model, so an interval reflects which users happened to be drawn given the fitted rule, not the uncertainty of the fit itself.
Classify a new rating
The notebook's last cell asks which group a user who rates a film 8.5 belongs to, reading component 1 as “Sci-fi lover”.
P(component 1 | x) = 0.001
P(component 2 | x) = 0.999
- as the notebook would print it
- “likely a ROMANCE LOVER”
- after matching labels by mean
- Sci-fi lover
Parity with the original notebook
matches ✓This run starts from the notebook's own random draw. Comparing this browser's TypeScript trace with the trace exported from the notebook, iterations 1 to 15 agree to within 2.8 × 10⁻¹³ (largest absolute difference in any π, μ, σ or log-likelihood). The console below is regenerated from this run and is identical, character for character, to what the notebook printed.
Replay the notebook's console output
Starting EM Algorithm...
==================================================
--- ITERATION 1 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.412
Average P(group 2): 0.588
=== M-STEP ===
Mixing proportions: π₁ = 0.412 (was 0.500)
π₂ = 0.588 (was 0.500)
Means: μ₁ = 4.536 (was 5.121)
μ₂ = 7.386 (was 7.532)
Std devs: σ₁ = 1.220 (was 0.667)
σ₂ = 1.616 (was 1.239)
Log-likelihood: -425.50
--- ITERATION 2 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.381
Average P(group 2): 0.619
=== M-STEP ===
Mixing proportions: π₁ = 0.381 (was 0.412)
π₂ = 0.619 (was 0.588)
Means: μ₁ = 4.340 (was 4.536)
μ₂ = 7.366 (was 7.386)
Std devs: σ₁ = 1.424 (was 1.220)
σ₂ = 1.384 (was 1.616)
Log-likelihood: -417.92
Improvement: 7.5786
--- ITERATION 3 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.375
Average P(group 2): 0.625
=== M-STEP ===
Mixing proportions: π₁ = 0.375 (was 0.381)
π₂ = 0.625 (was 0.619)
Means: μ₁ = 4.264 (was 4.340)
μ₂ = 7.383 (was 7.366)
Std devs: σ₁ = 1.425 (was 1.424)
σ₂ = 1.312 (was 1.384)
Log-likelihood: -417.22
Improvement: 0.6936
--- ITERATION 4 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.374
Average P(group 2): 0.626
=== M-STEP ===
Mixing proportions: π₁ = 0.374 (was 0.375)
π₂ = 0.626 (was 0.625)
Means: μ₁ = 4.223 (was 4.264)
μ₂ = 7.400 (was 7.383)
Std devs: σ₁ = 1.391 (was 1.425)
σ₂ = 1.283 (was 1.312)
Log-likelihood: -416.98
Improvement: 0.2434
--- ITERATION 5 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.372
Average P(group 2): 0.628
=== M-STEP ===
Mixing proportions: π₁ = 0.372 (was 0.374)
π₂ = 0.628 (was 0.626)
Means: μ₁ = 4.193 (was 4.223)
μ₂ = 7.409 (was 7.400)
Std devs: σ₁ = 1.361 (was 1.391)
σ₂ = 1.269 (was 1.283)
Log-likelihood: -416.86
Improvement: 0.1227
--- ITERATION 6 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.370
Average P(group 2): 0.630
=== M-STEP ===
Mixing proportions: π₁ = 0.370 (was 0.372)
π₂ = 0.630 (was 0.628)
Means: μ₁ = 4.169 (was 4.193)
μ₂ = 7.413 (was 7.409)
Std devs: σ₁ = 1.339 (was 1.361)
σ₂ = 1.261 (was 1.269)
Log-likelihood: -416.79
Improvement: 0.0659
--- ITERATION 7 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.368
Average P(group 2): 0.632
=== M-STEP ===
Mixing proportions: π₁ = 0.368 (was 0.370)
π₂ = 0.632 (was 0.630)
Means: μ₁ = 4.149 (was 4.169)
μ₂ = 7.411 (was 7.413)
Std devs: σ₁ = 1.323 (was 1.339)
σ₂ = 1.257 (was 1.261)
Log-likelihood: -416.75
Improvement: 0.0421
--- ITERATION 8 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.365
Average P(group 2): 0.635
=== M-STEP ===
Mixing proportions: π₁ = 0.365 (was 0.368)
π₂ = 0.635 (was 0.632)
Means: μ₁ = 4.131 (was 4.149)
μ₂ = 7.408 (was 7.411)
Std devs: σ₁ = 1.310 (was 1.323)
σ₂ = 1.257 (was 1.257)
Log-likelihood: -416.72
Improvement: 0.0332
--- ITERATION 9 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.362
Average P(group 2): 0.638
=== M-STEP ===
Mixing proportions: π₁ = 0.362 (was 0.365)
π₂ = 0.638 (was 0.635)
Means: μ₁ = 4.114 (was 4.131)
μ₂ = 7.403 (was 7.408)
Std devs: σ₁ = 1.300 (was 1.310)
σ₂ = 1.257 (was 1.257)
Log-likelihood: -416.69
Improvement: 0.0302
--- ITERATION 10 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.359
Average P(group 2): 0.641
=== M-STEP ===
Mixing proportions: π₁ = 0.359 (was 0.362)
π₂ = 0.641 (was 0.638)
Means: μ₁ = 4.098 (was 4.114)
μ₂ = 7.396 (was 7.403)
Std devs: σ₁ = 1.290 (was 1.300)
σ₂ = 1.259 (was 1.257)
Log-likelihood: -416.66
Improvement: 0.0292
--- ITERATION 11 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.356
Average P(group 2): 0.644
=== M-STEP ===
Mixing proportions: π₁ = 0.356 (was 0.359)
π₂ = 0.644 (was 0.641)
Means: μ₁ = 4.083 (was 4.098)
μ₂ = 7.390 (was 7.396)
Std devs: σ₁ = 1.282 (was 1.290)
σ₂ = 1.262 (was 1.259)
Log-likelihood: -416.63
Improvement: 0.0290
--- ITERATION 12 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.353
Average P(group 2): 0.647
=== M-STEP ===
Mixing proportions: π₁ = 0.353 (was 0.356)
π₂ = 0.647 (was 0.644)
Means: μ₁ = 4.067 (was 4.083)
μ₂ = 7.383 (was 7.390)
Std devs: σ₁ = 1.273 (was 1.282)
σ₂ = 1.264 (was 1.262)
Log-likelihood: -416.60
Improvement: 0.0290
--- ITERATION 13 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.350
Average P(group 2): 0.650
=== M-STEP ===
Mixing proportions: π₁ = 0.350 (was 0.353)
π₂ = 0.650 (was 0.647)
Means: μ₁ = 4.052 (was 4.067)
μ₂ = 7.376 (was 7.383)
Std devs: σ₁ = 1.265 (was 1.273)
σ₂ = 1.267 (was 1.264)
Log-likelihood: -416.57
Improvement: 0.0291
--- ITERATION 14 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.347
Average P(group 2): 0.653
=== M-STEP ===
Mixing proportions: π₁ = 0.347 (was 0.350)
π₂ = 0.653 (was 0.650)
Means: μ₁ = 4.037 (was 4.052)
μ₂ = 7.369 (was 7.376)
Std devs: σ₁ = 1.257 (was 1.265)
σ₂ = 1.270 (was 1.267)
Log-likelihood: -416.54
Improvement: 0.0292
--- ITERATION 15 ---
=== E-STEP ===
Posterior probabilities computed for 200 users
Average P(group 1): 0.344
Average P(group 2): 0.656
=== M-STEP ===
Mixing proportions: π₁ = 0.344 (was 0.347)
π₂ = 0.656 (was 0.653)
Means: μ₁ = 4.022 (was 4.037)
μ₂ = 7.361 (was 7.369)
Std devs: σ₁ = 1.249 (was 1.257)
σ₂ = 1.273 (was 1.270)
Log-likelihood: -416.51
Improvement: 0.0293
==================================================
FINAL RESULTS
==================================================
Estimated Parameters:
pi1: 0.344
pi2: 0.656
mu1: 4.022
mu2: 7.361
sigma1: 1.249
sigma2: 1.273
True Parameters:
pi1: 0.600
pi2: 0.400
mu1: 7.500
mu2: 4.000
sigma1: 1.200
sigma2: 1.500
Full trace (15 iterations)
| t | log-lik | Δ | π₁ | μ₁ | μ₂ | σ₁ | σ₂ |
|---|---|---|---|---|---|---|---|
| 1 | -425.4955 | 0.4120 | 4.5363 | 7.3864 | 1.2201 | 1.6163 | |
| 2 | -417.9169 | 7.57856 | 0.3813 | 4.3404 | 7.3657 | 1.4239 | 1.3840 |
| 3 | -417.2233 | 0.69363 | 0.3754 | 4.2644 | 7.3831 | 1.4245 | 1.3118 |
| 4 | -416.9799 | 0.24336 | 0.3738 | 4.2229 | 7.3999 | 1.3907 | 1.2835 |
| 5 | -416.8572 | 0.12273 | 0.3722 | 4.1931 | 7.4094 | 1.3612 | 1.2687 |
| 6 | -416.7913 | 0.06591 | 0.3701 | 4.1693 | 7.4125 | 1.3393 | 1.2608 |
| 7 | -416.7491 | 0.04213 | 0.3676 | 4.1492 | 7.4114 | 1.3231 | 1.2573 |
| 8 | -416.7159 | 0.03324 | 0.3649 | 4.1312 | 7.4077 | 1.3104 | 1.2565 |
| 9 | -416.6857 | 0.03018 | 0.3620 | 4.1144 | 7.4025 | 1.2998 | 1.2574 |
| 10 | -416.6565 | 0.02923 | 0.3590 | 4.0984 | 7.3964 | 1.2904 | 1.2592 |
| 11 | -416.6275 | 0.02899 | 0.3561 | 4.0828 | 7.3897 | 1.2817 | 1.2616 |
| 12 | -416.5985 | 0.02900 | 0.3531 | 4.0675 | 7.3828 | 1.2734 | 1.2643 |
| 13 | -416.5694 | 0.02908 | 0.3501 | 4.0522 | 7.3757 | 1.2653 | 1.2672 |
| 14 | -416.5402 | 0.02919 | 0.3471 | 4.0371 | 7.3685 | 1.2573 | 1.2703 |
| 15 | -416.5109 | 0.02931 | 0.3441 | 4.0219 | 7.3613 | 1.2492 | 1.2734 |