Skip to content
EM lab, home

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.

speed

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
00.10.20.3densityμ₁ 4.02μ₂ 7.36

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.

iterationℓ(θ)

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
10.344true 0.404.022true 4.001.249true 1.50Romance lovers
20.656true 0.607.361true 7.501.273true 1.20Sci-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
em.fit(max_iterations=15, tolerance=1e-4), regenerated
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)
tlog-likΔπ₁μ₁μ₂σ₁σ₂
1-425.49550.41204.53637.38641.22011.6163
2-417.91697.578560.38134.34047.36571.42391.3840
3-417.22330.693630.37544.26447.38311.42451.3118
4-416.97990.243360.37384.22297.39991.39071.2835
5-416.85720.122730.37224.19317.40941.36121.2687
6-416.79130.065910.37014.16937.41251.33931.2608
7-416.74910.042130.36764.14927.41141.32311.2573
8-416.71590.033240.36494.13127.40771.31041.2565
9-416.68570.030180.36204.11447.40251.29981.2574
10-416.65650.029230.35904.09847.39641.29041.2592
11-416.62750.028990.35614.08287.38971.28171.2616
12-416.59850.029000.35314.06757.38281.27341.2643
13-416.56940.029080.35014.05227.37571.26531.2672
14-416.54020.029190.34714.03717.36851.25731.2703
15-416.51090.029310.34414.02197.36131.24921.2734