K-means is the first clustering algorithm most people learn. It works well when your clusters are spherical and evenly sized.
But real data rarely cooperates. When your clusters are elongated, overlapping, or noisy, K-means forces square pegs into round holes. The right algorithm depends on what your data actually looks like.
What you need
- Python 3 with scikit-learn, numpy, matplotlib
- Understanding that clustering is unsupervised (no labels)
- A dataset you want to group
K-means: centroid-based clustering
K-means partitions data into k clusters by minimizing the distance between points and their cluster centroid. It iterates until centroids stabilize.
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
X, _ = make_blobs(n_samples=300, centers=4, random_state=42)
kmeans = KMeans(n_clusters=4, random_state=42)
labels = kmeans.fit_predict(X)
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
plt.title('K-means on blobs')
plt.show()
K-means assumes clusters are convex and isotropic. It fails on crescents, rings, or clusters with very different densities.
DBSCAN: density-based clustering
DBSCAN groups points that are closely packed together and marks outliers as noise. It needs two parameters: eps (neighborhood radius) and min_samples.
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_moons
X, _ = make_moons(n_samples=300, noise=0.1, random_state=42)
dbscan = DBSCAN(eps=0.2, min_samples=5)
labels = dbscan.fit_predict(X)
n_clusters = len(set(labels)) - (1 if -1 in labels else 0)
print(f'Clusters found: {n_clusters}')
Output: Clusters found: 2
DBSCAN handles irregular shapes and noise. It struggles when clusters have very different densities because a single eps value cannot capture both.
Agglomerative clustering: hierarchy
Agglomerative clustering builds a tree of merges. Each point starts as its own cluster, and the closest pairs merge iteratively.
from sklearn.cluster import AgglomerativeClustering
from sklearn.datasets import make_moons
X, _ = make_moons(n_samples=300, noise=0.1, random_state=42)
agg = AgglomerativeClustering(n_clusters=2)
labels = agg.fit_predict(X)
print(f'Cluster counts: {len([l for l in labels if l==0])}, {len([l for l in labels if l==1])}')
Output: Cluster counts: 202, 98
Agglomerative clustering gives you a dendrogram to choose k after the fact. It is slower than K-means for large datasets.
Comparison
| Algorithm | Strengths | Weaknesses | Best for |
|---|---|---|---|
| K-means | Fast, simple | Assumes spherical clusters | Even, convex clusters |
| DBSCAN | Handles noise, arbitrary shapes | Sensitive to eps | Irregular shapes, outlier detection |
| Agglomerative | Dendrogram for k selection | Slow for large n | Small datasets, hierarchical structure |
Edge cases
- K-means: if k is wrong, results are meaningless. Use the elbow method or silhouette score to choose.
- DBSCAN: if eps is too small, everything is noise. If too large, everything is one cluster.
- Agglomerative: linkage choice (ward, complete, average) changes results. Ward works best for spherical clusters.
FAQ
Common questions about clustering algorithms in Python.
How do I choose k for K-means?
Run K-means for k from 2 to 10, plot inertia (sum of squared distances), and look for the elbow where adding more clusters gives diminishing returns.
When should I use DBSCAN over K-means?
Use DBSCAN when you do not know how many clusters there are, when clusters have irregular shapes, or when your data has noise and outliers.
Is Agglomerative clustering the same as hierarchical clustering?
Agglomerative is one type of hierarchical clustering (bottom-up). Divisive hierarchical clustering starts with one cluster and splits top-down, but it is rarely used because it is computationally expensive.

