Skip to content
Mighten's Blog

Feature Crossing Fundamentals: POLY2, FM, and FFM

Learn the fundamentals of feature crossing in recommender systems. Explore Simpson's Paradox, POLY2 brute-force crossing, and the latent vector breakthroughs in Factorization Machines (FM) and Field-aware Factorization Machines (FFM).

Recommender System 15 min read

Hi, continuing our recommender systems journey, today we tackle a key Logistic Regression (LR) limitation we saw last time: LR assumes a linear decision function in feature space and cannot model feature interactions — but recommendation signals often produce joint effects.

Modeling joint effects requires a different approach: feature crossing, the evolution of which we trace through:

  • POLY2: Brute-force feature crossing
  • Factorization Machines (FM): Latent vector-based feature crossing
  • Field-aware Factorization Machines (FFM): Field-aware feature crossing

Each step addressed the shortcomings of its predecessor, culminating in the deep learning paradigm that dominates modern recommender systems.


KEY DEFINITION: Feature Crossing

Combining two or more features to capture their joint effect.

For example: “Young users who like games click much more often than just ‘young users’ or just ‘game lovers’ individually.”


Before diving into models, let’s start with a counterintuitive phenomenon that demonstrates why treating features independently is not merely suboptimal — it can lead to actively wrong conclusions.

Simpson’s Paradox: A trend appears in different groups of data but disappears or reverses when these groups are combined.

Suppose we have click-through rate data for two mobile games, broken down by player skill level:

GroupGameClicksImpressionsCTR
Professional PlayersGame A95010,0009.5%
Game B5050010.0%
Amateur PlayersGame A955,0001.9%
Game B105002.0%

Key observations from the segmented data:

  • Game B is always better — by a small margin in both groups (0.5% and 0.1% respectively)
  • Professional players click ~5× more often than amateurs (an inherent base rate difference from their greater engagement with games)
  • Game A is disproportionately shown to professionals (10,000 impressions vs. 5,000)
  • Game B is tested equally across both groups (500 impressions each)

Within both skill groups, Game B clearly wins. The recommendation system should prioritize Game B for everyone, right?

Now look at the combined data, ignoring player skill:

GroupGameClicksImpressionsCTR
All UsersGame A1,04515,0006.97%
Game B601,0006.00%

The Paradox: Game B wins for both professional and amateur players individually… but Game A wins overall!

Why this happens: Player skill level is a confounding variable that correlates with both:

  1. Exposure: Game A was disproportionately shown to professional players (who click more often)
  2. Outcome: Professional players have inherently higher CTR regardless of which game is shown — they’re simply more engaged with gaming content

Game A gets a “free ride” from being tested mostly on click-happy users, while Game B is penalized by being tested equally on both populations. The uneven weighting of subpopulations in the aggregate reverses the true pattern.

The Connection to Logistic Regression: If we ignore player skill and train LR using only the game ID, the model would incorrectly conclude that Game A is better. In recommender systems, many predictive signals arise from interactions between features rather than from individual features alone. Capturing these interactions requires feature crossing.


Consider a game recommendation scenario with only 3 features:

FeatureMeaning
x1x_1Is it Late Night? (1 = yes, 0 = no)
x2x_2Is it Role-Playing Game (RPG)? (1 = yes, 0 = no)
x3x_3Is it Young User? (1 = yes, 0 = no)

Intuition: Young users click RPG game recommendations much more often at night than during the day.

Logistic Regression prediction for sample x=[1,1,1]\boldsymbol{x} = [1, 1, 1] (Late Night + RPG + Young User):

y^=σ(w1×1+w2×1+w3×1+b)=σ(w1+w2+w3+b)\hat{y} = \sigma(w_1 \times 1 + w_2 \times 1 + w_3 \times 1 + b) = \sigma(w_1 + w_2 + w_3 + b)

LR only considers individual feature effects. It cannot answer: What is the joint effect of “late night” AND “RPG” AND “young user” appearing together? — the “night owl RPG gamer” effect!

POLY2 prediction for the same sample (second-order only):

