Skip to content
AI360Xpert
Beta

Expected SARSA

Instead of gambling on a single randomly sampled next action, Expected SARSA computes the exact average value over all available actions weighted by the probability of taking them.

Backup diagrams contrasting SARSA's sampled action branch, Q-learning's greedy maximum branch, and Expected SARSA's probability-weighted expectation.
Backup diagrams contrasting SARSA's sampled action branch, Q-learning's greedy maximum branch, and Expected SARSA's probability-weighted expectation.

Why Does This Exist?

In classical Temporal Difference learning, SARSA computes its bootstrap target using the exact action At+1A_{t+1} sampled by the agent's behavior policy:

YtSARSA=Rt+1+γQ(St+1,At+1)Y_t^{\text{SARSA}} = R_{t+1} + \gamma Q(S_{t+1}, A_{t+1})

Because At+1A_{t+1} is a random draw from an exploratory policy (such as ϵ\epsilon-greedy), this single sample injects massive variance into the update. Two identical transitions landing in the exact same state St+1S_{t+1} can produce wildly contradictory target values: one step samples a greedy action yielding high value, while the very next step samples an exploratory blunder yielding a catastrophic penalty. To prevent divergence from this sampling noise, practitioners must reduce the learning rate α\alpha, slowing convergence to a crawl.

Q-learning sidesteps this action variance by taking the greedy maximum max⁡aQ(St+1,a)\max_a Q(S_{t+1}, a). However, Q-learning is strictly off-policy: it assumes infallible future execution. In hazardous environments where the agent continues to explore, Q-learning ignores its own exploratory blunders, suffering from maximization bias and frequently driving the agent into catastrophic penalties during online learning.

Expected SARSA resolves this fundamental tension. Instead of rolling the dice on a single sampled action At+1A_{t+1}, it computes the exact mathematical expectation across all possible next-state actions under policy π\pi:

YtExp=Rt+1+γ∑a∈Aπ(a∣St+1)Q(St+1,a)Y_t^{\text{Exp}} = R_{t+1} + \gamma \sum_{a \in \mathcal{A}} \pi(a \mid S_{t+1}) Q(S_{t+1}, a)

By replacing a random draw with its expected value, Expected SARSA completely eliminates action-selection sample variance while faithfully accounting for exploratory risk.

Think of It Like This

Calculating an exam grade: die roll vs best answer vs weighted course syllabus

Imagine a university grading policy for a multi-part final exam containing easy questions, moderate questions, and treacherous trap questions.

  • The SARSA examiner rolls a multi-sided die to pick a single question at random and awards you that single question's score as your entire course grade. If you roll an easy question, your recorded grade spikes; if you roll a treacherous trap question by sheer bad luck, your recorded grade plummets. Over infinite repeated exams the average score is technically correct, but every individual update suffers extreme variance from the random die roll.
  • The Q-learning examiner assumes you will answer only the easiest question on the entire test, completely ignoring that the exam rules force you to answer harder questions 10% of the time during testing.
  • The Expected SARSA examiner consults the syllabus, takes the exact probability of every question appearing, multiplies each by its expected score, and assigns your deterministic expected value: ∑ipi×scorei\sum_i p_i \times \text{score}_i. No dice are rolled. Every evaluation is smooth, predictable, and fully accounts for the presence of the hard questions.

Where the analogy stops: A course syllabus has static question weights, whereas in reinforcement learning, both the policy distribution π(a∣s)\pi(a \mid s) and the action values Q(s,a)Q(s, a) continuously shift as the agent learns, requiring the expectation to be recomputed dynamically at every time step.

How It Actually Works

Expectation Backup and Policy Duality

Let St∈SS_t \in \mathcal{S} denote the state at step tt, At∈AA_t \in \mathcal{A} the action taken, Rt+1∈RR_{t+1} \in \mathbb{R} the scalar reward, and St+1∈SS_{t+1} \in \mathcal{S} the resulting state. The update rule for Expected SARSA is:

