2323"""
2424
2525import warnings
26- from typing import TypeAlias
2726
2827import matplotlib .pyplot as plt
2928import numpy as np
3332warnings .filterwarnings ("ignore" )
3433
3534TAG = "GAUSSIAN-MIXTURE/ "
36- FloatArray : TypeAlias = NDArray [np .float64 ]
3735
3836
3937class GaussianMixture :
@@ -54,12 +52,12 @@ def __init__(
5452 self .seed : int | None = seed
5553
5654 # parameters
57- self .weights_ : FloatArray | None = None
58- self .means_ : FloatArray | None = None
55+ self .weights_ : NDArray [ np . float64 ] | None = None
56+ self .means_ : NDArray [ np . float64 ] | None = None
5957 self .covariances_ : NDArray [np .float64 ] | None = None
6058 self .log_likelihoods_ : list [float ] = []
6159
62- def _initialize_parameters (self , data : FloatArray ) -> None :
60+ def _initialize_parameters (self , data : NDArray [ np . float64 ] ) -> None :
6361 """Randomly initialize means, covariances, and mixture weights.
6462
6563 Examples
@@ -86,7 +84,7 @@ def _initialize_parameters(self, data: FloatArray) -> None:
8684 )
8785 self .weights_ = np .ones (self .n_components ) / self .n_components
8886
89- def _e_step (self , data : FloatArray ) -> FloatArray :
87+ def _e_step (self , data : NDArray [ np . float64 ] ) -> NDArray [ np . float64 ] :
9088 """Compute responsibilities (posterior probabilities).
9189
9290 Examples
@@ -123,7 +121,11 @@ def _e_step(self, data: FloatArray) -> FloatArray:
123121 responsibilities /= responsibilities .sum (axis = 1 , keepdims = True )
124122 return responsibilities
125123
126- def _m_step (self , data : FloatArray , responsibilities : FloatArray ) -> None :
124+ def _m_step (
125+ self ,
126+ data : NDArray [np .float64 ],
127+ responsibilities : NDArray [np .float64 ],
128+ ) -> None :
127129 """Update weights, means, and covariances.
128130
129131 Note: assumes the model parameters are already initialized.
@@ -161,7 +163,7 @@ def _m_step(self, data: FloatArray, responsibilities: FloatArray) -> None:
161163 # Add small regularization term for numerical stability
162164 covariances [k ] += np .eye (n_features ) * 1e-6
163165
164- def _compute_log_likelihood (self , data : FloatArray ) -> float :
166+ def _compute_log_likelihood (self , data : NDArray [ np . float64 ] ) -> float :
165167 """Compute total log-likelihood of the model.
166168
167169 Note: assumes the model parameters are already initialized.
@@ -196,7 +198,7 @@ def _compute_log_likelihood(self, data: FloatArray) -> float:
196198 log_likelihood = np .sum (np .log (np .sum (total_pdf , axis = 1 ) + 1e-12 ))
197199 return log_likelihood
198200
199- def fit (self , data : FloatArray ) -> None :
201+ def fit (self , data : NDArray [ np . float64 ] ) -> None :
200202 """Fit the Gaussian Mixture Model to data using the EM algorithm.
201203
202204 Examples
@@ -235,7 +237,7 @@ def fit(self, data: FloatArray) -> None:
235237
236238 print (f"{ TAG } Training complete. Final log-likelihood: { log_likelihood :.4f} " )
237239
238- def predict (self , data : FloatArray ) -> NDArray [np .int_ ]:
240+ def predict (self , data : NDArray [ np . float64 ] ) -> NDArray [np .int_ ]:
239241 """Predict cluster assignment for each data point.
240242
241243 Note: assumes the model parameters are already initialized.
@@ -255,7 +257,7 @@ def predict(self, data: FloatArray) -> NDArray[np.int_]:
255257 responsibilities = self ._e_step (data )
256258 return np .argmax (responsibilities , axis = 1 )
257259
258- def plot_results (self , data : FloatArray ) -> None :
260+ def plot_results (self , data : NDArray [ np . float64 ] ) -> None :
259261 """Visualize GMM clustering results (2D only).
260262
261263 Note: This method assumes self.means_ is initialized.
0 commit comments