Menu
CoddyTech

K-Means by Hand

Part of the Unsupervised Learning section of Coddy's Machine Learning journey. Lesson 3 of 51.

K-means repeats a round of two steps to find k clusters. Assign: each point joins its nearest center. Move: each center goes to its points' mean. Three ice cream carts:

150 towels on a beach in three crowds, left, middle and right. Three carts start close together near the middle; black lines trace each cart's path round by round to a star in the middle of its own crowd

One round in NumPy, where dists is a distance table with one column per center:

labels = dists.argmin(axis=1)  # assign
for c in range(k):
    centers[c] = X[labels == c].mean(axis=0)  # move

argmin(axis=1) gives each row's smallest column: its nearest center. Round after round the centers settle; when none moves, k-means is done.

challenge icon

Challenge

Easy

A T-shirt maker refits its sizes S, M and L to today's customers. Its old size chart starts the centers, distances(people, centers) gives the distance table, and the program reads how many rounds to run.

  1. Each round: assign every person, then move every center.
  2. Print each size's center and how many people it got in the last round, as below.

For another maker:

Rounds run: 2
S: chest 87.3 cm, length 65.1 cm, 14 people
M: chest 95.0 cm, length 68.9 cm, 31 people
L: chest 104.8 cm, length 72.6 cm, 45 people

Try it yourself

import numpy as np

# Don't change the lines below
rng = np.random.default_rng(12)
chest = np.concatenate([rng.normal(88, 3, 30), rng.normal(98, 3.5, 35), rng.normal(110, 4, 25)])
length = np.concatenate([rng.normal(66, 1.8, 30), rng.normal(70, 2, 35), rng.normal(75, 2.2, 25)])
# 90 customers, one row each: chest and length in cm
people = np.round(np.column_stack([chest, length]), 1)

# The old size chart starts the centers: S, M, L
sizes = ["S", "M", "L"]
centers = np.array([[85.0, 64.0], [90.0, 67.0], [96.0, 69.0]])
rounds = int(input())


# Distance table: one row per person, one column per center
def distances(X, centers):
    table = np.zeros((len(X), len(centers)))
    for c in range(len(centers)):
        table[:, c] = np.sqrt(((X - centers[c]) ** 2).sum(axis=1))
    return table


# Write your code below
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Unsupervised Learning

Practice on your own: Online Python compiler