import numpy as np
from sklearn.datasets import load_digits
from sklearn.mixture import GaussianMixture
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from scipy.stats import mode

digits = load_digits()
X = digits.data
y = digits.target

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

pca = PCA(n_components=20)
X_pca = pca.fit_transform(X_scaled)

gmm = GaussianMixture(n_components=10, random_state=42)
gmm.fit(X_pca)

clusters = gmm.predict(X_pca)

labels = np.zeros_like(clusters)

for i in range(10):
    mask = (clusters == i)
    if np.sum(mask) == 0:
        continue
    labels[mask] = mode(y[mask])[0]

accuracy = np.mean(labels == y)

print(accuracy)
      
print("\nCLUSTER DISTRIBUTION:")
for i in range(10):
    print(f"Cluster {i}: {np.sum(clusters == i)} samples")

print("\nFIRST 20 PREDICTIONS:")
for i in range(20):
    print(f"Actual: {y[i]}  |  Predicted: {labels[i]}")

print("\nFINAL ACCURACY:")
print(f"Accuracy = {accuracy * 100:.2f}%")



import matplotlib.pyplot as plt

for i in range(10):
    cluster_indices = np.where(clusters == i)[0]

    if len(cluster_indices) == 0:
        continue

    plt.figure(figsize=(6, 2))
    plt.suptitle(f"Cluster {i} Samples")

    # show first 5 images from cluster
    for j in range(min(5, len(cluster_indices))):
        idx = cluster_indices[j]

        plt.subplot(1, 5, j + 1)
        plt.imshow(digits.images[idx])
        plt.title(f"{labels[idx]}")
        plt.axis('off')

    plt.show() 