Soft clustering with probabilities
Where KMeans gives a hard assignment, a Gaussian mixture gives a probability per component — so you can see which rows are genuinely ambiguous.
from sklearn.mixture import GaussianMixture
import numpy as np
gm = GaussianMixture(n_components=4, covariance_type="full",
n_init=5, random_state=42).fit(X_scaled)
proba = gm.predict_proba(X_scaled)
labels = gm.predict(X_scaled)
# Rows where the top probability is low sit between segments.
# In customer segmentation those are often the interesting ones.
confidence = proba.max(axis=1)
print("ambiguous rows:", (confidence < 0.6).sum())
# BIC chooses the number of components without needing labels
for k in range(2, 8):
g = GaussianMixture(k, random_state=42).fit(X_scaled)
print(f"k={k} BIC={g.bic(X_scaled):12.0f}") # lower is better