How to Calculate Expected Value of a Continuous Random Variable

Expected value represents the long-run average outcome of a random variable. For continuous random variables, we calculate it using integration rather than summation. The formal definition is:

Key Insights

  • Expected value for continuous random variables uses integration (∫ x·f(x)dx) instead of summation, representing the center of mass of the probability distribution
  • Numerical integration and Monte Carlo simulation provide practical alternatives when analytical solutions are intractable or impossible
  • Not all distributions have defined expected values—the Cauchy distribution is a critical counterexample where the integral diverges

Introduction to Expected Value for Continuous Variables

Expected value represents the long-run average outcome of a random variable. For continuous random variables, we calculate it using integration rather than summation. The formal definition is:

E[X] = ∫ x·f(x)dx

where f(x) is the probability density function (PDF) and the integral spans the variable’s support.

This differs fundamentally from discrete random variables, where E[X] = Σ x·P(X=x). The transition from sum to integral reflects the shift from counting probabilities at specific points to measuring probability density across a continuum.

Expected value appears everywhere in quantitative fields. Financial analysts use it for portfolio optimization, engineers apply it in reliability analysis, and data scientists employ it in loss function design. Understanding how to calculate it accurately is essential for making data-driven decisions.

Mathematical Foundation

The expected value of a continuous random variable X with PDF f(x) is:

E[X] = ∫_{-∞}^{∞} x·f(x)dx

This integral must be taken over the entire support of X (the range where f(x) > 0). For the expected value to exist, the integral must converge absolutely:

∫_{-∞}^{∞} |x|·f(x)dx < ∞

The PDF must satisfy ∫ f(x)dx = 1 (total probability equals one). The expected value represents the distribution’s center of mass—if you imagine the PDF as a physical shape with uniform density, E[X] is where it would balance on a fulcrum.

import numpy as np
import matplotlib.pyplot as plt
from scipy import integrate

# Visualize expected value as center of mass
x = np.linspace(0, 10, 1000)
# Beta distribution shifted and scaled
pdf = 12 * x**2 * (10-x) / 10000

# Calculate expected value
expected_value = integrate.quad(lambda t: t * 12 * t**2 * (10-t) / 10000, 0, 10)[0]

plt.figure(figsize=(10, 6))
plt.plot(x, pdf, 'b-', linewidth=2, label='PDF f(x)')
plt.axvline(expected_value, color='r', linestyle='--', linewidth=2, 
            label=f'E[X] = {expected_value:.2f}')
plt.fill_between(x, pdf, alpha=0.3)
plt.xlabel('x', fontsize=12)
plt.ylabel('Density', fontsize=12)
plt.title('Expected Value as Center of Mass', fontsize=14)
plt.legend(fontsize=11)
plt.grid(alpha=0.3)
plt.show()

Step-by-Step Calculation Process

Follow this systematic approach:

  1. Identify the PDF and domain: Determine f(x) and the interval [a, b] where it’s non-zero
  2. Set up the integral: Write E[X] = ∫_a^b x·f(x)dx
  3. Solve analytically: Use integration techniques (substitution, integration by parts, etc.)
  4. Verify and interpret: Check that the result makes intuitive sense

Let’s calculate E[X] for a uniform distribution on [a, b]:

import numpy as np
from scipy import integrate
from scipy.stats import uniform

# Uniform distribution on [2, 8]
a, b = 2, 8

# Analytical calculation
# For uniform distribution: f(x) = 1/(b-a) for x in [a,b]
# E[X] = ∫ x · 1/(b-a) dx from a to b
# E[X] = [x²/2]/(b-a) from a to b
# E[X] = (b² - a²)/(2(b-a)) = (b+a)/2
analytical_ev = (a + b) / 2
print(f"Analytical E[X]: {analytical_ev}")

# Numerical verification
def integrand(x):
    return x * (1 / (b - a))

numerical_ev, error = integrate.quad(integrand, a, b)
print(f"Numerical E[X]: {numerical_ev:.6f}")
print(f"Integration error: {error:.2e}")

# Verify with scipy.stats
dist = uniform(loc=a, scale=b-a)
scipy_ev = dist.mean()
print(f"SciPy E[X]: {scipy_ev}")

Numerical Integration Methods

Many distributions lack closed-form solutions for expected value. Numerical integration becomes essential in these cases.

SciPy’s integrate.quad() uses adaptive quadrature, automatically adjusting step sizes for accuracy. It’s robust for most well-behaved functions:

from scipy import integrate
from scipy.stats import expon
import numpy as np

# Exponential distribution with rate λ = 0.5
lambda_rate = 0.5

# PDF: f(x) = λ·e^(-λx) for x ≥ 0
# E[X] = 1/λ (analytical result)
analytical = 1 / lambda_rate

# Numerical integration
def integrand(x):
    return x * lambda_rate * np.exp(-lambda_rate * x)

# Integrate from 0 to a large upper bound (effectively infinity)
numerical, error = integrate.quad(integrand, 0, np.inf)

print(f"Analytical E[X]: {analytical}")
print(f"Numerical E[X]: {numerical:.6f}")
print(f"Relative error: {abs(numerical - analytical) / analytical * 100:.4f}%")

# Compare with scipy.stats
dist = expon(scale=1/lambda_rate)
print(f"SciPy E[X]: {dist.mean()}")

