Clustering
Cluster Inertia
Compute k-means inertia: sum of squared distances from each point to its
assigned centroid. Loop over points, look up the centroid by assignment index,
compute squared Euclidean distance, accumulate. Library: NumPy fancy indexing
centroids[assignments] broadcasts centroids per point for a vectorized diff.
RESULT: inertia (rounded).
By hand
points=[[1,2],[2,1],[1,3],[7,6],[8,7],[6,8]], assignments=[0,0,0,1,1,1], centroids=[[1,1],[7,7]]. Sq-dists: (0+1)+(1+0)+(0+4)+(0+1)+(1+0)+(1+1) = 1+1+4+1+1+2 = 10.
naive.py
Replay: real traced execution (multi-file project)
points = [[1,2],[2,1],[1,3],[7,6],[8,7],[6,8]]
assignments = [0, 0, 0, 1, 1, 1]
centroids = [[1, 1], [7, 7]]
inertia = 0.0
for i in range(len(points)):
cx = centroids[assignments[i]][0]
cy = centroids[assignments[i]][1]
dx = points[i][0] - cx
dy = points[i][1] - cy
inertia = inertia + dx*dx + dy*dy
print('RESULT:', round(inertia, 4))
points ← [[1, 2], [2, 1], [1, 3], [7, 6], [8, 7], [6, 8]]
1points = [[1,2],[2,1],[1,3],[7,6],[8,7],[6,8]]2assignments = [0, 0, 0, 1, 1, 1]values this step[[1, 2], [2, 1], [1, 3], [7, 6], [8, 7], [6, 8]]pointsassignments ← [0, 0, 0, 1, 1, 1]
1points = [[1,2],[2,1],[1,3],[7,6],[8,7],[6,8]]2assignments = [0, 0, 0, 1, 1, 1]3centroids = [[1, 1], [7, 7]]values this step[0, 0, 0, 1, 1, 1]assignmentscentroids ← [[1, 1], [7, 7]]
2assignments = [0, 0, 0, 1, 1, 1]3centroids = [[1, 1], [7, 7]]4inertia = 0.0values this step[[1, 1], [7, 7]]centroidsinertia ← 0.0
3centroids = [[1, 1], [7, 7]]4inertia = 0.05for i in range(len(points)):values this step0.0inertiai ← 0, cx ← 1, cy ← 1, dx ← 0, dy ← 1, inertia ← 1.0
pass 1 of 64inertia = 0.05for i in range(len(points)):6 cx = centroids[assignments[i]][0]7 cy = centroids[assignments[i]][1]8 dx = points[i][0] - cx9 dy = points[i][1] - cy10 inertia = inertia + dx*dx + dy*dy11print('RESULT:', round(inertia, 4))values this step0i1cx1cy0dx1dy0.0 → 1.0inertiaAll 6 passes — pass 1 is the card above pass icxcydxdyinertia1 0 1 1 0 1 0.0 → 1.0 2 0 → 1 — — 0 → 1 1 → 0 1.0 → 2.0 3 1 → 2 — — 1 → 0 0 → 2 2.0 → 6.0 4 2 → 3 1 → 7 1 → 7 — 2 → -1 6.0 → 7.0 5 3 → 4 — — 0 → 1 -1 → 0 7.0 → 8.0 6 4 → 5 — — 1 → -1 0 → 1 8.0 → 10.0 for i in range(len(points)):
4inertia = 0.05for i in range(len(points)):6 cx = centroids[assignments[i]][0]stdout ← RESULT: 10.0
10 inertia = inertia + dx*dx + dy*dy11print('RESULT:', round(inertia, 4))values this stepRESULT: 10.0stdout
With NumPy
centroids[assignments] selects the centroid row for each point; subtracting
gives per-point delta vectors; squaring and summing over axis=1 yields squared
distances; a final np.sum gives inertia.
library.py
import numpy as np
from dalib.display import set_display
set_display()
points = np.array([[1,2],[2,1],[1,3],[7,6],[8,7],[6,8]], dtype=float)
assignments = np.array([0, 0, 0, 1, 1, 1])
centroids = np.array([[1.0, 1.0], [7.0, 7.0]])
deltas = points - centroids[assignments]
sq_dists = np.sum(deltas**2, axis=1)
print('sq_dists:', [round(float(v), 4) for v in sq_dists])
inertia = float(np.sum(sq_dists))
print('RESULT:', round(inertia, 4))
sq_dists: [1.0, 1.0, 4.0, 1.0, 1.0, 2.0]
RESULT: 10.0
Implementation notes
centroids[assignments[i]]uses the assignment as an integer index into the centroid list — no if/else branching needed per cluster.- Squared Euclidean distance (no sqrt) matches the metric k-means minimizes; inertia and the assignment loop are consistent.
- Cross-reference:
kmeans-one-iteration(this chapter) for centroids that minimize inertia after one full assign+update cycle.