So far this course has fed your networks numbers — returns, volumes, volatilities, the
nicely-behaved continuous stuff a matrix multiply is happy to chew on. But real market data
is riddled with labels: the ticker JPM, the sector “Financials”, the country “US”, the
exchange “NYSE”, the day-of-week “Monday”, the regime tag “risk-off”. And then there’s the
truly unstructured swamp — news headlines, 10-K filings, earnings-call transcripts.
A neural net does not know what “Financials” means. It multiplies and adds. It cannot
multiply the string "JPM". So before any of your hard-won RNN / TCN / transformer machinery
can touch a category, you have to turn that label into a vector. The lazy way is one-hot
encoding. The good way — the way that lets a bank learn from what other banks did — is an
embedding. This lesson is about doing it well, and about the leakage traps that embeddings
make extraordinarily easy to fall into.
One-hot encoding is a waste
You one-hot encode a universe of 3,000 tickers and feed the result straight into the first dense layer. What is the single biggest structural problem with this representation (before we even talk about parameters)?
Analogy. One-hot encoding is like giving every employee in a 3,000-person company a badge that is a single light in a 3,000-light panel — yours is light #1,742, lit; everyone else’s is dark. The badge tells you who someone is and absolutely nothing about what they’re like. Two analysts on the same desk are as “far apart” as the CEO and the night janitor.
Definition. One-hot encoding maps a category from a vocabulary of cardinality to the indicator vector — a -long vector that is in position and everywhere else. All distinct one-hot vectors are mutually orthogonal: for , and for every pair. Constant distance, zero similarity structure.
Worked example. Take a toy universe of four tickers and encode them:
| Ticker | Sector | One-hot vector |
|---|---|---|
| JPM | Financials | [1, 0, 0, 0] |
| BAC | Financials | [0, 1, 0, 0] |
| XOM | Energy | [0, 0, 1, 0] |
| AAPL | Technology | [0, 0, 0, 1] |
Distance between the two banks, . Distance between a bank and the oil major, . Identical. The encoding insists JPM and BAC are no more similar than JPM and XOM.
Now scale up. With tickers, each input is a 3,000-long sparse vector. A first dense layer with hidden units needs weights just to read the ticker — and most of them see a single non-zero example at a time, so they update glacially.
The curse, again
Remember lesson 1’s complaint that deep nets starve on markets’ tiny effective sample size? One-hot encoding pours gasoline on that fire. A 3,000-wide sparse input multiplies your parameter count without adding information, and each ticker’s column only gets a gradient on the rows where that exact ticker appears. High cardinality + low effective-N is precisely the regime where one-hot encoding overfits fastest.
When to use it
One-hot is fine — even preferable for its simplicity — when cardinality is low (say : day-of-week, a handful of regimes) and you have plenty of data per category. At that scale the parameter cost is trivial and the lack of learned similarity barely matters. It’s only at high cardinality that it becomes a liability.
Fill in the structural facts about one-hot vectors.
Pick the right option for each blank, then check.
Any two distinct one-hot vectors are , which means the model receives information about category similarity, and a first dense layer's parameter count grows in the cardinality.
Entity embeddings
An entity embedding layer maps a ticker id to a dense vector. Where do the values in that vector come from?
Analogy. This is word2vec for stocks. Word2vec learned that “king − man + woman ≈ queen” not because anyone told it, but because words that appear in similar contexts ended up with similar vectors. An entity embedding does the same with tickers: two banks that respond alike to rate moves get nudged toward each other in the embedding space, because sharing a representation lowers the loss. You never hand-label “these are both banks” — the geometry falls out of the training signal.
Definition. An embedding maps each category id to a dense vector via a lookup into an embedding matrix , where row is . Equivalently it’s a dense layer with no bias and no activation applied to the one-hot vector: . The matrix is trained jointly with the task. The embedding dimension (with ) is a hyperparameter you choose.
Dimension rule of thumb. Two popular heuristics:
The first (the fast.ai rule) caps the size for huge vocabularies; the second grows very slowly. Both encode the same instinct: more categories deserve a richer space, but with sharply diminishing returns.
Worked example. With tickers, the min-rule gives . The fourth-root rule gives . People usually land somewhere in between; say . Parameter count of the embedding: — versus the the one-hot dense layer needed above for , and crucially every row now accumulates shared structure rather than memorising one ticker in isolation.
| Property | One-hot encoding | Entity embedding () |
|---|---|---|
| Vector length | ||
| Storage / params (read) | ||
| Encodes similarity? | No — all pairs equidistant | Yes — learned geometry |
| Generalises across cats? | No | Yes (banks share structure) |
| Sparse vs dense | Sparse, mostly zeros | Dense, all dimensions used |
| Interpretable axes? | Trivially (one per cat) | Not directly (latent factors) |
Pick a term, then click its definition.
When to use it
Reach for an entity embedding when a categorical is high-cardinality and you have a large pooled cross-section so many categories can pool statistical strength (more on this below). It shines exactly where one-hot drowns. But it is not free: you’ve added parameters that can memorise, and a learned space that — like every learned thing here — can leak the future if you’re careless.
Embedding alternative & text data
You want to feed yesterday's news flow into a return model. Which approach turns a headline into something the network can actually consume, without you hand-coding features?
Analogy. A pretrained text embedding is a translator you hired who already speaks the language fluently. You don’t teach them English from scratch on your 4,000 trading days of headlines — you hand them the sentence and they hand you back a compact “meaning vector”. Your downstream model only has to learn what that meaning implies for returns, not what English is.
Definition & taxonomy. “Embedding alternative data” really means producing a dense vector representation of unstructured or semi-structured inputs:
| Alt-data input | Representation | Typical dimension |
|---|---|---|
| News headline / filing | Pretrained sentence/document embedding | 384–1536 |
| Sentiment of text | Scalar (or small vector) sentiment score | 1–3 |
| Document topic mix | Topic-model vector (e.g. LDA proportions) | 20–100 |
| Continuous alt-signal | Standardised scalar, optionally binned + embedded | 1–8 |
| Categorical alt-tag | Entity embedding (same machinery as tickers) | -ish |
The point is uniform: by the time it reaches the network, everything — ticker, sector, news, sentiment — is a dense vector, and the downstream layers don’t care which column came from a lookup table and which came from a language model.
Worked example (out-of-vocabulary). Your training universe has tickers. In
live trading a freshly-IPO’d name appears that the embedding table has never seen. With a raw
lookup, there is no row for it — the model crashes or silently maps to garbage. The fix is
to reserve an extra row at index for an <UNK> (“unknown”) token: build , route every unseen id to row , and train that row by
randomly mapping some rare tickers to <UNK> during training so it learns a sensible “generic
new name” vector. Same trick handles out-of-vocabulary words in text encoders.
Cardinality discipline
Before embedding any categorical, count distinct values as they exist at decision time and
decide an OOV policy. A “country” field with 40 values is cheap; a “news source URL” field with
80,000 values is a memorisation trap unless you bucket the long tail into <UNK>. Cardinality
is a design decision, not a given.
When to use it
Pretrained text embeddings earn their keep when the signal lives in the language (tone of a filing, novelty of a headline) and your own dataset is far too small to learn English from scratch — which is essentially always in finance. Skip the heavy encoder when a one-line sentiment score already captures everything you’ll act on; a 1,536-dim vector feeding a model with 3,000 training days is a fast track to overfitting.
Sort each market input by the representation that fits it best.
Place each item in the right group.
- Exchange / venue code
- Full text of an earnings-call transcript
- A news headline string
- GICS sector label
- Ticker id from a 3,000-name universe
- 10-K risk-factors section
Leakage traps embeddings make easy
You learn a ticker embedding on your ENTIRE dataset (2010–2025), then run a purged, walk-forward backtest on top of those frozen vectors and report a beautiful Sharpe. Why is the result still contaminated?
This is the section that matters. Embeddings are a learned representation, and anything learned can memorise the future. Every leakage lesson from Machine Learning for Alpha — preprocessing-on-full-data, survivorship, look-ahead — has an embedding-shaped version that is easier to commit and harder to spot.
The five traps.
| # | Trap | What leaks |
|---|---|---|
| a | Embedding fit on the full sample | Test-period co-occurrences bleed into the vectors (preprocessing-on-full-data) |
| b | Survivorship in the entity set | Vocabulary built from names that survived to today silently drops the dead |
| c | Look-ahead labels (regime / reclassification) | A tag assigned with hindsight encodes the outcome it should predict |
| d | A category that encodes the future | e.g. a was_acquired flag is a label masquerading as a feature |
| e | Target leakage via memorisation | On tiny data the embedding learns an id→outcome map instead of structure |
Worked example (regime look-ahead). Suppose you tag each day with a regime label and embed it. You define “risk-off” by checking whether the next 20 days had a drawdown exceeding 10%:
That label at time is a function of returns from to . Embed it, feed it to a model predicting , and your “feature” already contains the answer — the embedding for “risk-off” will look spectacularly predictive, and on live data, where you can’t see the next 20 days, it evaporates. The fix: define the regime using only information available at or before (a trailing volatility threshold, a moving-average crossover), and assign it causally.
Embeddings launder leakage — audit every category like a hostile witness
The danger is that an embedding is opaque, so leakage hides inside a dense vector instead of a
named column you’d flag in review. Three habits: (1) Fit the embedding inside the training
fold only — refit per walk-forward window, never on the pooled full sample; treat it exactly
like a fitted scaler. (2) Build the vocabulary point-in-time — the set of tickers/sectors
must be the universe as known on the decision date, including names later delisted, or you’ve
re-imported survivorship through the back door. (3) Interrogate every categorical: “could a
human assign this label without knowing the future?” If a regime tag, sector reclassification,
or was_acquired flag needs hindsight, it is a target, not a feature, no matter how dense the
vector that hides it.
Which of these embedding setups leak future information? Select every one that does.
When the leak is subtle
The nastiest case is (e), memorisation on tiny data. With tickers, , and only ~1,000 days of pooled history, the embedding can quietly learn an id→average-return lookup — a fancy target-encoding fit on the training labels. It validates poorly out-of-sample and you’ll blame “regime change”. The tell: in-sample fit improves sharply with while out-of-sample stalls or degrades. Shrink , add regularisation/dropout on the embedding, or question whether you have the data to embed this category at all.
A teammate refits ticker embeddings on the full 15-year history “for stability”, then runs purged walk-forward CV on top. Why is the purging useless here, in the vocabulary of Machine Learning for Alpha?
Answer. Purged CV protects against temporal leakage between the train and test labels during model fitting — it removes overlapping windows and embargoes near the split. But the embedding was fit before the CV even started, on data that includes the test period. That is preprocessing-on-full-data leakage: the features handed to the CV already encode test-period structure, so purging the model fit changes nothing. The cure is identical to the one for scalers and PCA in that course — fit the transform inside the training fold only, then apply the frozen-from-train transform to the held-out data. An embedding is just a fitted transform with parameters; treat it like one.
When embeddings earn their keep
You have a categorical with 12 distinct values, 800 training rows, and you're choosing between an entity embedding and a gradient-boosted tree with native categorical handling. What's the sober call?
Analogy. Embeddings are a team sport. Their whole advantage is letting categories pool strength — one bank learning from a thousand bank-days. If you’ve got two banks and a long weekend of data, there’s no team to pool; you’re just memorising. Embeddings reward a crowded stadium, not an empty one.
The decision, made precise. Favour an embedding when both hold: (1) cardinality is high ( in the hundreds-to-thousands), so one-hot is wasteful and similarity structure is worth learning; and (2) you have a large pooled cross-section — many entities many periods — so the embedding has enough examples per latent factor to learn structure rather than ids. Avoid it when data is tiny (it memorises), when cardinality is low (an ordinal or target encoding, or just a one-hot, is simpler), or when a tree will do.
| Situation | Cardinality | Effective data | Best tool |
|---|---|---|---|
| 3,000 tickers, 15y daily, pooled panel | High | Large | Entity embedding |
| Day-of-week feature | Low (7) | Any | One-hot / cyclical encoding |
| 12 sectors, 800 rows | Low–med | Small | Target/ordinal encoding or a tree |
| Mixed tabular features, modest data | Mixed | Modest | Gradient-boosted trees |
| News text, signal in language | n/a | Small own-data | Pretrained text embedding |
Foreshadowing lesson 6
Notice how often the honest answer above is “use a tree”. Gradient-boosted trees handle categoricals natively (no one-hot, no embedding matrix), need no GPU, and resist overfitting on the small, noisy, low-signal panels that define finance. The next lesson makes the uncomfortable case directly: on most tabular market problems, trees usually win — and embeddings are the exception you reach for, not the default.
When to use it — the trade-off
The embedding trade is expressive power and shared structure bought with parameters, opacity, and a fresh surface for leakage. You take the trade when high cardinality and a deep pooled cross-section make the shared structure real and learnable. You decline it when the data can’t fund the parameters, or when a tree gives you 95% of the benefit with 5% of the foot-guns.
Summarise the embedding decision rule.
Pick the right option for each blank, then check.
Entity embeddings pay off when cardinality is and the pooled cross-section is ; with little data the embedding tends to , and for plain tabular panels a gradient-boosted is often the simpler winner.
Recap
Big picture
Embeddings for categorical & alt-data
- Embeddings
- One-hot
- Orthogonal → no similarity
- K-wide, params blow up
- OK only when K is small
- Entity embedding
- Lookup table E (K×m), learned
- m ≈ min(50, ⌈K/2⌉) or K^0.25
- word2vec for stocks: banks cluster
- Alt & text data
- Pretrained sentence/doc vectors
- Sentiment / topic vectors
- OOV → <UNK> row
- Leakage traps
- Fit on full sample
- Survivorship vocabulary
- Look-ahead regime labels
- Category encodes the future
- Memorisation on tiny data
- When to embed
- High cardinality + big panel
- Not tiny data, not low K
- Else: trees usually win
- One-hot
Embeddings check
Why does one-hot encoding fail to express that two banks are similar?
Check your answer to continue.