Skip to content
AI360Xpert
Beta

Feature Construction in RL

Linear reinforcement learning algorithms can only compute flat hyperplanes over their inputs. Feature construction transforms raw continuous state variables into rich, non-linear representation vectors, enabling linear models to learn complex, curved value functions.

Feature construction transforms raw continuous state variables into rich representation vectors, enabling linear function approximators to capture non-linear value functions.
Feature construction transforms raw continuous state variables into rich representation vectors, enabling linear function approximators to capture non-linear value functions.

Why Does This Exist?

In reinforcement learning with function approximation, linear methods represent state values as a simple inner product between a learned parameter vector w\mathbf{w} and a feature vector x(s)\mathbf{x}(s):

v^(s,w)≐w⊤x(s)=∑i=1dwixi(s)\hat{v}(s, \mathbf{w}) \doteq \mathbf{w}^\top \mathbf{x}(s) = \sum_{i=1}^d w_i x_i(s)

Linear function approximators offer decisive mathematical advantages: they are computationally lightweight (O(d)O(d) per step), possess a unimodal error surface free from deceptive local minima, and enjoy rigorous convergence guarantees under on-policy Temporal Difference Learning.

However, linear models suffer from a fundamental geometric limitation: they can only fit flat hyperplanes over their input features.

If an agent directly passes raw physical state variables—such as a robot's joint angle θ\theta and angular velocity θ˙\dot{\theta}—as features x(s)=[θ,θ˙]⊤\mathbf{x}(s) = [\theta, \dot{\theta}]^\top, the model can only express values that vary linearly along those axes: v^(s,w)=w1θ+w2θ˙+w0\hat{v}(s, \mathbf{w}) = w_1 \theta + w_2 \dot{\theta} + w_0. If the true optimal value function is curved, possesses saddle points, or features sharp cliff boundaries (as in Mountain Car or CartPole), a flat hyperplane fails catastrophically. The agent cannot capture multi-variable interactions or localized non-linearities.

Feature construction exists to overcome this representational bottleneck without sacrificing the stability and convergence proofs of linear learning.

By designing non-linear feature mappings x:S→Rd\mathbf{x}: \mathcal{S} \to \mathbb{R}^d—such as state aggregation, polynomial cross-terms, Fourier bases, or radial basis functions—all non-linear complexity is embedded directly into the feature space. The learning algorithm remains strictly linear in its parameter weights w\mathbf{w}, but the composite function w⊤x(s)\mathbf{w}^\top \mathbf{x}(s) can approximate arbitrary, complex non-linear value surfaces.

Think of It Like This

Whole Raw Spices vs. Artisan Spice Blends

Imagine cooking in a commercial kitchen with an automated seasoning dispenser. The machine only has volume dials for its ingredient hoppers; it can adjust how many grams of a powder to pour into a pan, but it cannot chop, roast, grind, or chemically alter ingredients during cooking.

If you dump whole, raw ingredients into the hoppers—unroasted cumin seeds, whole peppercorns, and rock salt crystals (raw continuous state coordinates)—the resulting dish is uneven and bitter. The simple dispenser has no mechanism to crush the seeds or activate aromatic oils. It can only adjust the overall volume of whole seeds.

A master chef solves this through feature engineering (spice preparation):

  1. Before loading the dispenser, the chef toasts the cumin, grinds the peppercorns, and blends them with smoked paprika and garlic powder into an artisan spice rub (the non-linear feature map x(s)\mathbf{x}(s)).
  2. The complex chemical reactions, roasting, and interaction flavors are synthesized beforehand during preparation.
  3. The automated dispenser now only needs to adjust a single linear volume knob (the weight vector w\mathbf{w}) to produce an award-winning sauce.

The dispenser remains completely linear and predictable, but the pre-blended features allow it to deliver complex, multi-layered flavors.

