ML Models From Scratch ยท Hard
Gaussian Mixture Model
Fit a diagonal-covariance Gaussian mixture model with expectation-maximization.
Task
Implement class GaussianMixtureModel(initial_weights, initial_means, initial_variances, max_iterations, tolerance, epsilon). Implement a diagonal-covariance Gaussian mixture model trained with expectation-maximization, including stable responsibilities, parameter updates, convergence tracking, probabilities, predictions, and total log-likelihood.
Requirements
- Copy initial_weights, initial_means, and initial_variances so caller-owned arrays are not mutated.
- Clamp every variance to at least epsilon during initialization and after each M-step.
- e_step(x) computes responsibilities in log space and returns one normalized row per example.
- m_step(x, responsibilities) updates weights, means, and diagonal variances from component effective counts.
- score(x) returns the total data log-likelihood using a stable log-sum-exp calculation.
- fit(x) performs at most max_iterations E-steps and M-steps and appends the post-update total log-likelihood to log_likelihood_history.
- After at least two updates, converge when the absolute change in consecutive log-likelihood values is less than or equal to tolerance.
- Store n_iterations, converged, and final responsibilities after fitting.
- predict_proba(x) returns responsibilities and predict(x) returns the highest-responsibility component; ties choose the lowest component index.
Example
model = GaussianMixtureModel(
np.array([0.5, 0.5]),
np.array([[0.0], [10.0]]),
np.array([[2.0], [2.0]]),
max_iterations=20,
tolerance=1e-8,
epsilon=1e-6,
)
model.fit(np.array([[0.0], [2.0], [8.0], [10.0]]))
model.predict(np.array([[1.0], [9.0], [5.0]]))
# array([0, 1, 0])