What is Reinforcement Learning?
RL is fundamentally different from supervised and unsupervised learning. There is no labelled dataset. Instead, an agent learns by interacting with an environment, taking actions and receiving feedback in the form of rewards. The goal: learn a policy — a strategy for choosing actions — that maximises cumulative reward over time.
The Five Core Components
The RL Interaction Loop
import gymnasium as gym # pip install gymnasium
# Classic CartPole environment: balance a pole on a cart
env = gym.make("CartPole-v1", render_mode=None)
# State: [cart_pos, cart_velocity, pole_angle, pole_angular_velocity]
# Action: 0 = push left, 1 = push right
# Reward: +1 for every timestep the pole stays upright
# Episode ends: pole falls (angle > 12°) or cart moves off screen or 500 steps
obs, info = env.reset(seed=42)
print(f"Initial state: {obs}") # 4-dim vector
print(f"Action space: {env.action_space}") # Discrete(2)
print(f"Obs space: {env.observation_space}") # Box(4,)
# ── Random agent (baseline — no learning)
total_reward = 0
obs, _ = env.reset()
for step in range(500):
action = env.action_space.sample() # random action
obs, reward, terminated, truncated, info = env.step(action)
total_reward += reward
if terminated or truncated:
break
print(f"Random agent survived {step+1} steps, total reward: {total_reward}")Policy and Value Functions
The policy $\pi(a|s)$ is the agent's strategy — a probability distribution over actions given the current state. The agent's goal is to find the optimal policy $\pi^*$ that maximises expected return.
The Bellman Equation
The cornerstone of RL — a recursive relationship expressing $V^\pi(s)$ in terms of immediate reward and successor state values:
Exploration vs. Exploitation
The central dilemma of RL: exploit what you know (choose the action with highest estimated reward) vs. explore new actions (discover potentially better ones). The $\epsilon$-greedy strategy balances both:
import numpy as np
class EpsilonGreedy:
def __init__(self, n_actions, eps_start=1.0, eps_end=0.01, eps_decay=0.995):
self.n_actions = n_actions
self.eps = eps_start
self.eps_end = eps_end
self.eps_decay = eps_decay
def select_action(self, q_values):
if np.random.random() < self.eps:
return np.random.randint(self.n_actions) # explore
return np.argmax(q_values) # exploit
def decay(self):
self.eps = max(self.eps_end, self.eps * self.eps_decay)
# Epsilon decays from 1.0 → 0.01 over ~1000 steps
eg = EpsilonGreedy(n_actions=2)
for i in range(10):
eg.decay()
if i % 2 == 0:
print(f" Step {i*100+100:4d}: eps = {eg.eps:.4f}")RL Algorithm Taxonomy
Summary
- RL = agent + environment. Agent learns by trial-and-error, not from labelled data.
- Goal: maximise discounted return $G_t = \sum \gamma^k R_{t+k+1}$.
- $Q^*(s,a)$: optimal action-value. Bellman equation expresses it recursively.
- $\epsilon$-greedy: explore randomly with prob $\epsilon$, exploit best known action otherwise. Decay $\epsilon$ over time.