One-Hot Encoding
The cleanest way to give a model unambiguous categorical identity — a vector of length V with exactly one active position. No fake numeric order, no learned geometry, just a precise pointer into vocabulary space.
One-Hot Encoding: The Single Glowing Lightbulb
Imagine a massive board with 128,000 lightbulbs in the library. When the scholar wants to select token #42, exactly lightbulb #42 switches ON (1) while all 127,999 others stay OFF (0). Dot-multiplying this one-hot vector with the embedding matrix acts as an instantaneous physical selector pulling out row #42. However, because all lightbulb axes are perpendicular, one-hot vectors cannot tell the scholar if "cat" is closer to "dog" than to "airplane".
IntroductionWhat is one-hot encoding?
One-hot encoding is the most direct answer to the question: how do you give a model an unambiguous identity for each category in a set? Given a vocabulary of size V, each token or category is represented as a vector of length V where every position is 0 except for exactly one position — the one corresponding to this token — which is 1.
The name comes from digital electronics: a "one-hot" signal is a bus where exactly one wire is high (1) at any given time. In NLP, the "bus" is the vocabulary, and the "high wire" is the token's unique index.
Vocabulary: [cat, dog, fish, bird] (V = 4) cat → [1, 0, 0, 0] dog → [0, 1, 0, 0] fish → [0, 0, 1, 0] bird → [0, 0, 0, 1]
- Exactly one active position per vector — no exceptions.
- Every vector has the same length V (vocabulary size).
- There is no semantic relationship encoded — cat and dog are just as "far" from each other as cat and fish.
WhyWhy one-hot at all?
The naive alternative — assigning integer IDs (cat=0, dog=1, fish=2, bird=3) and feeding those integers directly into a model — creates an implicit ordering that does not exist. If dog gets ID 1 and fish gets ID 2, the model may infer that fish is "greater than" or "closer to 3" than dog, which is nonsensical. One-hot eliminates this fake numeric order entirely.
🚫 Problem with raw IDs
Integer IDs imply a numeric scale: ID 3 − ID 1 = 2, suggesting "distance". Models using IDs directly will learn spurious relationships from ordinal proximity. The assignment was arbitrary — it should carry zero information.
✅ One-hot advantage
Every token occupies a completely orthogonal axis. The encoding is unambiguous identity, not a position on a scale. The model receives no misleading numeric signal from the encoding itself.
W @ one_hot), the conceptual model of one-hot is exactly what embedding lookups implement. Understanding one-hot is the prerequisite for understanding embeddings.
IntuitionA row of switches
Imagine a control panel with V switches, one for each word in your vocabulary. Exactly one switch is ON at any time — the switch labelled with the current token. Every other switch is OFF. The entire state of the panel is your one-hot vector.
The key insight: the position of the 1 carries all the information. The value of the 1 is always just 1 — it signals presence, not magnitude. There is no "more cat-ness" or "less dog-ness" in this encoding.
This is fundamentally different from, say, word frequency counts, where values vary in magnitude and carry information. In one-hot, every active token has exactly the same activation value: 1.
TheoryOne-hot geometry: orthogonality and equidistance
One-hot vectors form the standard basis of an V-dimensional space. Each vector $\mathbf{e}_i$ has a 1 at index $i$ and 0s everywhere else. This has precise geometric consequences.
The geometric consequence of equidistance is that one-hot vectors encode no semantic topology. "cat" and "dog" are no closer together than "cat" and "spaceship". The encoding is maximally agnostic about semantic relationships — it delegates all relationship learning to the embedding layer on top.
How It WorksThe four-step construction
Constructing a one-hot vector for a token is entirely mechanical — no learning, no parameters, no ambiguity:
- Fix the vocabulary: Enumerate all possible tokens and assign each a unique integer ID. The order is arbitrary but must remain fixed. Vocabulary size is V.
- Find the token's ID: Look up the token in the vocabulary dictionary to retrieve its integer index
i. - Create a zero vector: Allocate a vector of length V filled with zeros:
[0, 0, …, 0]. - Set position i to 1: Flip exactly one position to 1:
vector[i] = 1. The result is the one-hot encoding.
The embedding layer in a neural network performs the equivalent of: take the one-hot vector $\mathbf{e}_i$, multiply by the embedding matrix $W \in \mathbb{R}^{V \times d}$, and get the $d$-dimensional embedding: $W^\top \mathbf{e}_i = W[i, :]$ — the $i$-th row of $W$. In practice, this is implemented as a direct row index rather than a full matrix multiply, but the math is identical.
embedding_matrix[token_id] is mathematically equivalent but uses O(d) memory instead of O(V).CalculateManual worked example
Walk through a complete manual construction. Vocabulary: [red, green, blue, yellow, black] — V = 5. Token to encode: "blue".
[0, 0, 0, 0, 0]
[0, 0, 1, 0, 0]
Vocab [red, green, blue, yellow, black] → IDs [0, 1, 2, 3, 4] red → [1, 0, 0, 0, 0] green → [0, 1, 0, 0, 0] blue → [0, 0, 1, 0, 0] ← token "blue" → ID 2 → position 2 is hot yellow → [0, 0, 0, 1, 0] black → [0, 0, 0, 0, 1]
Dot product check: blue · green = [0,0,1,0,0] · [0,1,0,0,0] = 0+0+0+0+0 = 0. Orthogonal, as expected.
Distance check: ‖blue − green‖₂ = ‖[0,−1,1,0,0]‖₂ = √(0+1+1+0+0) = √2 ≈ 1.414. Equidistant, as expected.
Visualize + Hands-onInteractive one-hot encoder
Select any token from the demo vocabulary below and click Encode to see its one-hot vector rendered as a grid of cells. The blue cell marks the active dimension — every other position is zero.
Now try to observe these properties as you switch tokens:
- The position of the hot cell changes but its value is always 1.
- All other cells are always 0 — the vector is maximally sparse.
- Two different tokens can never share the same hot position.
- Adding a new token to the vocabulary would grow every vector by one dimension.
CodePython one-hot encoding implementation
A fully annotated implementation showing one-hot construction from scratch, with numpy for efficiency, and a demonstration of the key properties (orthogonality, equidistance, and the embedding-lookup equivalence).
import numpy as np
# ── Step 1: Build vocabulary ────────────────────────────────────────────────
vocab = ["cat", "dog", "fish", "bird", "rabbit"]
token_to_id = {tok: i for i, tok in enumerate(vocab)}
V = len(vocab)
# ── Step 2: Core one-hot function ───────────────────────────────────────────
def one_hot(token_id: int, vocab_size: int) -> np.ndarray:
"""
Create a one-hot vector of length vocab_size.
Args:
token_id: Integer index of the token (0-based).
vocab_size: Total vocabulary size V.
Returns:
numpy array of shape (V,) with a single 1.0 at position token_id.
"""
vec = np.zeros(vocab_size, dtype=np.float32)
vec[token_id] = 1.0
return vec
# ── Step 3: Encode tokens ───────────────────────────────────────────────────
cat_vec = one_hot(token_to_id["cat"], V) # [1, 0, 0, 0, 0]
dog_vec = one_hot(token_to_id["dog"], V) # [0, 1, 0, 0, 0]
fish_vec = one_hot(token_to_id["fish"], V) # [0, 0, 1, 0, 0]
# ── Step 4: Verify geometric properties ────────────────────────────────────
print(f"cat · dog = {np.dot(cat_vec, dog_vec):.1f}") # 0.0 (orthogonal)
print(f"cat · cat = {np.dot(cat_vec, cat_vec):.1f}") # 1.0 (self-dot)
print(f"‖cat−dog‖ = {np.linalg.norm(cat_vec - dog_vec):.4f}") # 1.4142 (√2)
print(f"‖cat−fish‖ = {np.linalg.norm(cat_vec-fish_vec):.4f}") # 1.4142 (√2, always)
print(f"Non-zero entries: {int(cat_vec.sum())}") # 1
# ── Step 5: The embedding lookup equivalence ────────────────────────────────
d = 4 # small embedding dimension
np.random.seed(0)
embedding_matrix = np.random.randn(V, d).astype(np.float32)
# Method A: matrix multiply with one-hot (expensive — O(V*d))
embed_A = embedding_matrix.T @ cat_vec # shape: (d,)
# Method B: direct index lookup (efficient — O(d))
embed_B = embedding_matrix[token_to_id["cat"]] # shape: (d,)
print(f"Methods match: {np.allclose(embed_A, embed_B)}") # True
What to observe
- Vector length is always V regardless of which token
- Every pair of distinct tokens has dot product = 0
- Every pair has Euclidean distance = √2
- Embedding lookup is mathematically identical to matrix multiply
What to extend
- Batch encode: stack one-hot rows into an (N × V) matrix
- Compare memory: N × V floats vs N integer IDs
- Try scipy.sparse for memory-efficient sparse storage
- Add a cosine similarity check (should always be 0)
Hands-onExperiments to deepen intuition
Run these experiments in a Python notebook or your browser console. Each one challenges a common misconception.
Experiment set: four key checks
CompareToken ID vs One-hot vs Embedding
These three representations sit at successive levels of abstraction in the token → model pipeline. Understanding their relationship is foundational:
| Aspect | Token ID | One-hot | Embedding |
|---|---|---|---|
| Representation | Single integer | V-dimensional binary vector | d-dimensional float vector |
| Semantic info | None — arbitrary ordinal | None — pure categorical identity | Potential — learned from context |
| Memory per token | 4 bytes (int32) | V × 4 bytes (e.g., 200 KB for V=50k) | d × 4 bytes (e.g., 3 KB for d=768) |
| Pairwise similarity | Meaningless ordinal distance | Always 0 (orthogonal, equidistant) | Meaningful — dot product / cosine |
| Role in pipeline | Vocabulary index pointer | Conceptual bridge; categorical identity | Neural representation for model input |
| Materialized at runtime? | Yes — always | No — replaced by index lookup | Yes — embedding_matrix[token_id] |
ApplyWhere one-hot encoding is actually used
Classification targets
Multi-class classifiers output probability distributions. The ground-truth label is one-hot encoded — class 3 out of 10 is [0,0,0,1,0,0,0,0,0,0]. Cross-entropy loss directly compares model output to this one-hot label.
Tabular / categorical features
In classical ML (sklearn, XGBoost), one-hot encoding transforms categorical columns into indicator columns. Country "France" out of 5 countries becomes [0,1,0,0,0]. This is OneHotEncoder in sklearn.
Educational tooling
One-hot is the best pedagogical bridge from categorical variables to numeric vectors. Teaching tokenization, embedding space, or attention patterns all benefit from starting with one-hot as the intuition layer.
LLM intuition: embedding as projection
The embedding layer $W \in \mathbb{R}^{V \times d}$ can be understood as: "given the one-hot identity of token $i$, project it into a learned d-dimensional space". This framing makes weight tying (input/output embeddings) and transfer learning conceptually natural.
LimitationsWhat one-hot fundamentally cannot do
- Memory does not scale: For V = 100,000 tokens, each one-hot vector has 100,000 elements with 99,999 of them being zero. Storing a corpus of 1 billion tokens as dense one-hot would require ~400 GB of float32 data.
- Every token is equidistant: Cat and dog, cat and democracy, cat and the number 7 — all are distance √2 from each other. One-hot encodes no topology of meaning, no clusters, no analogies.
- No learned relationships: Synonyms, antonyms, hypernyms, analogies — none of these are captured. The encoding is purely identity-based; relationships must be learned on top (via embeddings).
- Vocabulary must be fixed in advance: Adding a new token requires extending every previously encoded vector's dimension. This makes one-hot brittle for open-vocabulary or streaming settings.
Common mistake
"I can measure word similarity by comparing one-hot vectors."
Better mental model
"One-hot vectors are maximally uninformative about similarity — that's their feature, not a bug. They delegate similarity learning to the embedding layer."
Feynman ChallengeCan you explain it simply?
Explain one-hot encoding to a friend who knows spreadsheets but not linear algebra. Use the "survey checkbox" metaphor:
- Imagine a survey question: "Which animal do you mean?" with checkboxes for cat / dog / fish / bird.
- Exactly one box is checked. The "one-hot vector" is just the list of answers: [✓, ☐, ☐, ☐] for cat.
- Every response has the same number of checkboxes. It doesn't matter that cat=0 or dog=1 — the position is what matters, not the number.
- Now explain why one-hot knows nothing about which animals are similar — the boxes don't care about meaning, only identity.
- Finally, explain that embeddings are the step where a model learns to move similar animals closer together in a new coordinate system.
Misconceptions to address:
- "One-hot vectors encode similarity" — No: all distinct tokens are equidistant (dot product = 0, distance = √2).
- "A larger ID means a more important word" — No: IDs are arbitrary indices with no semantic ordering.
- "One-hot is what language models actually use internally" — No: LLMs use dense learned embeddings; one-hot is the conceptual foundation, not the runtime representation.
- "I need to materialize the full one-hot vector in my code" — No:
embedding_matrix[token_id]is mathematically equivalent and uses 99%+ less memory.
BuildMini-projects to cement your understanding
🔨 Mini-Projects
1 · One-hot playground
Build a tiny web widget: text input for vocabulary (comma-separated), click any token, render its one-hot vector as a row of colored blocks (blue for 1, grey for 0). Show the vector length and the active dimension index.
2 · Token comparison tool
Select two tokens, compute their dot product (always 0) and Euclidean distance (always √2). Then add a learned embedding matrix and show how cosine similarity changes to a meaningful value after one training step.
3 · Memory estimator
Build a calculator: input vocab_size and num_tokens, compute memory for (a) dense one-hot (vocab_size × 4 bytes), (b) integer IDs (4 bytes each), and (c) embeddings of dimension d. Display all three side by side.
SummaryOne-hot in one page
- What it is: A V-dimensional binary vector with exactly one 1, at the token's vocabulary index.
- Why it exists: Prevents fake numeric ordering of raw integer IDs; gives each category its own orthogonal axis.
- Geometry: All distinct tokens are perfectly orthogonal (dot = 0) and equidistant (distance = √2).
- Memory: Too large to materialize at scale — V=50k means 200 KB per vector; replaced by direct index lookup.
- Relationship to embeddings: An embedding lookup is mathematically
W.T @ one_hot— the embedding matrix projects from one-hot space to a learned dense space. - Limitation: Encodes zero semantic similarity — motivates the move to learned dense embeddings.