Q(St,At)←Q(St,At)+α[Rt+1+γ∑a∈Aπ(a∣St+1)Q(St+1,a)−Q(St,At)]Q(S_t, A_t) \leftarrow Q(S_t, A_t) + \alpha \left[ R_{t+1} + \gamma \sum_{a \in \mathcal{A}} \pi(a \mid S_{t+1}) Q(S_{t+1}, a) - Q(S_t, A_t) \right]

where:

  • α∈(0,1]\alpha \in (0, 1] is the step-size parameter (learning rate).
  • γ∈[0,1)\gamma \in [0, 1) is the discount factor.
  • π(a∣St+1)\pi(a \mid S_{t+1}) is the probability of selecting action aa in state St+1S_{t+1} under the target policy π\pi.
  • ∑a∈Aπ(a∣St+1)Q(St+1,a)=Eπ[Q(St+1,⋅)]\sum_{a \in \mathcal{A}} \pi(a \mid S_{t+1}) Q(S_{t+1}, a) = \mathbb{E}_{\pi}[Q(S_{t+1}, \cdot)] is the expected action value under π\pi.

Variance Reduction Analysis

Consider the variance of the TD target conditioned on the transition (St,At,Rt+1,St+1)(S_t, A_t, R_{t+1}, S_{t+1}):

VarAt+1[Rt+1+γQ(St+1,At+1)∣St+1]=γ2VarAt+1[Q(St+1,At+1)]\text{Var}_{A_{t+1}}\left[ R_{t+1} + \gamma Q(S_{t+1}, A_{t+1}) \mid S_{t+1} \right] = \gamma^2 \text{Var}_{A_{t+1}}\left[ Q(S_{t+1}, A_{t+1}) \right]

In standard SARSA, VarAt+1[Q(St+1,At+1)]>0\text{Var}_{A_{t+1}}\left[ Q(S_{t+1}, A_{t+1}) \right] > 0 whenever policy π\pi assigns non-zero probability to multiple actions with distinct values. In Expected SARSA:

Var[∑aπ(a∣St+1)Q(St+1,a)  |  St+1]=0\text{Var}\left[ \sum_{a} \pi(a \mid S_{t+1}) Q(S_{t+1}, a) \;\middle|\; S_{t+1} \right] = 0

The action-sampling variance is identically zero. The only remaining stochasticity in the update stems from environment dynamics (transition probabilities P(St+1∣St,At)P(S_{t+1} \mid S_t, A_t) and stochastic rewards Rt+1R_{t+1}). Because variance is strictly lower, Expected SARSA can use substantially larger learning rates α\alpha without becoming unstable, converging faster than SARSA across almost all tabular benchmarks.

Unifying On-Policy and Off-Policy Control

Expected SARSA separates the behavior policy b(a∣s)b(a \mid s) (which selects actions in the environment) from the target policy π(a∣s)\pi(a \mid s) (which defines the expectation in the TD target):

  1. On-Policy Expected SARSA: Set π=b\pi = b. For an ϵ\epsilon-greedy policy with ∣A∣|\mathcal{A}| actions, the greedy action a∗=arg⁡max⁡aQ(St+1,a)a^* = \arg\max_a Q(S_{t+1}, a) has probability 1−ϵ+ϵ∣A∣1 - \epsilon + \frac{\epsilon}{|\mathcal{A}|}, while every non-greedy action has probability ϵ∣A∣\frac{\epsilon}{|\mathcal{A}|}. The expectation is: Eπ[Q(St+1,⋅)]=(1−ϵ)max⁡aQ(St+1,a)+ϵ∣A∣∑a∈AQ(St+1,a)\mathbb{E}_{\pi}[Q(S_{t+1}, \cdot)] = \left(1 - \epsilon\right) \max_{a} Q(S_{t+1}, a) + \frac{\epsilon}{|\mathcal{A}|} \sum_{a \in \mathcal{A}} Q(S_{t+1}, a)
  2. Off-Policy (Q-learning as a special case): Set π\pi to be purely greedy with respect to QQ, assigning π(a∗∣St+1)=1\pi(a^* \mid S_{t+1}) = 1 and π(a∣St+1)=0\pi(a \mid S_{t+1}) = 0 for all a≠a∗a \neq a^*. The expectation collapses to: ∑a∈Aπ(a∣St+1)Q(St+1,a)=max⁡a∈AQ(St+1,a)\sum_{a \in \mathcal{A}} \pi(a \mid S_{t+1}) Q(S_{t+1}, a) = \max_{a \in \mathcal{A}} Q(S_{t+1}, a) Expected SARSA directly reproduces Q-learning without requiring importance sampling corrections on the next action.

