Patterns without labels

K-Means: Find the Groups

Place the centers, assign the points and update the means. Watch the groups emerge one step at a time.

10 min to exploreMachine Learning · CPTR 235 · BSAD 720
01 / UNDERSTAND

What changes when you change k, the starting centers or the scale of a feature?

K-means alternates nearest-center assignment and mean updates. Its distance measure makes initialization and feature scale consequential; clusters need interpretation in context.

02 / EXPLORE

Make a prediction.
Then move a control.

36 invented observationsEuclidean distance · 2 features
01 / Assign

Choose a starting configuration, then assign each observation to its nearest centroid.

K-means observations and centroidsUse the controls to assign points and update their centroids. Enter centroid coordinates in the controls below as a keyboard equivalent to clicking the plot.
0Centroid updates
—Within-cluster SSE
Not assignedCurrent state

Two repeating steps: assign by distance, then move each centroid to the mean of its assigned observations.

Place a starting centroid

Select one, then click the plot or enter coordinates. Changing a centroid restarts the steps.

Inspect coordinates and cluster membership
Current feature coordinates
ObservationFeature 1Feature 2Cluster

An educational experiment with illustrative data. The controls run locally in your browser.

03 / SEE THE CODE

The idea,
in Python.

A compact implementation of the core concept. Open the code when you are ready to connect the visual to the algorithm.

Open the core implementation Python ↗
Standalone example · illustrative valuesDownload .py
import numpy as np

X = np.array([[1., 1.], [1., 2.], [4., 4.], [5., 4.]])
centers = X[[0, 2]].copy()

for _ in range(20):
    # Assign each point to its nearest center.
    distance2 = ((X[:, None, :] - centers[None, :, :]) ** 2).sum(axis=2)
    labels = distance2.argmin(axis=1)
    # Keep an empty cluster's previous center.
    updated = np.array([
        X[labels == j].mean(axis=0) if np.any(labels == j) else centers[j]
        for j in range(len(centers))
    ])
    if np.allclose(updated, centers):
        break
    centers = updated

print(centers)
04 / TRY IT

Explain the change.
Test your reasoning.

  1. Run the same points with two different starting configurations.
  2. Increase k. Does a lower within-cluster distance prove a better explanation?
  3. Change the scale of one feature, then compare with standardized features.
← All visual labsNext: Draw the Best-Fit Line

Find your next idea.

Search across courses, research, projects, and resources.

Ideas, connected.esc to close