y^=σ(w1+w2+w3+b+w12×1×1+w13×1×1+w23×1×1)\hat{y} = \sigma(w_1 + w_2 + w_3 + b + w_{12} \times 1 \times 1 + w_{13} \times 1 \times 1 + w_{23} \times 1 \times 1)

The additional terms capture pairwise interactions. For 3 features, POLY2 learns 3 cross weights: w12w_{12} (Late Night×RPG), w13w_{13} (Late Night×Young User), w23w_{23} (RPG×Young User).

First, define the second-order crossing function — the core of POLY2:

ΦPOLY2(w,x)=j1=1n1j2=j1+1nwh(j1,j2)xj1xj2(1-1)\boxed{ \Phi_{\text{POLY2}}(\boldsymbol{w}, \boldsymbol{x}) = \sum_{j_1=1}^{n-1} \sum_{j_2=j_1+1}^{n} w_{h(j_1, j_2)} x_{j_1} x_{j_2} } \tag{1-1}

Where h(j1,j2)h(j_1, j_2) is an injective index function mapping feature pair (j1,j2)(j_1, j_2) to a unique storage location (typically implemented via hashing in practice).

Definition (POLY2 Model). The full POLY2 model combines first-order terms with the second-order crossing layer:

fPOLY2(x)=σ(w0+w1Tx+ΦPOLY2(w2,x))(1-2)\boxed{ f_{\text{POLY2}}(\boldsymbol{x}) = \sigma\left( w_0 + \boldsymbol{w_1}^T \boldsymbol{x} + \Phi_{\text{POLY2}}(\boldsymbol{w_2}, \boldsymbol{x}) \right) } \tag{1-2}

Where:

  • nn is the number of features
  • w0Rw_0 \in \mathbb{R} is the bias term
  • w1Rn\boldsymbol{w_1} \in \mathbb{R}^n is the first-order weight vector
  • wh(j1,j2)Rw_{h(j_1, j_2)} \in \mathbb{R} is the second-order weight for feature pair (j1,j2)(j_1, j_2)
  • Note: We only consider j1<j2j_1 < j_2 to avoid double-counting and self-interaction terms

In words: POLY2 learns a unique weight for every possible pair of features.


BASICS: Why One-Hot Encoding Causes Sparsity

Categorical features (Gender, UserID, City) must be converted to numerical form. One-hot encoding creates a dimension per category.

For example: [Weekday=Tuesday, Gender=Male, City=London] → 7 (days) + 2 (genders) + N (cities) dimensions. Only 3 values are non-zero.

The sparsity problem: For 100 million users, user ID one-hot creates 100 million dimensions, with exactly one non-zero value per sample. This is why POLY2’s direct pairwise learning fails — most feature pairs never co-occur in training data.


Property 1 (Parameter Count). POLY2 has 1+n+n(n1)2=O(n2)1 + n + \frac{n(n-1)}{2} = O(n^2) parameters. The quadratic growth is its fundamental computational bottleneck.

Property 2 (Gradient Sparsity). For one-hot encoded data, at most one feature per field is active. If sample x\boldsymbol{x} has only mm non-zero entries, then at most m(m1)2\frac{m(m-1)}{2} second-order terms receive gradient updates per sample. For sparse data, mnm \ll n, meaning most weights are never updated.

Property 3 (Co-occurrence Requirement). Weight wh(j1,j2)w_{h(j_1, j_2)} can only be learned if features j1j_1 and j2j_2 co-occur in the training data. If they never appear together:

fwh(j1,j2)=xj1xj2=0for all training samples\frac{\partial f}{\partial w_{h(j_1, j_2)}} = x_{j_1} x_{j_2} = 0 \quad \text{for all training samples}

The weight remains at its initial value forever.

POLY2 suffers from two fatal flaws that make it impractical for real-world recommendation systems:

FlawMathematical DescriptionPractical Consequence
Sparsity AmplificationMost wijw_{ij} receive zero gradient because
P(xi=1xj=1)P(xi=1)P(x_i=1 \cap x_j=1) \ll P(x_i=1)
Model cannot generalize to never-seen feature pairs
Parameter ExplosionO(n2)O(n^2) parameter growthStorage and computation become infeasible at scale