Worked numerical example

Let an agent be in state S0S_0 and take action A0="East"A_0 = \text{"East"}. The transition reaches state S1S_1 and yields immediate reward Rt+1=−1.0R_{t+1} = -1.0.

Parameters:

  • Learning rate α=0.5\alpha = 0.5
  • Discount factor γ=0.9\gamma = 0.9
  • Prior estimate Q(S0,"East")=2.0Q(S_0, \text{"East"}) = 2.0

In state S1S_1, there are three available actions A={a1,a2,a3}\mathcal{A} = \{a_1, a_2, a_3\}:

  • a1a_1 (Safe path): Q(S1,a1)=20.0Q(S_1, a_1) = 20.0 (greedy action, a∗a^*)
  • a2a_2 (Detour): Q(S1,a2)=10.0Q(S_1, a_2) = 10.0
  • a3a_3 (Cliff edge): Q(S1,a3)=−100.0Q(S_1, a_3) = -100.0

The agent follows an ϵ\epsilon-greedy behavior policy with ϵ=0.3\epsilon = 0.3:

  • π(a1∣S1)=1−0.3+0.33=0.7+0.1=0.8\pi(a_1 \mid S_1) = 1 - 0.3 + \frac{0.3}{3} = 0.7 + 0.1 = 0.8
  • π(a2∣S1)=0.33=0.1\pi(a_2 \mid S_1) = \frac{0.3}{3} = 0.1
  • π(a3∣S1)=0.33=0.1\pi(a_3 \mid S_1) = \frac{0.3}{3} = 0.1

1. Expected SARSA Update

First, compute the expected next-state action value:

Eπ[Q(S1,⋅)]=(0.8×20.0)+(0.1×10.0)+(0.1×−100.0)\mathbb{E}_\pi[Q(S_1, \cdot)] = (0.8 \times 20.0) + (0.1 \times 10.0) + (0.1 \times -100.0) Eπ[Q(S1,⋅)]=16.0+1.0−10.0=7.0\mathbb{E}_\pi[Q(S_1, \cdot)] = 16.0 + 1.0 - 10.0 = 7.0

Compute the TD Target and error:

YtExp=Rt+1+γEπ[Q(S1,⋅)]=−1.0+0.9×7.0=−1.0+6.3=5.3Y_t^{\text{Exp}} = R_{t+1} + \gamma \mathbb{E}_\pi[Q(S_1, \cdot)] = -1.0 + 0.9 \times 7.0 = -1.0 + 6.3 = 5.3 δtExp=5.3−Q(S0,A0)=5.3−2.0=3.3\delta_t^{\text{Exp}} = 5.3 - Q(S_0, A_0) = 5.3 - 2.0 = 3.3

Update the Q-value:

Q(S0,A0)←2.0+0.5×3.3=2.0+1.65=3.65Q(S_0, A_0) \leftarrow 2.0 + 0.5 \times 3.3 = 2.0 + 1.65 = 3.65