Where the analogy stops: Spices degrade chemically over time due to oxidation and humidity. In reinforcement learning, mathematical feature mappings x(s)\mathbf{x}(s) are deterministic, static functions that preserve exact numerical precision across millions of episodes.

How It Actually Works

Linear Value Representation and the Feature Construction Spectrum

When value functions are parameterized linearly, the gradient of the predicted value with respect to the parameter vector is simply the feature vector itself:

∇wv^(s,w)=x(s)\nabla_\mathbf{w} \hat{v}(s, \mathbf{w}) = \mathbf{x}(s)

This identity makes semi-gradient TD updates exceptionally clean and computationally efficient:

wt+1=wt+α[Rt+1+γv^(St+1,wt)−v^(St,wt)]x(St)\mathbf{w}_{t+1} = \mathbf{w}_t + \alpha \left[ R_{t+1} + \gamma \hat{v}(S_{t+1}, \mathbf{w}_t) - \hat{v}(S_t, \mathbf{w}_t) \right] \mathbf{x}(S_t)

where α∈(0,1]\alpha \in (0, 1] is the step-size learning rate and γ∈[0,1]\gamma \in [0, 1] is the discount factor. Because updates adjust w\mathbf{w} directly along the active feature directions x(St)\mathbf{x}(S_t), the design of x(s)\mathbf{x}(s) dictates how learning generalizes across the state space.

The Representation Spectrum

Practitioners construct feature vectors using several distinct mathematical paradigms:

[Pure Tabular] ────────► [State Aggregation] ────────► [Polynomial & RBF] ────────► [Deep Networks]One-Hot Vector            Discretized Grid Bins        Continuous Basis Envelopes    Learned RepresentationsZero Generalization       Step-Wise Generalization     Smooth Non-Linear Surface     Hierarchical Latentsd = |S|                   d = B₁ × B₂ × ... × B_D      d = Multi-Index Combinations  Millions of weights
  1. One-Hot Encoding (Exact Tabular): Each discrete state sis_i corresponds to a unique standard basis vector: x(s)=[0,…,0,1,0,…,0]⊤\mathbf{x}(s) = [0, \dots, 0, 1, 0, \dots, 0]^\top Updating state sis_i affects only wiw_i, yielding zero generalization across neighboring states.
  2. State Aggregation (Grid Bins): Continuous state dimensions are partitioned into discrete intervals. All states falling within a given multi-dimensional bin activate a single binary indicator: xi(s)={1if s∈Bini0otherwisex_i(s) = \begin{cases} 1 & \text{if } s \in \text{Bin}_i \\ 0 & \text{otherwise} \end{cases} States inside the same bin share identical value estimates, producing a piecewise-constant step-function approximation.
  3. Polynomial & Interaction Features: Expands continuous coordinates into products of powers: xpoly(s)=[1,s1,s2,s12,s22,s1s2]⊤\mathbf{x}_{\text{poly}}(s) = [1, s_1, s_2, s_1^2, s_2^2, s_1 s_2]^\top The cross-term s1s2s_1 s_2 is critical: it allows the model to capture non-linear diagonal synergies where the effect of coordinate s1s_1 depends directly on the magnitude of s2s_2.
  4. Fourier Basis: Constructs features using multidimensional cosine waves: xi(s)=cos⁡(πci⊤s)x_i(s) = \cos(\pi \mathbf{c}_i^\top s) where ci∈{0,1,…,n}D\mathbf{c}_i \in \{0, 1, \dots, n\}^D is an integer coefficient vector. Fourier bases provide global, smooth periodic features that excel in continuous kinematic control tasks.
  5. Radial Basis Functions (RBFs): Defines continuous bell-shaped receptive fields centered at prototype points ci\mathbf{c}_i: xi(s)=exp⁡(−∥s−ci∥22σi2)x_i(s) = \exp\left( -\frac{\|s - \mathbf{c}_i\|^2}{2\sigma_i^2} \right) Yields smooth, continuous generalization across distance metrics in Euclidean space.

The Generalization vs. Discrimination Trade-Off

The shape and width of constructed feature envelopes govern an inescapable trade-off:

  • Broad Feature Envelopes (Large σ\sigma or Large Grid Bins): High generalization. An update at state ss influences a wide region of neighboring states, speeding up initial learning. However, discrimination is low: the agent cannot resolve fine localized value differences or sharp optimal decision boundaries.
  • Narrow Feature Envelopes (Small σ\sigma or Fine Grid Bins): High discrimination. The agent can represent sharp cliffs and localized reward spikes. However, generalization is low: the agent must visit nearly every localized sub-region independently, degrading toward tabular sample complexity.

Worked numerical calculation

Consider an agent navigating a 2D continuous state space s=(x1,x2)s = (x_1, x_2), where x1∈[0.0,3.0]x_1 \in [0.0, 3.0] and x2∈[0.0,3.0]x_2 \in [0.0, 3.0].

We evaluate state s=(1.40,2.30)s = (1.40, 2.30) under two distinct feature construction regimes.


Regime 1: 3×33 \times 3 State Aggregation Grid

Each dimension is partitioned into 33 equal intervals of width 1.01.0:

  • Coordinate x1=1.40∈[1.0,2.0)  ⟹  x_1 = 1.40 \in [1.0, 2.0) \implies row index i=1i = 1.
  • Coordinate x2=2.30∈[2.0,3.0]  ⟹  x_2 = 2.30 \in [2.0, 3.0] \implies column index j=2j = 2.

The 2D bin coordinate is (i,j)=(1,2)(i, j) = (1, 2). Flattening to a 9-dimensional index (3i+j3i + j):

index=1×3+2=5\text{index} = 1 \times 3 + 2 = \mathbf{5}

The resulting constructed feature vector xgrid(s)∈{0,1}9\mathbf{x}_{\text{grid}}(s) \in \{0, 1\}^9 is:

xgrid(s)=[0,0,0,0,0,1,0,0,0]⊤\mathbf{x}_{\text{grid}}(s) = [0, 0, 0, 0, 0, 1, 0, 0, 0]^\top

Suppose the learned linear weight vector across the 9 bins is:

wgrid=[1.2,2.5,4.0,2.0,5.5,8.0,3.5,7.0,10.0]⊤\mathbf{w}_{\text{grid}} = [1.2, 2.5, 4.0, 2.0, 5.5, 8.0, 3.5, 7.0, 10.0]^\top

The estimated state value is:

v^(s,wgrid)=wgrid⊤xgrid(s)=w5=8.00\hat{v}(s, \mathbf{w}_{\text{grid}}) = \mathbf{w}_{\text{grid}}^\top \mathbf{x}_{\text{grid}}(s) = w_5 = \mathbf{8.00}

Any other state within the bounding box [1.0,2.0)×[2.0,3.0][1.0, 2.0) \times [2.0, 3.0] (e.g., (1.85,2.95)(1.85, 2.95)) evaluates to exactly 8.008.00.


Regime 2: Polynomial Expansion with Cross-Product Term

To capture smooth continuous variation and interaction, we construct a 6-dimensional polynomial feature map:

xpoly(s)=[1.0,x1,x2,x12,x22,x1x2]⊤\mathbf{x}_{\text{poly}}(s) = [1.0, x_1, x_2, x_1^2, x_2^2, x_1 x_2]^\top

Evaluating each feature term at s=(1.40,2.30)s = (1.40, 2.30):

  1. Bias term: x0=1.0000x_0 = 1.0000
  2. Linear terms: x1=1.4000x_1 = 1.4000, x2=2.3000x_2 = 2.3000
  3. Quadratic terms: x12=(1.4)2=1.9600x_1^2 = (1.4)^2 = 1.9600, x22=(2.3)2=5.2900x_2^2 = (2.3)^2 = 5.2900
  4. Cross-product interaction term: x1x2=1.4×2.3=3.2200x_1 x_2 = 1.4 \times 2.3 = \mathbf{3.2200}

The constructed feature vector is:

xpoly(s)=[1.0000,1.4000,2.3000,1.9600,5.2900,3.2200]⊤\mathbf{x}_{\text{poly}}(s) = [1.0000, 1.4000, 2.3000, 1.9600, 5.2900, 3.2200]^\top

Let the parameter weights be wpoly=[0.5,1.0,1.5,0.2,0.1,0.8]⊤\mathbf{w}_{\text{poly}} = [0.5, 1.0, 1.5, 0.2, 0.1, 0.8]^\top.

The estimated value is:

v^(s,wpoly)=wpoly⊤xpoly(s)=0.5(1.0)+1.0(1.4)+1.5(2.3)+0.2(1.96)+0.1(5.29)+0.8(3.22)=0.5000+1.4000+3.4500+0.3920+0.5290+2.5760=8.8470\begin{aligned} \hat{v}(s, \mathbf{w}_{\text{poly}}) &= \mathbf{w}_{\text{poly}}^\top \mathbf{x}_{\text{poly}}(s) \\ &= 0.5(1.0) + 1.0(1.4) + 1.5(2.3) + 0.2(1.96) + 0.1(5.29) + 0.8(3.22) \\ &= 0.5000 + 1.4000 + 3.4500 + 0.3920 + 0.5290 + 2.5760 \\ &= \mathbf{8.8470} \end{aligned}

Notice that the cross-product interaction term x1x2x_1 x_2 contributed +2.5760+2.5760 (nearly 30%30\% of the total value). Without feature construction, a purely additive linear model would be blind to this synergistic interaction.

Code

from typing import Dict, List, Tuple

class StateAggregationTransformer:    """Discretizes a multi-dimensional continuous state space into a multi-bin grid."""
    def __init__(        self,        bounds: List[Tuple[float, float]],        num_bins: List[int],    ) -> None:        """Initialize discretization intervals.
        Args:            bounds: List of (min_val, max_val) for each dimension.            num_bins: Number of equal-width bins along each dimension.        """        assert len(bounds) == len(num_bins), "Bounds and bin counts must match."        self.bounds = bounds        self.num_bins = num_bins        self.total_features = 1        for b in num_bins:            self.total_features *= b
    def get_bin_indices(self, state: List[float]) -> List[int]:        """Convert continuous coordinates into discrete bin indices."""        bin_coords: List[int] = []        for val, (low, high), bins in zip(state, self.bounds, self.num_bins):            clamped = max(low, min(high, val))            frac = (clamped - low) / (high - low)            bin_idx = min(bins - 1, int(frac * bins))            bin_coords.append(bin_idx)        return bin_coords
    def transform(self, state: List[float]) -> Dict[int, float]:        """Map continuous state to a sparse 1-hot feature dictionary."""        bin_coords = self.get_bin_indices(state)        # Convert multi-dimensional coordinate to flat index        flat_idx = 0        multiplier = 1        for coord, bins in reversed(list(zip(bin_coords, self.num_bins))):            flat_idx += coord * multiplier            multiplier *= bins        return {flat_idx: 1.0}
    def evaluate(self, state: List[float], weights: List[float]) -> float:        """Compute linear value estimate v_hat(s, w) = w^T x(s)."""        sparse_x = self.transform(state)        return sum(weights[idx] * val for idx, val in sparse_x.items())

def polynomial_feature_transform(state: List[float]) -> List[float]:    """Expand a 2D continuous state [x1, x2] into quadratic polynomial features."""    assert len(state) == 2, "Expected 2D input state."    x1, x2 = state[0], state[1]    return [1.0, x1, x2, x1 ** 2, x2 ** 2, x1 * x2]

# Verification matching the worked numerical exampletransformer = StateAggregationTransformer(    bounds=[(0.0, 3.0), (0.0, 3.0)],    num_bins=[3, 3],)
sample_state = [1.4, 2.3]bin_coords = transformer.get_bin_indices(sample_state)sparse_feat = transformer.transform(sample_state)
assert bin_coords == [1, 2]assert sparse_feat == {5: 1.0}
grid_weights = [1.2, 2.5, 4.0, 2.0, 5.5, 8.0, 3.5, 7.0, 10.0]grid_val = transformer.evaluate(sample_state, grid_weights)assert abs(grid_val - 8.00) < 1e-4
poly_feat = polynomial_feature_transform(sample_state)assert poly_feat == [1.0, 1.4, 2.3, 1.96, 5.29, 3.22]
poly_weights = [0.5, 1.0, 1.5, 0.2, 0.1, 0.8]poly_val = sum(f * w for f, w in zip(poly_feat, poly_weights))assert abs(poly_val - 8.8470) < 1e-4
print(f"State Aggregation Bin: {bin_coords} -> Flat Index: {list(sparse_feat.keys())[0]}")print(f"Grid Discretization Value: {grid_val:.2f}")print(f"Polynomial Features: {poly_feat}")print(f"Polynomial Estimated Value: {poly_val:.4f}")
# -> State Aggregation Bin: [1, 2] -> Flat Index: 5# -> Grid Discretization Value: 8.00# -> Polynomial Features: [1.0, 1.4, 2.3, 1.96, 5.29, 3.22]# -> Polynomial Estimated Value: 8.8470

Watch Out For

The Exponential Grid Explosion and Missing Interaction Terms

Two prevalent pitfalls trap engineers when designing linear representations for reinforcement learning:

1. The Curse of Dimensionality in Grid Discretization: Attempting to achieve fine discrimination by dividing every dimension into BB bins triggers an exponential parameter explosion:

d=BDd = B^D

In a 6-DoF robotic manipulator state space (D=12D = 12 joint angles and velocities), partitioning each variable into just B=10B = 10 bins generates 101210^{12} features. The memory requirement exceeds terabytes, and sample complexity collapses because each bin must be visited independently to learn its weight.

2. Missing Diagonal Interactions (The Additive Trap): Encoding each state variable with independent 1D features (e.g., x(s)=[x1(s1)⊤,x2(s2)⊤]⊤\mathbf{x}(s) = [\mathbf{x}_1(s_1)^\top, \mathbf{x}_2(s_2)^\top]^\top) reduces feature count from O(BD)O(B^D) to O(D⋅B)O(D \cdot B). However, an additive model cannot represent multi-variable interactions. If success requires both s1>0s_1 > 0 and s2>0s_2 > 0 simultaneously (a diagonal decision boundary), purely additive features fail to separate the classes.

Concrete Fix:

  1. Transition from Grid Discretization to Tile Coding: Tile coding uses multiple overlapping, coarsely quantized tilings with relative offsets. It achieves fine resolution while scaling linearly with the number of tilings rather than exponentially with resolution.
  2. Include Multi-Variable Cross Products: Always augment independent 1D basis functions with pairwise interaction terms (such as sisjs_i s_j or conjunctive tile intersections) whenever physical variables exhibit dynamic coupling.

The Quick Version

  • Linear value approximators v^(s,w)=w⊤x(s)\hat{v}(s, \mathbf{w}) = \mathbf{w}^\top \mathbf{x}(s) can only fit hyperplanes; feature construction embeds all non-linear domain complexity directly into x(s)\mathbf{x}(s).
  • Feature design controls the generalization-discrimination trade-off: broad features generalize quickly, while narrow features resolve sharp boundaries.
  • Constructing interaction terms (e.g., x1x2x_1 x_2 or conjunctive receptive fields) is essential to capture diagonal synergies that purely additive models cannot express.
  • Naive multi-dimensional grid discretization explodes exponentially (BDB^D), necessitating advanced sparse representations like tile coding or Fourier bases in higher dimensions.