For n=100,000n=100,000 features (common in CTR prediction), POLY2 requires ~5 billion parameters.


Historical Note: Explicit pairwise crossing was historically used in production, but the full POLY2 formulation was rarely practical at industrial scale due to quadratic parameter growth. It is, however, the conceptual beginning of automatic feature interaction.


In 2010, Steffen Rendle introduced Factorization Machines, which addressed both limitations through a single elegant idea: Instead of learning separate weights for every feature pair, learn a latent vector for each feature, and pair weights can thus be computed as the dot product of these two latent vectors.

Connection to Matrix Factorization

FM’s latent vector approach is conceptually identical to how Matrix Factorization represents users and items in Collaborative Filtering — MF is mathematically a special case of FM:

Matrix FactorizationFactorization Machines
FeaturesOnly user ID + item IDAny number of features
Predictionr^ui=puTqi\hat{r}_{ui} = \boldsymbol{p}_u^{\text{T}} \boldsymbol{q}_iy^ij=viTvj\hat{y}_{ij} = \boldsymbol{v}_i^{\text{T}} \boldsymbol{v}_j
RepresentsEntities (users/items)Any feature
Answers”What is this?""How does this interact?”
ScopeOnly user × itemAny feature × any feature

Paradigm shift: From modeling entities to modeling feature interactions universally. MF learned latent vectors exclusively for users and items. FM generalizes this idea to ALL features — user demographics, item categories, contextual features, and beyond.

Three key design choices that make FM work:

  • Small fixed dimension: Each vector has only kk dimensions, where kk is a hyperparameter chosen through experimentation (typically 8, 16, or 32)
  • Learned automatically: Vectors start as random values, updated end-to-end via gradient descent
  • Generalizes across pairs: A vector is shaped by all features it co-occurs with, so even never-seen pairs can obtain meaningful interaction estimates

No manual feature engineering required — feature affinities are discovered automatically from data.


Using the same 3 features as before: Late Night (x1x_1), RPG (x2x_2), Young User (x3x_3).

Instead of learning 3 unique weights w12,w13,w23w_{12}, w_{13}, w_{23}, FM learns 3 latent vectors with dimension k=2k=2:

v1=[0.9,0.6],v2=[0.8,0.7],v3=[0.7,0.9]\boldsymbol{v}_1 = [0.9, 0.6], \quad \boldsymbol{v}_2 = [0.8, 0.7], \quad \boldsymbol{v}_3 = [0.7, 0.9]

Now compute cross terms via dot product:

w12=v1,v2=0.9×0.8+0.6×0.7=1.14w13=v1,v3=0.9×0.7+0.6×0.9=1.17w23=v2,v3=0.8×0.7+0.7×0.9=1.19\begin{align*} w_{12} &= \langle \boldsymbol{v}_1, \boldsymbol{v}_2 \rangle = 0.9 \times 0.8 + 0.6 \times 0.7 = 1.14 \\ w_{13} &= \langle \boldsymbol{v}_1, \boldsymbol{v}_3 \rangle = 0.9 \times 0.7 + 0.6 \times 0.9 = 1.17 \\ w_{23} &= \langle \boldsymbol{v}_2, \boldsymbol{v}_3 \rangle = 0.8 \times 0.7 + 0.7 \times 0.9 = 1.19 \end{align*}

w23=1.19w_{23} = 1.19 is the highest — RPG and Young User have the strongest affinity!

Key Insight: Even if “Late Night” and “RPG” never co-occur in training (e.g., we only have daytime RPG views and late-night FPS views), as long as each appears with “Young User” in some samples, their vectors can still be learned and their compatibility can be computed!


First, define the latent vector crossing function — the core innovation of FM:

ΦFM(V,x)=j1=1n1j2=j1+1nvj1,vj2xj1xj2(2-1)\boxed{ \Phi_{\text{FM}}(\boldsymbol{V}, \boldsymbol{x}) = \sum_{j_1=1}^{n-1} \sum_{j_2=j_1+1}^{n} \langle \boldsymbol{v}_{j_1}, \boldsymbol{v}_{j_2} \rangle x_{j_1} x_{j_2} } \tag{2-1}