2. Contrast with SARSA (Sample-Dependent)

  • Case A (Agent randomly samples greedy action a1a_1): YtSARSA=−1.0+0.9×20.0=17.0  ⟹  δt=15.0Y_t^{\text{SARSA}} = -1.0 + 0.9 \times 20.0 = 17.0 \implies \delta_t = 15.0 Q(S0,A0)←2.0+0.5×15.0=9.5Q(S_0, A_0) \leftarrow 2.0 + 0.5 \times 15.0 = 9.5
  • Case B (Agent randomly samples cliff blunder a3a_3): YtSARSA=−1.0+0.9×(−100.0)=−91.0  ⟹  δt=−93.0Y_t^{\text{SARSA}} = -1.0 + 0.9 \times (-100.0) = -91.0 \implies \delta_t = -93.0 Q(S0,A0)←2.0+0.5×(−93.0)=−44.5Q(S_0, A_0) \leftarrow 2.0 + 0.5 \times (-93.0) = -44.5

3. Contrast with Q-Learning (Greedy Max)

YtQ=−1.0+0.9×max⁡(20.0,10.0,−100.0)=−1.0+0.9×20.0=17.0Y_t^{\text{Q}} = -1.0 + 0.9 \times \max(20.0, 10.0, -100.0) = -1.0 + 0.9 \times 20.0 = 17.0 Q(S0,A0)←2.0+0.5×(17.0−2.0)=9.5Q(S_0, A_0) \leftarrow 2.0 + 0.5 \times (17.0 - 2.0) = 9.5

Key Takeaway: SARSA's estimate oscillates violently between +9.5+9.5 and −44.5-44.5 based entirely on the roll of the exploration dice. Q-learning blindly assumes future perfection (+9.5+9.5), ignoring that the agent falls off the cliff 10% of the time. Expected SARSA produces a steady, deterministic update (3.653.65), accurately penalizing the cliff risk without sample variance.

Code

from typing import Dict, Listimport numpy as np
def compute_epsilon_greedy_probs(    q_values: np.ndarray,    epsilon: float,) -> np.ndarray:    """Computes action probabilities under an epsilon-greedy policy."""    num_actions = len(q_values)    best_action = int(np.argmax(q_values))    probs = np.full(num_actions, epsilon / num_actions, dtype=np.float64)    probs[best_action] += 1.0 - epsilon    return probs
def step_expected_sarsa(    q_table: Dict[str, np.ndarray],    s: str,    a_idx: int,    r: float,    s_next: str,    target_probs: np.ndarray,    alpha: float = 0.5,    gamma: float = 0.9,) -> float:    """Updates Q-table using Expected SARSA probability-weighted target."""    expected_next_q = float(np.dot(target_probs, q_table[s_next]))    target = r + gamma * expected_next_q    td_error = target - q_table[s][a_idx]    q_table[s][a_idx] += alpha * td_error    return float(q_table[s][a_idx])
def step_sarsa(    q_table: Dict[str, np.ndarray],    s: str,    a_idx: int,    r: float,    s_next: str,    a_next_idx: int,    alpha: float = 0.5,    gamma: float = 0.9,) -> float:    """Updates Q-table using standard SARSA sampled-action target."""    target = r + gamma * float(q_table[s_next][a_next_idx])    td_error = target - q_table[s][a_idx]    q_table[s][a_idx] += alpha * td_error    return float(q_table[s][a_idx])
def step_q_learning(    q_table: Dict[str, np.ndarray],    s: str,    a_idx: int,    r: float,    s_next: str,    alpha: float = 0.5,    gamma: float = 0.9,) -> float:    """Updates Q-table using Q-learning greedy max target."""    target = r + gamma * float(np.max(q_table[s_next]))    td_error = target - q_table[s][a_idx]    q_table[s][a_idx] += alpha * td_error    return float(q_table[s][a_idx])
# Environment setup matching the worked numerical example# S1 actions: [Safe path = 20.0, Detour = 10.0, Cliff edge = -100.0]q_exp = {"S0": np.array([2.0]), "S1": np.array([20.0, 10.0, -100.0])}q_sarsa_safe = {"S0": np.array([2.0]), "S1": np.array([20.0, 10.0, -100.0])}q_sarsa_cliff = {"S0": np.array([2.0]), "S1": np.array([20.0, 10.0, -100.0])}q_ql = {"S0": np.array([2.0]), "S1": np.array([20.0, 10.0, -100.0])}
# Target policy: epsilon-greedy with epsilon = 0.3 -> probs = [0.8, 0.1, 0.1]probs = compute_epsilon_greedy_probs(q_exp["S1"], epsilon=0.3)
# 1. Expected SARSA updateval_exp = step_expected_sarsa(q_exp, "S0", 0, -1.0, "S1", probs)
# 2. SARSA updates: sampled greedy (index 0) vs sampled blunder (index 2)val_sarsa_safe = step_sarsa(q_sarsa_safe, "S0", 0, -1.0, "S1", a_next_idx=0)val_sarsa_cliff = step_sarsa(q_sarsa_cliff, "S0", 0, -1.0, "S1", a_next_idx=2)
# 3. Q-learning update (greedy max)val_ql = step_q_learning(q_ql, "S0", 0, -1.0, "S1")
print(f"Expected SARSA Q(S0, East): {val_exp:.2f}")# -> Expected SARSA Q(S0, East): 3.65
print(f"SARSA (sampled safe) Q(S0, East): {val_sarsa_safe:.2f}")# -> SARSA (sampled safe) Q(S0, East): 9.50
print(f"SARSA (sampled cliff) Q(S0, East): {val_sarsa_cliff:.2f}")# -> SARSA (sampled cliff) Q(S0, East): -44.50
print(f"Q-learning Q(S0, East): {val_ql:.2f}")# -> Q-learning Q(S0, East): 9.50

