k-means made you pick k. This doesn't.
Build the whole tree of groupings, from every point alone to one big group — then cut it wherever the structure tells you to.
Start with every point as its own cluster. Then repeat until one is left:
Twenty-nine merges for thirty points. No k, no centroids, no seed.
30 points, three blobs from make_blobs, no labels. Small on purpose — a
dendrogram draws one leaf per point.
How far apart are two clusters? Pick a rule:
dsingle(A,B)=a∈A,b∈Bmin∥xa−xb∥ dcomplete(A,B)=a∈A,b∈Bmax∥xa−xb∥ daverage(A,B)=∣A∣∣B∣1a∈A∑b∈B∑∥xa−xb∥Single chains, complete makes tight balls, average is the safe first try.
Points condense on top; the dendrogram builds bar by bar below. Every frame is one real merge. Red links the two clusters fusing this step.
Low merges happen inside blobs; then the tree jumps a big gap to fuse them. That gap is where k=3 comes from — you didn't pick it, the heights announced it.
The dendrogram, colored by the k=3 clusters, gray between-blob merges above, the cut line dropped into the empty gap (height 3.92, between 1.90 and 5.94):
Our cut at k=3 vs sklearn.cluster.AgglomerativeClustering. Merge heights match
scipy to machine epsilon; flat labels match sklearn; both recover the true blobs.
Every adjusted Rand index is 1.0.