For improper integrals (infinite bounds), quad() handles them gracefully. You can also specify weight='exp' for exponentially decaying integrands to improve accuracy.

Monte Carlo Simulation Approach

Monte Carlo estimation provides an intuitive alternative: generate random samples from the distribution and compute their average. By the Law of Large Numbers, the sample mean converges to E[X] as sample size increases.

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm

# Normal distribution with μ=5, σ=2
mu, sigma = 5, 2
true_ev = mu  # For normal distribution, E[X] = μ

# Monte Carlo estimation with increasing sample sizes
sample_sizes = np.logspace(1, 5, 50, dtype=int)
estimates = []

np.random.seed(42)
for n in sample_sizes:
    samples = np.random.normal(mu, sigma, n)
    estimates.append(np.mean(samples))

# Plot convergence
plt.figure(figsize=(10, 6))
plt.semilogx(sample_sizes, estimates, 'b-', alpha=0.7, label='MC Estimate')
plt.axhline(true_ev, color='r', linestyle='--', linewidth=2, label=f'True E[X] = {true_ev}')
plt.fill_between(sample_sizes, true_ev - 0.1, true_ev + 0.1, 
                 alpha=0.2, color='r', label='±0.1 tolerance')
plt.xlabel('Sample Size', fontsize=12)
plt.ylabel('Estimated E[X]', fontsize=12)
plt.title('Monte Carlo Convergence to Expected Value', fontsize=14)
plt.legend(fontsize=11)
plt.grid(alpha=0.3)
plt.show()

# Final estimate with large sample
final_samples = 1000000
final_estimate = np.mean(np.random.normal(mu, sigma, final_samples))
print(f"MC estimate (n={final_samples:,}): {final_estimate:.6f}")
print(f"True E[X]: {true_ev}")
print(f"Error: {abs(final_estimate - true_ev):.6f}")

Monte Carlo methods work when you can sample from the distribution but can’t integrate analytically. The convergence rate is O(1/√n), meaning you need 100× more samples for 10× better accuracy.

Common Distributions and Their Expected Values

Here’s a practical comparison of theoretical formulas versus computed values:

import numpy as np
from scipy import stats
import pandas as pd

distributions = {
    'Uniform[0,1]': (stats.uniform(0, 1), 0.5),
    'Exponential(λ=2)': (stats.expon(scale=0.5), 0.5),
    'Normal(μ=3,σ=1)': (stats.norm(3, 1), 3.0),
    'Beta(α=2,β=5)': (stats.beta(2, 5), 2/7),
    'Gamma(k=2,θ=2)': (stats.gamma(2, scale=2), 4.0),
}

results = []
np.random.seed(42)

for name, (dist, theoretical) in distributions.items():
    # Monte Carlo estimate
    samples = dist.rvs(size=100000)
    mc_estimate = np.mean(samples)
    
    # SciPy built-in
    scipy_mean = dist.mean()
    
    results.append({
        'Distribution': name,
        'Theoretical': theoretical,
        'SciPy': scipy_mean,
        'Monte Carlo': mc_estimate,
        'MC Error': abs(mc_estimate - theoretical)
    })

df = pd.DataFrame(results)
print(df.to_string(index=False))

Practical Applications and Pitfalls

When Expected Value Doesn’t Exist

The Cauchy distribution is the canonical example of a distribution without a defined expected value. Its heavy tails cause the integral to diverge:

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import cauchy

# Cauchy distribution (location=0, scale=1)
dist = cauchy(0, 1)

# Attempt Monte Carlo estimation
sample_sizes = np.logspace(2, 6, 50, dtype=int)
estimates = []

np.random.seed(42)
for n in sample_sizes:
    samples = dist.rvs(size=n)
    estimates.append(np.mean(samples))

# Plot the failure to converge
plt.figure(figsize=(10, 6))
plt.semilogx(sample_sizes, estimates, 'b-', alpha=0.7)
plt.axhline(0, color='r', linestyle='--', alpha=0.5, label='Theoretical median = 0')
plt.xlabel('Sample Size', fontsize=12)
plt.ylabel('Sample Mean', fontsize=12)
plt.title('Cauchy Distribution: Sample Mean Does Not Converge', fontsize=14)
plt.legend(fontsize=11)
plt.grid(alpha=0.3)
plt.ylim(-5, 5)
plt.show()

print("Sample means for different runs (n=1,000,000):")
for i in range(5):
    samples = dist.rvs(size=1000000)
    print(f"Run {i+1}: {np.mean(samples):.4f}")

The sample means jump erratically regardless of sample size. This demonstrates why checking for absolute convergence is critical before computing expected values.

Expected Value vs. Median vs. Mode

These three measures of central tendency serve different purposes. For skewed distributions, expected value can be misleading. In risk analysis, you often care more about the median (50th percentile) or specific quantiles than the mean. For the exponential distribution, E[X] = 1/λ but the median is (ln 2)/λ ≈ 0.693/λ, showing significant difference.

Truncated Distributions

When working with truncated distributions (restricted to a subset of the original support), recalculate the expected value over the truncated domain with the renormalized PDF. Don’t naively use the original distribution’s expected value.

The expected value is a powerful tool for summarizing distributions, but always verify that it exists and represents meaningful information for your specific application. Combine it with other statistics—variance, quantiles, and visualizations—for complete understanding.

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.