Skip to content
AI360XpertBeta

First-Visit vs Every-Visit MC Prediction

When a state shows up twice in one episode, first-visit counts only the return after the first hello, while every-visit counts every hello. One is strictly unbiased, the other squeezes more data from each episode.

One looping episode gives returns 10.0, 8.0 and 5.0, of which first-visit keeps only 10.0 for the revisited state while every-visit averages 10.0 and 5.0 into 7.5
One looping episode gives returns 10.0, 8.0 and 5.0, of which first-visit keeps only 10.0 for the revisited state while every-visit averages 10.0 and 5.0 into 7.5

Why Does This Exist?

Monte Carlo prediction estimates a state's value by averaging the actual returns seen after visiting it: finish episodes, add up each visit's discounted future rewards, divide. The parent method is Monte Carlo methods, and action values get their own treatment at Monte Carlo estimation of action values.

Loops force a decision. In any environment with cycles, the agent can pass through the same state twice in one episode, at step t1t_1 and again at t2t_2, with different remaining futures. Which returns belong in the average for that state? First-visit keeps only the return after the first arrival and discards the rest. Every-visit keeps a return after each arrival. Both converge to the true value with enough episodes, yet on finite data they disagree, and the disagreement is largest exactly where states recur.

This page defines both estimators, shows where their numbers split, and says when the split matters. Control built on these estimates is Monte Carlo control.

The one idea you need first.

A return GtG_t is the discounted sum of rewards from step tt to termination: Gt=Rt+1+γRt+2+γ2Rt+3+…G_t = R_{t+1} + \gamma R_{t+2} + \gamma^2 R_{t+3} + \dots, with discount γ\gamma in [0,1][0, 1] weighting near rewards over far ones. The state value Vπ(s)V^\pi(s) is the expected return from ss under policy π\pi. Monte Carlo replaces that expectation with an average over visits actually seen.

Think of It Like This

One comment card per guest versus one per visit

A hotel manager wants a cleanliness score for the lobby. Some guests pass through three times a day. Under one-card-per-guest, each visitor scores the lobby once, on first arrival: every card comes from a different person, so the average is clean but slow to build. Under one-card-per-visit, every pass drops a card: data piles up three times faster, but one grumpy guest having a bad day counts three times, and all three cards share that day's mood.

Point for point: the guest is the episode, each pass is a state visit, the mood of the day is the shared downstream randomness, and the grumpy triple count is every-visit's finite-sample bias. Where it stops: hotel guests remember earlier passes and change their later scores, while an MDP's future from a state depends only on the state, never on how many times the agent has seen it.

How It Actually Works

First-visit: one sample per episode

For state ss in an episode, let T1(s)\mathcal{T}_1(s) be the earliest step with St=sS_t = s. Over MM episodes the estimate averages the return after that step wherever the state appeared:

VFV(s)=∑e=1MI(s∈τ(e)) GT1(e)(s)(e)∑e=1MI(s∈τ(e))V_{\text{FV}}(s) = \frac{\sum_{e=1}^M \mathbb{I}(s \in \tau^{(e)})\, G_{\mathcal{T}_1^{(e)}(s)}^{(e)}}{\sum_{e=1}^M \mathbb{I}(s \in \tau^{(e)})}

Here I\mathbb{I} is 11 when the episode visited ss and 00 otherwise. Because each episode donates at most one return and episodes are independent, the samples are independent and identically distributed. The estimator is unbiased at any sample size, E[VFV(s)]=Vπ(s)\mathbb{E}[V_{\text{FV}}(s)] = V^\pi(s), and converges by the law of large numbers with variance shrinking like 1/M1/M.

Every-visit: every arrival counts

Now keep all of them. With Tall(e)(s)\mathcal{T}_{\text{all}}^{(e)}(s) the set of every step where ss occurs:

VEV(s)=∑e=1M∑t∈Tall(e)(s)Gt(e)∑e=1M∣Tall(e)(s)∣V_{\text{EV}}(s) = \frac{\sum_{e=1}^M \sum_{t \in \mathcal{T}_{\text{all}}^{(e)}(s)} G_t^{(e)}}{\sum_{e=1}^M |\mathcal{T}_{\text{all}}^{(e)}(s)|}

Returns from two visits in one episode overlap: the earlier return physically contains the later one, Gta=Rta+1+⋯+γtb−taGtbG_{t_a} = R_{t_a+1} + \dots + \gamma^{t_b - t_a} G_{t_b}. Shared downstream rewards make the samples correlated, so the estimator carries finite-sample bias. It still converges to Vπ(s)V^\pi(s) as episodes pile up, and because it harvests more samples per episode its mean squared error is often lower early on.

Both update incrementally without storing history. On each recorded visit with return GtG_t, with N(s)N(s) counting recorded visits:

N(s)←N(s)+1,V(s)←V(s)+1N(s)[Gt−V(s)]N(s) \leftarrow N(s) + 1, \qquad V(s) \leftarrow V(s) + \frac{1}{N(s)}\left[G_t - V(s)\right]

Worked example

Undiscounted, γ=1.0\gamma = 1.0. Episode 1 loops: S1S_1 with reward 22, then S2S_2 with reward 33, then S1S_1 again with reward 55, then termination. Working backward, returns are G2=5.0G_2 = 5.0 at the second S1S_1, G1=3.0+5.0=8.0G_1 = 3.0 + 5.0 = 8.0 at S2S_2, and G0=2.0+8.0=10.0G_0 = 2.0 + 8.0 = 10.0 at the first S1S_1.

