Subroutine Logo
Subroutine
← Back to Playground AI & ML Intermediate

K-Means Clustering & Voronoi Space Partitioning

An interactive exploration of unsupervised machine learning, Expectation-Maximization (EM) iterations, and cluster boundary optimization.

Published: 2026-07-26
#AI & ML#Machine Learning#Clustering#K-Means#Unsupervised

Unsupervised machine learning algorithms find hidden patterns in unlabeled datasets. K-Means Clustering is one of the most popular clustering algorithms, partitioning NN observations into KK distinct clusters by minimizing the sum of squared distances between data points and their assigned cluster centroids.


1. Summary & Key Takeaways

  • Expectation-Maximization (EM): K-Means iterates between two alternating steps:
    1. E-Step (Assignment): Assign each data point xix_i to the nearest centroid μk\mu_k.
    2. M-Step (Update): Recalculate each centroid position μk\mu_k as the mean of all assigned points.
  • Objective Function (Inertia): Minimizes within-cluster sum-of-squares (WCSS): J=k=1KxSkxμk2J = \sum_{k=1}^{K} \sum_{x \in S_k} \| x - \mu_k \|^2
  • Voronoi Tessellation: The resulting cluster boundaries partition feature space into convex Voronoi cells.

2. Interactive K-Means Playground

Use the interactive 2D cluster simulator below to step through Expectation-Maximization iterations and watch centroid crosshairs adjust to point clusters!

Clustering Convergence

Click Step 1 Iteration repeatedly. Notice how centroids move rapidly during early iterations and quickly converge to stable cluster centers!

K-Means Clustering & Voronoi PartitionsUnsupervised ML

Alternate between Assigning Points (Expectation) and Updating Centroids (Maximization).

Next Algorithm Step:Step 1: Assign Points to Centroids
K-Means Clustering Implementation Code
kmeans_clustering.py
Python (NumPy)
# K-Means Clustering in Python using NumPy
import numpy as np

def k_means(X, k, max_iters=100):
    # 1. Randomly initialize k centroids
    centroids = X[np.random.choice(X.shape[0], k, replace=False)]
    
    for _ in range(max_iters):
        # Step 1: Assign points to nearest centroid (E-Step)
        distances = np.linalg.norm(X[:, np.newaxis] - centroids, axis=2)
        labels = np.argmin(distances, axis=1)
        
        # Step 2: Update centroids to mean of assigned points (M-Step)
        new_centroids = np.array([X[labels == i].mean(axis=0) for i in range(k)])
        
        if np.all(centroids == new_centroids):
            break
        centroids = new_centroids
        
    return centroids, labels

3. Mathematical Foundations

Given a set of NN data points (x1,x2,,xN)Rd(x_1, x_2, \dots, x_N) \in \mathbb{R}^d, K-Means partitions them into KK sets S={S1,S2,,SK}S = \{S_1, S_2, \dots, S_K\}:

Euclidean Distance Metric

d(x,μk)=j=1d(xjμk,j)2d(x, \mu_k) = \sqrt{\sum_{j=1}^{d} (x_j - \mu_{k,j})^2}

Centroid Update Rule

μk(t+1)=1Sk(t)xiSk(t)xi\mu_k^{(t+1)} = \frac{1}{|S_k^{(t)}|} \sum_{x_i \in S_k^{(t)}} x_i


4. Clustering Algorithm Comparison

AlgorithmTypeComplexityHandles Non-Convex Shapes?
K-MeansCentroid-basedO(NKId)O(N \cdot K \cdot I \cdot d)No (Prefers spherical clusters)
DBSCANDensity-basedO(NlogN)O(N \log N)Yes (Arbitrary cluster shapes)
HierarchicalTree-basedO(N3)O(N^3)Yes (Dendrogram hierarchy)