Watch Out For

Computational Bottleneck When Action Space |A| Is Massive

While standard SARSA performs an O(1)O(1) array lookup for the sampled action At+1A_{t+1} and Q-learning requires an O(∣A∣)O(|\mathcal{A}|) maximum, Expected SARSA must evaluate the full dot product ∑a∈Aπ(a∣St+1)Q(St+1,a)\sum_{a \in \mathcal{A}} \pi(a \mid S_{t+1}) Q(S_{t+1}, a) across all actions on every transition.

For small action spaces (such as gridworlds or standard discrete control tasks with 4 to 20 actions), this dot product is trivial and the variance reduction yields immediate wall-clock speedups. However, in recommender systems or combinatorial control environments with hundreds of thousands of discrete actions, calculating the explicit expectation at every step creates a severe computational bottleneck. Furthermore, in continuous action spaces, computing the integral ∫π(a∣s)Q(s,a)da\int \pi(a \mid s) Q(s, a) da analytically is intractable without specialized parameterizations.

Concrete Fix:

  1. Under ϵ\epsilon-greedy policies, avoid generating the full probability vector. Decompose the expectation into greedy and uniform components: Eπ[Q]=(1−ϵ)max⁡aQ+ϵ∣A∣∑aQ\mathbb{E}_\pi[Q] = (1 - \epsilon)\max_a Q + \frac{\epsilon}{|\mathcal{A}|}\sum_a Q, which can be computed in a single vectorized pass.
  2. For massive action spaces, use Sampled Expected SARSA: approximate the expectation using a mini-batch of K≪∣A∣K \ll |\mathcal{A}| sampled actions, capturing most variance-reduction benefits at a fraction of the computational cost.

The Quick Version

  • Expected SARSA replaces the single sampled next action Q(St+1,At+1)Q(S_{t+1}, A_{t+1}) with the policy-weighted expectation ∑aπ(a∣St+1)Q(St+1,a)\sum_a \pi(a \mid S_{t+1}) Q(S_{t+1}, a).
  • Eliminating action-selection sample variance allows Expected SARSA to train stably with significantly higher learning rates α\alpha than standard SARSA.
  • Expected SARSA smoothly unifies on-policy and off-policy TD learning: setting the target policy to the greedy policy reproduces Q-learning without importance sampling corrections.
  • The primary trade-off is computational: evaluating the expectation requires an inner product over ∣A∣|\mathcal{A}| actions at every step, making it ideal for discrete spaces but requiring approximations for massive or continuous action domains.