This replaces POLY2’s explicit pairwise weights with latent vector dot products.

Definition (Factorization Machine). The full FM model combines first-order terms with the latent vector crossing layer:

fFM(x)=σ(w0+w1Tx+ΦFM(V,x))(2-2)\boxed{ f_{\text{FM}}(\boldsymbol{x}) = \sigma\left( w_0 + \boldsymbol{w_1}^T \boldsymbol{x} + \Phi_{\text{FM}}(\boldsymbol{V}, \boldsymbol{x}) \right) } \tag{2-2}

Where:

  • nn is the number of features
  • w0Rw_0 \in \mathbb{R} is the bias term
  • w1Rn\boldsymbol{w_1} \in \mathbb{R}^n is the first-order weight vector
  • V={vjRk}j=1n\boldsymbol{V} = \{\boldsymbol{v}_j \in \mathbb{R}^k\}_{j=1}^{n} is the set of latent vectors
  • knk \ll n is the latent dimension (typically 8, 16, or 32)

In words: Instead of learning one weight per pair, FM learns one vector per feature. Pairwise interaction weight is parameterized as the dot product of latent vectors.

NOTE: FM can be interpreted as imposing a low-rank constraint on the pairwise interaction matrix, which explains why FM generalizes well despite using far fewer parameters than POLY2.


Property 1 (Linear Parameter Growth). By introducing latent vectors, FM reduces the parameter count from POLY2’s O(n2)O(n^2) down to FM’s O(nk)O(nk), where kk is the latent dimension and knk \ll n — a reduction from quadratic to linear in nn.

Property 2 (Linear Time Complexity). Naively, the second-order term enumerates all O(n2)O(n^2) feature pairs. But an algebraic rearrangement - expanding jvjxj2\left\| \sum_{j} \boldsymbol{v}_j x_j \right\|^2 - rewrites it as a sum over individual features, collapsing both training and inference to O(nk)O(nk), the same order as logistic regression.

Property 3 (Generalization Under Sparsity). A feature’s latent vector is learnable as long as it co-occurs with any other feature - not with every specific partner. During gradient descent, the update to vj\boldsymbol{v}_j accumulates from all pairs involving jj, so even combinations that never appear together in training (e.g., “Late Night × RPG”) still get a meaningful crossing weight, as long as each feature was seen somewhere. This is exactly what POLY2 cannot do.


AdvantageMathematical BasisPractical Impact
Sparsity RobustnessGeneralization via shared latent vectorsWorks even when most feature pairs never co-occur
Parameter EfficiencyO(nk)O(nk) vs O(n2)O(n^2)Memory usage drops by orders of magnitude
Fast InferenceLinear time computationSame order as Logistic Regression
SGD CompatibilityAll parameters differentiable end-to-endFits existing training pipelines

In 2015, FFM extended FM by introducing the concept of feature fields (field-awareness), making the model more expressive. It won multiple CTR prediction competitions and was subsequently adopted by companies such as Criteo and Meituan.

Consider a recommendation scenario in FFM with three feature fields, where each feature owns one latent vector per field:

Feature FieldActive FeatureLatent Vector Group for Active Feature
Publisher (PP)ESPNvESPN,P,vESPN,A,vESPN,G\boldsymbol{v}_{\text{ESPN},P},\quad \boldsymbol{v}_{\text{ESPN},A},\quad \boldsymbol{v}_{\text{ESPN},G}
Advertiser (AA)NikevNike,P,vNike,A,vNike,G\boldsymbol{v}_{\text{Nike},P},\quad \boldsymbol{v}_{\text{Nike},A},\quad \boldsymbol{v}_{\text{Nike},G}
Gender (GG)MalevMale,P,vMale,A,vMale,G\boldsymbol{v}_{\text{Male},P},\quad \boldsymbol{v}_{\text{Male},A},\quad \boldsymbol{v}_{\text{Male},G}

In practice, every feature stores one latent vector for every field, although the vector corresponding to its own field is often unused because interactions are typically modeled only across different fields. It is usually stored for implementation simplicity but ignored during interaction computation.

When two features cross, each picks the latent vector indexed by the other’s field:

