AI Concepts in Python

Cosine Similarity and k-Means Clustering in Python

Unsupervised learning finds structure in data without labels. Cosine similarity measures how alike two vectors are, and k-means groups points into clusters around centres it learns.

The concept in plain words

Unsupervised learning finds structure in data without labels. Cosine similarity measures how alike two vectors are, and k-means groups points into clusters around centres it learns.

Measure how similar two vectors are with cosine similarity and group unlabelled data with k-means.

Key ideas

  • Cosine similarity ignores length and compares only direction, which suits text and embeddings.
  • k-means needs the number of clusters k up front.
  • The starting centres can change the result, so k-means is often run several times.
  • Clusters come from the data alone; no labels are needed.

When should you use it?

  • Understand what happens inside neural networks and AI libraries.
  • Learn the idea before you implement it in the matching challenges.
  • Prepare for machine learning courses, interviews and projects.

See it in action

Press Step to alternate the two k-means steps, or Play to run them until nothing changes. Turn the vectors on the right to change their cosine similarity.

Example code

Run code →
main.py
import math

# Cosine similarity compares directions: 1 = same direction, 0 = unrelated.
def cosine(a, b):
    dot = sum(x * y for x, y in zip(a, b))
    return dot / (math.sqrt(sum(x * x for x in a)) * math.sqrt(sum(y * y for y in b)))

print("cos(doc1, doc2):", round(cosine([1, 2, 0], [2, 4, 0]), 3))
print("cos(doc1, doc3):", round(cosine([1, 2, 0], [0, 0, 3]), 3))

# k-means: assign points to the nearest centre, then move each centre to its points' mean.
points = [1, 2, 3, 10, 11, 12]
centres = [1.0, 2.0]
for step in range(1, 4):
    groups = [[], []]
    for p in points:
        nearest = min(range(len(centres)), key=lambda i: abs(p - centres[i]))
        groups[nearest].append(p)
    centres = [sum(g) / len(g) for g in groups]
    print(f"step {step}: centres={[round(c, 2) for c in centres]} groups={groups}")

Expected output

cos(doc1, doc2): 1.0
cos(doc1, doc3): 0.0
step 1: centres=[1.0, 7.6] groups=[[1], [2, 3, 10, 11, 12]]
step 2: centres=[2.0, 11.0] groups=[[1, 2, 3], [10, 11, 12]]
step 3: centres=[2.0, 11.0] groups=[[1, 2, 3], [10, 11, 12]]

How it works

cosine() divides the dot product by the lengths of both vectors, so doc2 (same direction as doc1) scores 1 and doc3 (no shared words) scores 0. k-means repeats two steps, assigning each point to its nearest centre and moving each centre to the mean of its points. Nothing changes after step 2, so it has converged.

Change the values and run the program in the CodeUtility online Python compiler without installing Python locally.

Practice exercises

Modify the runnable example with the exercises below to build understanding beyond copying the result.

  1. Change the inputs or weights and predict the output before running.
  2. Print the intermediate values to follow each step of the calculation.
  3. Solve the linked challenges below to implement the idea yourself.
Run in Python IDE →

Practice with a challenge

Use what this lesson covers to solve a real problem. Each challenge runs in your browser with instant tests and an AI review.

All challenges