02 · Setup: Python, NumPy & Your First Vectors¶
Install Python and NumPy¶
You'll need Python 3.9+ for this course.
# macOS (Homebrew)
brew install python
# Ubuntu/Debian
sudo apt install python3 python3-pip
# Windows
# Download from https://www.python.org/downloads/
Create a virtual environment and install NumPy:
Verify it:
Creating your first vectors¶
A vector in this course is just a 1-dimensional NumPy array of floats:
import numpy as np
v = np.array([0.2, 0.9, -0.1])
print(v) # [ 0.2 0.9 -0.1]
print(v.shape) # (3,)
print(v.dtype) # float64
Real embedding models produce vectors with hundreds of dimensions (384, 768, 1536 are common sizes), but the math is identical whether you have 3 numbers or 1536 — NumPy doesn't care.
Basic vector operations¶
a = np.array([1.0, 2.0, 3.0])
b = np.array([4.0, 5.0, 6.0])
a + b # array([5., 7., 9.]) element-wise addition
a - b # array([-3., -3., -3.])
a * 2.0 # array([2., 4., 6.]) scalar multiply
a * b # array([4., 10., 18.]) element-wise multiply (NOT dot product)
Magnitude (norm)¶
The magnitude (or norm, or length) of a vector tells you how far
it is from the origin. For a 3D vector [x, y, z] it's the familiar
Pythagorean formula extended to N dimensions:
v = np.array([3.0, 4.0])
magnitude = np.linalg.norm(v)
print(magnitude) # 5.0 (3-4-5 right triangle)
np.linalg.norm works for any number of dimensions:
v = np.array([0.2, 0.9, -0.1, 0.4, -0.6])
print(np.linalg.norm(v)) # sqrt(0.04+0.81+0.01+0.16+0.36) ≈ 1.095
You'll use this constantly: normalizing a vector (dividing it by its own magnitude) produces a unit vector — same direction, length exactly 1 — which is the basis for cosine similarity in the next lesson.
def normalize(v):
return v / np.linalg.norm(v)
unit = normalize(np.array([3.0, 4.0]))
print(unit) # [0.6 0.8]
print(np.linalg.norm(unit)) # 1.0
Representing toy "documents" as vectors¶
Before you generate real embeddings in Lesson 5, it helps to hand-craft a
tiny dataset so you can reason about the numbers directly. Imagine a
4-dimensional space where each dimension loosely tracks a theme —
[animals, technology, food, sports]:
documents = {
"doc1": np.array([0.9, 0.1, 0.0, 0.0]), # about animals
"doc2": np.array([0.8, 0.2, 0.1, 0.0]), # also about animals, slightly tech
"doc3": np.array([0.0, 0.9, 0.1, 0.0]), # about technology
"doc4": np.array([0.0, 0.0, 0.1, 0.9]), # about sports
}
for name, vec in documents.items():
print(name, "magnitude:", round(np.linalg.norm(vec), 3))
Real models never hand you interpretable dimensions like this — but keeping this toy dataset around for the next two lessons will let you verify that your distance and similarity code behaves the way you expect before you point it at opaque, 384-number real embeddings.
Exercise¶
Create three vectors of your own representing fictional documents. Use
np.linalg.norm to compute each one's magnitude, then normalize all three
into unit vectors and confirm each normalized vector has magnitude 1.0
(allow for tiny floating-point error, e.g. 0.9999999999999998). Print a
table of document name → original magnitude → normalized magnitude.