Quant Memo
Core

Learned Embeddings for Categorical Features

An embedding replaces a category, like a ticker or a sector, with a short list of numbers learned from data, so that categories the model finds similar end up sitting near each other in that number space instead of being treated as arbitrary and unrelated labels.

Prerequisites: The Multilayer Perceptron

A stock's sector is a category — "Technology," "Utilities," "Energy" — not a number. Feed it to a model as one-hot encoding (a column of zeros with a single 1 marking which sector) and every sector becomes equally different from every other. The model is told nothing about the fact that Technology and Communication Services often move together, while Technology and Utilities usually don't. One-hot vectors are all the same distance apart, by construction, whether the categories are close cousins or total opposites.

An embedding fixes that by learning, from the data itself, where each category should sit. Instead of "Technology" being a single 1 among five hundred zeros, it becomes a short list of numbers, say eight of them, and the model learns those eight numbers the same way it learns any other weight — by gradient descent on the training loss. If sectors that behave alike end up needing similar predictions, gradient descent will naturally pull their embeddings close together, because that's what lowers the loss. Think of it like a seating chart at a large conference that nobody drew up in advance: people who keep ending up in the same conversations gradually migrate to sit near each other, and by the end of the event, physical closeness on the chart tells you who has similar interests, purely as a byproduct of many small social decisions.

The mechanics, one symbol at a time

Say a categorical feature has KK possible values (e.g., K=11K=11 sectors). An embedding table is a matrix EE with KK rows, one per category, and dd columns, where dd (the embedding dimension) is a size you choose, typically much smaller than KK. For a category cc, its embedding is simply that row:

ec=Ec,:Rde_c = E_{c,:} \in \mathbb{R}^d

In words: look up row cc of a table, and the dd numbers you find there are that category's learned representation. There's no formula computing ece_c from anything else — the table's entries are free parameters, initialized randomly and then updated by backpropagation exactly like any weight matrix, based on how much moving ece_c would have reduced the loss on examples where category cc appeared.

Worked example 1: a two-dimensional embedding lookup

Suppose d=2d = 2 and the embedding table for four sectors, after training, has settled at:

sectore1e_1e2e_2
Technology1.80.9
Communication Services1.61.1
Utilities-1.50.2
Energy-1.3-0.8

Technology's row is looked up as eTech=(1.8,0.9)e_{\text{Tech}} = (1.8, 0.9), and that pair of numbers, not a one-hot vector, is what's concatenated with the stock's other features (say, momentum and volatility) before being fed to the rest of the network.

Compute the (Euclidean) distance between Technology and Communication Services: (1.81.6)2+(0.91.1)2=0.04+0.04=0.080.28\sqrt{(1.8-1.6)^2 + (0.9-1.1)^2} = \sqrt{0.04+0.04} = \sqrt{0.08} \approx 0.28, close together. Between Technology and Energy: (1.8(1.3))2+(0.9(0.8))2=9.61+2.89=12.53.54\sqrt{(1.8-(-1.3))^2 + (0.9-(-0.8))^2} = \sqrt{9.61+2.89} = \sqrt{12.5} \approx 3.54, far apart. Nobody told the model sectors should cluster this way; it emerged because Technology and Communication Services examples needed similar predictions during training, while Energy examples needed very different ones.

Worked example 2: why one-hot loses information a small model can't recover

Ten sectors, one-hot encoded, feeding a linear layer with weight wiw_i per sector. The layer's contribution for sector ii is just wiw_i — ten completely independent numbers with zero sharing between them. If the smallest sector has only 40 training examples, that sector's wiw_i is estimated from 40 points alone.

With a d=2d=2 embedding instead, that same small sector's prediction is a function of two numbers sitting inside a continuous space shared by every sector. Gradient descent, when nudging Technology's embedding based on thousands of Technology examples, also slightly reshapes the local geometry near sectors that started close to it — so a data-starved sector inherits some signal from its neighbors, rather than learning everything from its own 40 examples in isolation. This is the practical payoff: embeddings let rare categories borrow statistical strength from similar, common ones.

Matrix explorer
dashed = before · solid = after
det 1.25trace 2.50λ 1.81, 0.69area scales by 1.25×

The explorer above shows a different setting (a matrix stretching the unit circle) but the same underlying idea applies: a K×dK \times d embedding table is a linear map from a high-dimensional one-hot space down to a low-dimensional space, and training bends that map so that geometric closeness in the small space means learned similarity, not an accident of alphabetical category order.

one-hot: all equidistant embeddings: similar sectors cluster
One-hot places every category at an identical distance from every other; a trained embedding lets the model organize categories by learned similarity.

What this means in practice

Embedding dimension dd is a hyperparameter — too small re-creates the "everything looks similar" problem for genuinely different categories, too large wastes parameters and risks overfitting a category with few examples. A common rule of thumb scales dd with KK (something like dmin(50,K0.5)d \approx \min(50, \lceil K^{0.5}\rceil)), but it's worth tuning per problem. Embeddings need enough examples per category to be learned well; a category seen five times will end up with a nearly-arbitrary embedding, so rare categories are sometimes grouped into an explicit "other" bucket first. The same core idea underlies word embeddings — a ticker, a word, a merchant category are all just categories waiting for a learned coordinate.

An embedding replaces an arbitrary category label with a small vector of learned numbers, trained by gradient descent alongside the rest of the model, so that categories the model treats similarly end up geometrically close.

The classic confusion: treating embeddings as fixed, meaningful features that can be inspected in isolation like a hand-built feature. They are model-specific and re-learned from scratch (or fine-tuned) for every new training run and every dataset — the number that represents "Technology" in one model has no necessary relationship to the number representing "Technology" in a different model trained on different data, so embeddings from two separately trained models cannot be compared or combined directly.

Related concepts

Practice in interviews

Further reading

  • Guo & Berkhahn, Entity Embeddings of Categorical Variables
  • Chollet, Deep Learning with Python, ch. 6
ShareTwitterLinkedIn