Loading...
Loading...
Loading Curriculum...
Loading Subject...
Loading Topic...
Loading Lesson...
Loading Lab...
K-means repeatedly assigns points to the closest centroid, then moves centroids to the mean of their assigned points. Watch inertia decrease as clusters stabilize.
Group similar things.
Clustering finds hidden groups in data when you don’t have labels. Instead of predicting “spam/not spam”, you discover “these points behave similarly”.
Think of sorting mixed-colored balls into boxes. You don’t know the correct labels—so you keep moving the “center of each box” until balls settle into the nearest one.
Assignment ↔ Update.
Each point joins the closest centroid.
Each centroid moves to the mean of its group.
Inertia acts like an energy score you’re lowering.
Because “similarity” needs a distance rule.
Clustering starts by assuming you can measure how “close” two points are. In K-means, that’s usually Euclidean distance.
A centroid is the center of a cluster (mean location). K-means moves centers until they match the points assigned to them.
It grows when points are far from their cluster centers. The algorithm tries to push points closer.
Step through assign → update and watch centroids converge.
Loading Lab...
Math that matches what you see moving.
Here, is 1 if point is assigned to centroid . Inertia chart is this energy—lower means tighter groups.
Why teams use unlabeled grouping.
Where each centroid wins.
Copy-friendly Python example with the same logic as the lab.
# K-Means clustering (from scratch)
import random
import math
def dist2(a, b):
return (a[0]-b[0])**2 + (a[1]-b[1])**2
def kmeans(points, k, steps, seed=0):
random.seed(seed)
# init: pick random points as centroids
centroids = random.sample(points, k)
for _ in range(steps):
# 1) assign each point to nearest centroid
assign = []
for p in points:
best = 0
bestD = float("inf")
for j in range(k):
d = dist2(p, centroids[j])
if d < bestD:
bestD = d
best = j
assign.append(best)
# 2) update centroids (mean of assigned points)
nextC = [[0.0, 0.0] for _ in range(k)]
counts = [0 for _ in range(k)]
for (p, a) in zip(points, assign):
nextC[a][0] += p[0]
nextC[a][1] += p[1]
counts[a] += 1
for j in range(k):
if counts[j] > 0:
centroids[j] = [nextC[j][0]/counts[j], nextC[j][1]/counts[j]]
return centroids, assignSpot the symptoms in the visualization.
Everything important, quickly.