Part (1), Publisher “ESPN” × Advertiser “Nike”:

wESPN,Nike=vESPN,A,  vNike,Pw_{\text{ESPN},\text{Nike}} = \langle \boldsymbol{v}_{\text{ESPN},A},\; \boldsymbol{v}_{\text{Nike},P} \rangle
  • “ESPN” uses its Advertiser-vector (field AA) vESPN,A\boldsymbol{v}_{\text{ESPN},A}
  • “Nike” uses its Publisher-vector (field PP) vNike,P\boldsymbol{v}_{\text{Nike},P}

Part (2), Publisher “ESPN” × Gender “Male”:

wESPN,Male=vESPN,G,  vMale,Pw_{\text{ESPN},\text{Male}} = \langle \boldsymbol{v}_{\text{ESPN},G},\; \boldsymbol{v}_{\text{Male},P} \rangle

Part (3), Advertiser “Nike” × Gender “Male”:

wNike,Male=vNike,G,  vMale,Aw_{\text{Nike},\text{Male}} = \langle \boldsymbol{v}_{\text{Nike},G},\; \boldsymbol{v}_{\text{Male},A} \rangle

Assembling the second-order term. The FFM second-order crossing for this sample sums all three pairwise crossings, each multiplied by the product of the two feature values:

ΦFFM=wESPN,NikexESPNxNike+wESPN,MalexESPNxMale+wNike,MalexNikexMale\Phi_{\text{FFM}} = w_{\text{ESPN},\text{Nike}} \, x_{\text{ESPN}} x_{\text{Nike}} + w_{\text{ESPN},\text{Male}} \, x_{\text{ESPN}} x_{\text{Male}} + w_{\text{Nike},\text{Male}} \, x_{\text{Nike}} x_{\text{Male}}

In this case, under one-hot encoding, each field has exactly one active feature: xESPN=xNike=xMale=1x_{\text{ESPN}} = x_{\text{Nike}} = x_{\text{Male}} = 1, all others 00. Pairs involving an inactive feature are zeroed out, so only these three survive - and within each, 1×1=11 \times 1 = 1 drops the xx factors, leaving:

ΦFFM=wESPN,Nike+wESPN,Male+wNike,Male\Phi_{\text{FFM}} = w_{\text{ESPN},\text{Nike}} + w_{\text{ESPN},\text{Male}} + w_{\text{Nike},\text{Male}}

Why this beats FM. Notice ESPN appears in two crossings - with Nike and with Male - yet uses two different vectors (vESPN,A\boldsymbol{v}_{\text{ESPN},A} vs vESPN,G\boldsymbol{v}_{\text{ESPN},G}). FM, with only one vector vESPN\boldsymbol{v}_{\text{ESPN}}, would be forced to reuse it for both. That single vector must simultaneously encode “how ESPN relates to advertisers” and “how ESPN relates to user demographics” - two semantically distinct jobs blurred into one representation. FFM splits them apart, which is why it tends to be more accurate on field-structured data, at the cost of f×f\times more parameters.

Definition (Field). A field is a logical grouping of features, typically originating from the same domain or categorical variable. Formally, let F={F1,F2,...,Ff}F = \{F_1, F_2, ..., F_f\} be a partition of the feature index set {1,...,n}\{1, ..., n\} into ff fields, where FpF_p is the set of features belonging to field pp.

Definition (Field-aware Factorization Machine).

In an FFM, each feature learns a field-specific latent vector for every other field it interacts with. The field-aware interaction term is defined as:

ΦFFM(V,x)=j1=1n1j2=j1+1nvj1,fj2,vj2,fj1xj1xj2(3-1)\boxed{ \Phi_{\text{FFM}}(\boldsymbol{V}, \boldsymbol{x}) = \sum_{j_1=1}^{n-1} \sum_{j_2=j_1+1}^{n} \langle \boldsymbol{v}_{j_1, f_{j_2}}, \boldsymbol{v}_{j_2, f_{j_1}} \rangle x_{j_1} x_{j_2} } \tag{3-1}

The full FFM model is:

fFFM(x)=σ(w0+w1Tx+ΦFFM(V,x))(3-2)\boxed{ f_{\text{FFM}}(\boldsymbol{x}) = \sigma\left( w_0 + \boldsymbol{w_1}^T \boldsymbol{x} + \Phi_{\text{FFM}}(\boldsymbol{V}, \boldsymbol{x}) \right) } \tag{3-2}

Where:

  • fjf_j denotes the field that feature jj belongs to
  • vj,pRk\boldsymbol{v}_{j, p} \in \mathbb{R}^k is the latent vector of feature jj when interacting with features from field pp

In words: Each feature maintains ff distinct latent vectors, dynamically selecting the vector that corresponds to the field of the feature it is currently crossing with.

Property 1 (Parameter Count). FFM has 1+n+n×k×f=O(nkf)1 + n + n \times k \times f = O(nkf) parameters. This is still much better than POLY2’s O(n2)O(n^2) when fn/kf \ll n/k, but ff times more than FM.

Property 2 (No Linear Time Trick). FFM cannot use FM’s algebraic rearrangement. The second-order computation remains O(kn2)O(kn^2) in naive form, or O(km2)O(km^2) where mm is non-zero features per sample.

This makes FFM significantly slower than FM in practice - a classic trade-off between the expressiveness FFM gains and the engineering cost it incurs.


The evolution from POLY2 to FFM represents a defining chapter in recommender systems — the era where second-order feature crossing moved from theoretical concept to industrial practice. Each model addressed its predecessor’s critical flaws, paving the way for the deep learning revolution.


PropertyLogistic Regression (LR)POLY2FMFFM
Crossing MechanismNone (manual)Explicit pairwiseLatent vector dot-productField-aware latent vectors
Parameter CountO(n)O(n)O(n2)O(n^2)O(nk)O(nk)O(nkf)O(nkf)
Inference ComplexityO(n)O(n)O(n2)O(n^2)O(nk)O(nk)O(km2)O(km^2)
Sparsity Robustness★★☆☆☆★☆☆☆☆★★★★★★★★★☆
GeneralizationIndividual featuresRequires co-occurrenceAny never-seen pairsNever-seen per field
Interpretability★★★★★★★★★☆★★★☆☆★★☆☆☆

Note:

  • nn = number of features
  • mm = non-zero features per sample (typically 10–50), making FFM practical despite theoretical O(n2)O(n^2) complexity.

ModelStrengthsTrade-offsPrimary Use Case
POLY2Perfect expressiveness, no rank restrictionParameter explosion, no generalizationSmall datasets, academic research
FMLinear complexity, excellent generalization, SGD-friendlySingle vector per feature limits expressivenessDefault choice for high-throughput production
FFMField-aware semantics, higher accuracyf×f \times more parameters, slower inferenceAccuracy-critical applications, competition settings

Start with FM — it offers the best speed-accuracy tradeoff for most industrial scenarios.

Consider FFM only when:

  1. Accuracy gains justify 5–10× compute cost
  2. Fields are semantically distinct (e.g., Publisher ≠ Advertiser ≠ User)
  3. Training data is large enough to support f×f \times more parameters
  4. Latency requirements are flexible (batch scoring or low QPS)

  1. The Latent Vector Revolution — FM’s greatest insight was borrowing matrix factorization’s latent vector paradigm to solve both sparsity and complexity simultaneously. This pattern — sharing parameters across related tasks — remains the foundation of modern embedding systems.

  2. Structure Beats Capacity — FFM demonstrated that encoding domain knowledge (field structure) into model architecture can deliver more accurate results than simply increasing parameter count.

  3. The Second-Order Ceiling — Despite their ingenuity, all these models are fundamentally limited to pairwise interactions. This constraint created the demand for deep learning architectures capable of arbitrary-order feature combination.

  4. Ideas Outlive Models — While FM and FFM are rarely used standalone today, many modern architectures (e.g., DeepFM) explicitly retain FM as one component:

    • Embedding layers = generalized latent vectors
    • Attention mechanisms = field-aware interaction on steroids
    • Multi-head attention = extreme version of multiple interaction modes

The second-order crossing era taught us how to share parameters to generalize across sparse data — a lesson that remains central to every modern deep learning-based recommender system.


Comments