First-visit keeps 10.010.0 for S1S_1 and 8.08.0 for S2S_2, so VFV(S1)=10.0V_{\text{FV}}(S_1) = 10.0 and VFV(S2)=8.0V_{\text{FV}}(S_2) = 8.0. Every-visit additionally keeps the 5.05.0 after the second S1S_1: VEV(S1)=(10.0+5.0)/2=7.5V_{\text{EV}}(S_1) = (10.0 + 5.0)/2 = 7.5 while VEV(S2)=8.0V_{\text{EV}}(S_2) = 8.0.

Episode 2 is short: S2S_2 with reward 44, then S1S_1 with reward 22. Returns are 2.02.0 at S1S_1 and 4.0+2.0=6.04.0 + 2.0 = 6.0 at S2S_2. Incremental updates give first-visit VFV(S1)=10.0+(2.0−10.0)/2=6.0V_{\text{FV}}(S_1) = 10.0 + (2.0 - 10.0)/2 = 6.0 and VFV(S2)=8.0+(6.0−8.0)/2=7.0V_{\text{FV}}(S_2) = 8.0 + (6.0 - 8.0)/2 = 7.0. Every-visit folds in the extra sample: VEV(S1)=7.5+(2.0−7.5)/3=5.67V_{\text{EV}}(S_1) = 7.5 + (2.0 - 7.5)/3 = 5.67, matching (10.0+5.0+2.0)/3(10.0 + 5.0 + 2.0)/3, and VEV(S2)=7.0V_{\text{EV}}(S_2) = 7.0. Note S2S_2 agrees under both rules in both episodes, because it never repeated within an episode. The methods split only where states recur.

Code

Both estimators on the exact two episodes above, using only the standard library.

from typing import Dict, List, Tuple
Episode = List[Tuple[str, float]]

def episode_returns(episode: Episode, gamma: float = 1.0) -> List[Tuple[str, float]]:    """Return per step, computed backward then restored to forward order."""    G = 0.0    out: List[Tuple[str, float]] = []    for state, reward in reversed(episode):        G = gamma * G + reward        out.append((state, G))    out.reverse()    return out

def first_visit(episodes: List[Episode], gamma: float = 1.0) -> Dict[str, float]:    """Average the return after each state's first appearance per episode."""    total: Dict[str, float] = {}    count: Dict[str, int] = {}    for episode in episodes:        seen = set()        for state, G in episode_returns(episode, gamma):            if state not in seen:                seen.add(state)                total[state] = total.get(state, 0.0) + G                count[state] = count.get(state, 0) + 1    return {s: total[s] / count[s] for s in total}

def every_visit(episodes: List[Episode], gamma: float = 1.0) -> Dict[str, float]:    """Average the return after every appearance of each state."""    total: Dict[str, float] = {}    count: Dict[str, int] = {}    for episode in episodes:        for state, G in episode_returns(episode, gamma):            total[state] = total.get(state, 0.0) + G            count[state] = count.get(state, 0) + 1    return {s: total[s] / count[s] for s in total}

episodes: List[Episode] = [[("S1", 2.0), ("S2", 3.0), ("S1", 5.0)], [("S2", 4.0), ("S1", 2.0)]]fv, ev = first_visit(episodes), every_visit(episodes)for state in sorted(fv):    print(f"V_FV({state}) = {fv[state]:.2f}")  # -> V_FV(S1) = 6.00 and V_FV(S2) = 7.00for state in sorted(ev):    print(f"V_EV({state}) = {ev[state]:.2f}")  # -> V_EV(S1) = 5.67 and V_EV(S2) = 7.00

The prints match the hand trace: first-visit 6.006.00 and 7.007.00, every-visit 5.675.67 and 7.007.00.

Watch Out For

Trusting Monte Carlo values built from a handful of long episodes

Each return sums every reward to termination with no bootstrapping to absorb shocks, so one chaotic episode injects its noise into every state it touched. With long horizons or jittery rewards, values swing wildly between evaluation batches.

The symptom is estimates that jump by large fractions from one batch to the next, and policy updates that oscillate instead of settling. The fix is volume before control: hundreds of episodes minimum, a discount below 11 to damp far noise, or a switch to temporal-difference bootstrapping that replaces distant randomness with learned estimates.

Letting one looping episode vote many times in a small dataset

Every-visit counts each pass of a cycle separately, so a single episode stuck in a loop before a big penalty or payoff contributes that anomaly once per pass. In small logs the revisited states inherit the outlier several times over.

The symptom is severe over or underestimation concentrated exactly on states that recur, while non-repeating states look sane. The fix is first-visit whenever unbiasedness on limited data matters, reserving every-visit for high-throughput settings where sample volume washes the correlation out.

The Quick Version

  • First-visit averages the return after a state's first appearance per episode, giving independent samples and a strictly unbiased estimate.
  • Every-visit averages after every appearance, harvesting more samples per episode at the price of correlated returns and finite-sample bias.
  • Both converge to the true value Vπ(s)V^\pi(s) as episodes grow; every-visit often has lower error early because it uses more data.
  • The two agree wherever states never repeat within an episode and split only on revisited states: 10.010.0 versus 7.57.5 after the looping episode here.
  • Both need complete episodes and suffer higher variance than bootstrapping methods, since whole-trajectory noise lands in every return.