Random Variables & Expected Value
A raffle ticket costs ₹20. Is it a good deal? To answer, you need to turn chance into numbers: what can you win, how likely is each prize, and what do you get on average if you play many times? A random variable and its expected value are the tools that do this.
In this lesson you will learn what a random variable is, write its probability distribution as a table, compute the expected value and variance by hand and with scipy.stats, check them with simulation, and meet continuous random variables, where probabilities are areas.
What is a random variable?
A random variable is a number whose value is decided by a chance process. By convention it is written with a capital letter, such as X, and its possible values with a small letter, such as x.
- X = the number shown by a die (values 1 to 6).
- X = the number of sixes hit in an over.
- X = the rupees you win at a fair game.
- X = the minutes you wait for a bus.
A discrete random variable has separate values you can list (counts, prizes). A continuous random variable can take any value in a range (waiting time, weight).
Probability distributions and expected value
For a discrete random variable, the probability distribution (or probability mass function, PMF) lists each value with its probability. The probabilities must add up to 1.
The expected value E[X], also written μ, is the long-run average: each value weighted by its probability. The variance measures how far X typically lands from μ.
E[X] = Σ x x P(x)
Var(X) = Σ (x - μ)² x P(x) = E[X²] - μ²
SD(X) = √Var(X)For one fair die, every value has probability 1/6:
from fractions import Fraction
values = [1, 2, 3, 4, 5, 6]
probs = [Fraction(1, 6)] * 6
mean = sum(x * p for x, p in zip(values, probs))
var = sum((x - mean) ** 2 * p for x, p in zip(values, probs))
print("E[X] =", mean, "=", float(mean))
print("Var(X) =", var, "=", round(float(var), 4))
print("Check, E[X^2] - E[X]^2 =", sum(x * x * p for x, p in zip(values, probs)) - mean ** 2)E[X] = 7/2 = 3.5 Var(X) = 35/12 = 2.9167 Check, E[X^2] - E[X]^2 = 35/12
The expected value of a die is 3.5, a value the die can never actually show. "Expected" does not mean "most likely"; it means "the average over many repetitions". Both variance formulas give 35/12, about 2.92.
Is the school-fair game fair?
A school fair runs an invented spinning-wheel game. Each spin costs ₹20 and pays one of four prizes.
| Prize (₹) | 0 | 10 | 50 | 200 |
|---|---|---|---|---|
| Probability | 0.55 | 0.30 | 0.13 | 0.02 |
By hand: E[X] = 0 x 0.55 + 10 x 0.30 + 50 x 0.13 + 200 x 0.02 = 0 + 3 + 6.5 + 4 = ₹13.50.
import numpy as np
from scipy import stats
# Invented school-fair game: pay ₹20, spin a wheel, win a prize
prize = np.array([0, 10, 50, 200])
prob = np.array([0.55, 0.30, 0.13, 0.02])
ev = (prize * prob).sum()
var = ((prize - ev) ** 2 * prob).sum()
print(f"Expected prize: ₹{ev:.2f} (ticket ₹20)")
print(f"School's expected profit per player: ₹{20 - ev:.2f}")
print(f"SD of the prize: ₹{np.sqrt(var):.2f}")
wheel = stats.rv_discrete(values=(prize, prob))
print("scipy mean and SD:", wheel.mean(), round(wheel.std(), 2))Expected prize: ₹13.50 (ticket ₹20) School's expected profit per player: ₹6.50 SD of the prize: ₹31.19 scipy mean and SD: 13.5 31.19
A player pays ₹20 and gets back ₹13.50 on average, so the school earns about ₹6.50 per spin. Over 500 spins at the fair, that is roughly ₹3,250 for the school library. stats.rv_discrete(values=(x, p)) builds a distribution object from any probability table and gives you mean(), var(), std(), pmf() and more.
The long run: checking with simulation
Expected value is a long-run idea, so a simulation should approach it as the number of players grows. rng.choice(prize, size=n, p=prob) spins the wheel n times with the given probabilities.
import numpy as np
rng = np.random.default_rng(12)
prize = np.array([0, 10, 50, 200])
prob = np.array([0.55, 0.30, 0.13, 0.02])
for n in [10, 1_000, 100_000]:
wins = rng.choice(prize, size=n, p=prob)
print(f"{n:>7,} players: average prize ₹{wins.mean():.2f}")10 players: average prize ₹16.00 1,000 players: average prize ₹14.92 100,000 players: average prize ₹13.27
With 10 players, the average is ₹16.00, and one lucky ₹200 winner could have pushed it far higher. With 100,000 players it is close to ₹13.50. The large SD (₹31.19) is the reason short runs vary so much: most players win nothing, and a rare big prize swings the average.
Combining random variables
Some rules save a lot of work. For any random variables X and Y and constants a and b:
E[aX + b] = a E[X] + b
Var(aX + b) = a² Var(X) (adding a constant does not change spread)
E[X + Y] = E[X] + E[Y] (always)
Var(X + Y) = Var(X) + Var(Y) (only if X and Y are independent)So the total of two dice should have E = 3.5 + 3.5 = 7 and Var = 35/12 + 35/12 = 35/6. Check by building the whole distribution:
from collections import Counter
from fractions import Fraction
from itertools import product
totals = Counter(a + b for a, b in product(range(1, 7), repeat=2))
pmf = {t: Fraction(c, 36) for t, c in sorted(totals.items())}
for t, p in pmf.items():
print(f"{t:>2}: {str(p):>5} {'*' * totals[t]}")
mean = sum(t * p for t, p in pmf.items())
var = sum((t - mean) ** 2 * p for t, p in pmf.items())
print("E =", mean, " Var =", var)2: 1/36 * 3: 1/18 ** 4: 1/12 *** 5: 1/9 **** 6: 5/36 ***** 7: 1/6 ****** 8: 5/36 ***** 9: 1/9 **** 10: 1/12 *** 11: 1/18 ** 12: 1/36 * E = 7 Var = 35/6
The rules agree with the full calculation. The triangle of stars also shows something important: adding two flat (uniform) distributions gives a peaked one. Add many more and the shape becomes a bell curve, which is the idea behind the central limit theorem.
Continuous random variables
A continuous random variable can take infinitely many values, so the probability of any exact value is 0. Instead, probabilities are areas under a curve called the probability density function (PDF). The cumulative distribution function (CDF) gives P(X ≤ x), the area to the left of x.
The simplest example is the uniform distribution: every value in a range is equally likely. If a bus comes every 10 minutes and you arrive at a random moment, your wait is uniform from 0 to 10 minutes.
from scipy import stats
# A bus comes every 10 minutes and you arrive at a random moment (invented)
wait = stats.uniform(loc=0, scale=10)
print("P(wait < 3 min) =", wait.cdf(3))
print("P(wait 2 to 5 min) =", wait.cdf(5) - wait.cdf(2))
print("P(wait exactly 4 min) =", wait.cdf(4) - wait.cdf(4))
print("Density at 4 min:", wait.pdf(4))
print("Mean wait:", wait.mean(), " SD:", round(wait.std(), 3))P(wait < 3 min) = 0.3 P(wait 2 to 5 min) = 0.3 P(wait exactly 4 min) = 0.0 Density at 4 min: 0.1 Mean wait: 5.0 SD: 2.887
In SciPy, uniform(loc, scale) covers the range from loc to loc + scale. The density is a flat line at height 0.1 (so the total area, 10 x 0.1, is 1). The probability of waiting between 2 and 5 minutes is the area of a rectangle 3 wide and 0.1 high: 0.3. A density is not a probability: it can be larger than 1 for narrow ranges, and only areas under it are probabilities.
Common mistakes
- Thinking E[X] is the most likely value. A die's expected value, 3.5, never appears.
- Probabilities that do not add up to 1. Always check
sum(p) == 1(or close to it with decimals). - Adding variances of dependent variables. Var(X + Y) = Var(X) + Var(Y) needs independence.
- Asking for P(X = x) for a continuous variable. It is 0; ask for a range instead.
Key points
- A random variable is a number decided by chance; it is discrete (countable values) or continuous (any value in a range).
- E[X] = Σ x P(x) is the long-run average; Var(X) = Σ (x - μ)² P(x).
- E[aX + b] = aE[X] + b, Var(aX + b) = a²Var(X), and variances add for independent variables.
stats.rv_discrete(values=(x, p))turns any probability table into a distribution object.- For continuous variables, probabilities are areas under the PDF, found with the CDF.
Exercise
An invented insurance plan for a ₹15,000 phone costs ₹1,200 a year. In a year, the chance of a claim for a screen repair (₹4,000) is 0.15 and for a total loss (₹15,000) is 0.03; otherwise there is no claim. Build a probability table for the insurer's payout, compute the expected payout and SD by hand with NumPy and with stats.rv_discrete, and print the insurer's expected profit per plan.
Show solution
import numpy as np
from scipy import stats
payout = np.array([0, 4000, 15000])
prob = np.array([0.82, 0.15, 0.03])
ev = (payout * prob).sum()
sd = np.sqrt(((payout - ev) ** 2 * prob).sum())
print(f"Expected payout: ₹{ev:.0f}, SD ₹{sd:.0f}")
plan = stats.rv_discrete(values=(payout, prob))
print("scipy:", round(plan.mean()), round(plan.std()))
print(f"Expected profit per plan: ₹{1200 - ev:.0f}")Expected payout: ₹1050, SD ₹2837 scipy: 1050 2837 Expected profit per plan: ₹150
The probability of no claim is 1 - 0.15 - 0.03 = 0.82. On average the insurer pays ₹1,050 per plan, so each ₹1,200 plan earns about ₹150, but the large SD shows why an insurer needs many customers to make that average dependable.
Quick Quiz
1. A game pays ₹100 with probability 0.1 and ₹0 otherwise. What is the expected payout?
E[X] = 100 x 0.1 + 0 x 0.9 = ₹10.
2. X has variance 4. What is the variance of 3X + 5?
Var(aX + b) = a² Var(X) = 9 x 4 = 36; adding 5 does not change the spread.
3. For a continuous random variable, what is P(X = 2.5)?
Probabilities are areas, and a single point has no width.
4. Which statement about expected value is true?
E[X] is a long-run average and may not be a possible value at all.
Learn Statistics with a mentor
Free lessons get you started. Our Data Science & Machine Learning training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
