Without labels, you find structure instead of predicting a target. Cluster similar rows with K-Means and compress features with PCA to discover what the data contains.
Why: when there are no labels, clustering groups similar rows so you can discover segments — customer types, anomaly groups, natural categories. When: K-Means for roughly spherical, similarly-sized clusters; it needs you to pick k. Where: scale features first, since K-Means is distance-based.
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
X_s = StandardScaler().fit_transform(X) # distance-based -> scale first
km = KMeans(n_clusters=3, n_init=10, random_state=42)
labels = km.fit_predict(X_s) # cluster id per row
print("cluster sizes:", [int((labels == i).sum()) for i in range(3)])Why: K-Means makes you choose the number of clusters, and picking it wrong gives meaningless groups — the elbow (inertia) and silhouette score guide the choice. When: sweep a range of k and look for the elbow or the peak silhouette. Where: there is rarely one "true" k; use these as evidence, not proof.
from sklearn.metrics import silhouette_score
for k in range(2, 7):
km = KMeans(n_clusters=k, n_init=10, random_state=42).fit(X_s)
sil = silhouette_score(X_s, km.labels_)
print(f"k={k} inertia={km.inertia_:.0f} silhouette={sil:.3f}")
# Pick k at the inertia "elbow" and a high silhouette.Why: K-Means is not always right — DBSCAN finds arbitrary shapes and detects outliers, and PCA compresses features into a few informative dimensions (as seen in the preprocessing course). When: DBSCAN for non-spherical clusters or noise; PCA to reduce and visualize. Where: unsupervised results need human interpretation — the algorithm finds structure, you decide if it means anything.
from sklearn.cluster import DBSCAN
from sklearn.decomposition import PCA
# DBSCAN: density-based, finds arbitrary shapes, labels outliers as -1.
db = DBSCAN(eps=0.5, min_samples=5).fit(X_s)
print("clusters found:", len(set(db.labels_)) - (1 if -1 in db.labels_ else 0))
# PCA to 2D for visual inspection of the clusters (see preprocessing course).
coords = PCA(n_components=2).fit_transform(X_s)