How to Merge Numerical and Embedding Sequential Models to treat categories in `RNN`
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.
Introduction
When an RNN must learn from both continuous sequence features and categorical sequence features, the usual solution is to encode the categories with Embedding layers and then merge those embeddings with the numerical inputs before the recurrent layer. In Keras, that almost always means using the Functional API instead of trying to stack everything into one Sequential model.
Why numerical and categorical sequence features need different treatment
Numerical sequence features can usually go directly into an RNN after normalization. Examples include:
- sensor values
- prices
- durations
- counts
Categorical features are different. A category such as weekday=3 or product_id=27 is not a meaningful continuous quantity, so feeding raw integer IDs into an RNN is usually a bad idea. An embedding layer learns a dense vector representation for each category instead.
That gives you two streams:
- numeric tensors already shaped as sequence features
- embedded categorical tensors learned from integer category IDs
The model then merges those streams.
Merge them by concatenating per time step
The most common pattern is:
- one input for the numeric sequence
- one input for the categorical sequence
- embedding on the categorical branch
- concatenate along the feature axis
- pass the combined tensor to the RNN
Example:
The important part is that both inputs line up by time step. At each time index, the RNN receives the numeric features plus the embedding features for the categorical value at that same index.
Match the shapes correctly
The biggest shape rule is this:
- numeric branch:
(batch, timesteps, numeric_features) - categorical branch before embedding:
(batch, timesteps) - categorical branch after embedding:
(batch, timesteps, embedding_dim)
After concatenation:
- merged branch:
(batch, timesteps, numeric_features + embedding_dim)
If the time dimension does not match between the branches, you cannot concatenate them directly.
That is why trying to combine one Sequential model for embeddings and another for numeric input often becomes awkward. The merge happens at the tensor-shape level, so the Functional API is the natural fit.
Multiple categorical features
If you have several categorical sequence features, embed each one separately, then concatenate all branches:
This scales much better than trying to manually one-hot encode everything into a giant sparse feature axis.
Common Pitfalls
The biggest mistake is feeding raw categorical integer IDs directly into the RNN and assuming the model will interpret them meaningfully. Category IDs are labels, not continuous values.
Another mistake is forgetting that the categorical input to Embedding should normally be integer indices, not one-hot vectors. The embedding layer expects lookup indices.
Developers also run into shape mismatches by forgetting that the embedding output adds a feature dimension. After embedding, the categorical branch becomes three-dimensional.
Finally, do not force this into Sequential if there are multiple inputs. The Functional API is the right tool for multi-branch sequence models.
Summary
- Feed numerical sequence features directly and categorical sequence features through embeddings.
- Use the Functional API to build separate input branches and merge them cleanly.
- Concatenate branches along the feature axis so each time step carries both numeric and embedding information.
- Keep the time dimension aligned across all branches.
- For multiple categorical features, embed each one separately and merge them before the RNN.
Related reading
- How to merge two saved keras model?
- How to monitor a filtered version of a metric in EarlyStopping callback in tensorflow?
- How to monitor dead relus
- How to monitor gradient vanish and explosion in keras with tensorboard?
- How to parse product titles unstructured into structured data?
- How to proceed with NLP task for recognizing intent and slots
- How to monitor the status of model training running on the server via fast-api
- How to multiply matrices in the result of using chain rule in the backpropagation algorithm
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseNo course covers this one yet
Basis Lab writes one for you from a sentence about what you want to be able to do, then teaches it and checks you understood. Your first course is free.
Build my courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.