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.
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 and again at , 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 is the discounted sum of rewards from step to termination: , with discount in weighting near rewards over far ones. The state value is the expected return from under policy . 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 in an episode, let be the earliest step with . Over episodes the estimate averages the return after that step wherever the state appeared:
Here is when the episode visited and 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, , and converges by the law of large numbers with variance shrinking like .
Every-visit: every arrival counts
Now keep all of them. With the set of every step where occurs:
Returns from two visits in one episode overlap: the earlier return physically contains the later one, . Shared downstream rewards make the samples correlated, so the estimator carries finite-sample bias. It still converges to 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 , with counting recorded visits:
Worked example
Undiscounted, . Episode 1 loops: with reward , then with reward , then again with reward , then termination. Working backward, returns are at the second , at , and at the first .
First-visit keeps for and for , so and . Every-visit additionally keeps the after the second : while .
Episode 2 is short: with reward , then with reward . Returns are at and at . Incremental updates give first-visit and . Every-visit folds in the extra sample: , matching , and . Note 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.00The prints match the hand trace: first-visit and , every-visit and .
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 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 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: versus after the looping episode here.
- Both need complete episodes and suffer higher variance than bootstrapping methods, since whole-trajectory noise lands in every return.