Lesson 37 · Probability and Statistics in python
Understanding the Law of Large Numbers Through Dice Roll Simulations in Python
Welcome! In this lesson, we explore probability using simple dice rolls. We will use Python to experiment, observe the Law of Large Numbers, and learn how…
- CourseProbability and Statistics in python
- Lesson37 of 35
- Video16 min
- FormatJupyter notebook · 11 code cells
What you'll learn
Data
No separate download needed — the notebook creates or downloads everything it uses.
📓 Full notebook
Download .ipynbSimulating Dice Rolls and the Law of Large Numbers#
Welcome! In this lesson, we explore probability using simple dice rolls.
We will use Python to experiment, observe the Law of Large Numbers, and learn how real randomness behaves.
Even if you have never programmed before, you will be able to follow along.
By the end, you will be able to describe what probability means and simulate random outcomes yourself.
# Setting up the basics
import warnings; warnings.filterwarnings("ignore")
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
np.random.seed(42)
print("Setup complete.")
What is Probability?#
Probability is how likely something is to happen.
For example, when you roll a fair dice, each number from 1 to 6 is equally likely, so each has a probability of 1/6.
Probabilities are always between 0 and 1.
# Rolling one dice once
roll = np.random.randint(1, 7)
print("You rolled a:", roll)
# Let us roll the dice ten times and see what happens
rolls = np.random.randint(1, 7, size=10)
print("Ten dice rolls:", rolls)
# Let's look at the counts for each outcome
counts = pd.Series(rolls).value_counts().sort_index()
print(counts)
# Visualize the distribution with a bar chart
counts.plot(kind="bar", color="skyblue")
plt.title("Dice Roll Frequencies (10 Rolls)")
plt.xlabel("Dice Number")
plt.ylabel("Count")
plt.show()
Experimental vs Theoretical Probability#
Theoretical probability is what math predicts. For one dice, each outcome should happen 1/6 of the time.
Experimental probability is what we observe by doing the experiment in real life (or in code!).
With more rolls, experimental probability gets closer to the theoretical value.
# Roll 1000 times to see probability in action
large_rolls = np.random.randint(1, 7, size=1000)
large_counts = pd.Series(large_rolls).value_counts().sort_index()
print(large_counts)
# Plotting the frequencies for 1000 rolls
large_counts.plot(kind="bar", color="limegreen")
plt.title("Dice Roll Frequencies (1000 Rolls)")
plt.xlabel("Dice Number")
plt.ylabel("Count")
plt.show()
The Law of Large Numbers#
As we roll a dice more and more times, our observed averages approach the theoretical probability.
This is called the Law of Large Numbers.
It explains why casinos, insurers, and scientists trust average results in the long run.
It also reminds us that random short-term streaks are normal.
# Show the average dice value growing over time
N = 1000
rolls = np.random.randint(1, 7, size=N)
cumulative_avg = np.cumsum(rolls) / np.arange(1, N + 1)
plt.plot(cumulative_avg, color="orange")
plt.axhline(3.5, linestyle="--", color="black", label="Theoretical avg (3.5)")
plt.title("Average Dice Value Over Many Rolls")
plt.xlabel("Number of Rolls")
plt.ylabel("Cumulative Average")
plt.legend()
plt.show()
Practice: Try your own dice experiment!#
Change the number of rolls or use a different 'sided dice' in the code cells above.
What do you notice about the averages and the frequencies?
Write down your observations.
# Interactive: Choose number of dice rolls
num_trials = int(input("How many times would you like to roll the dice? "))
user_rolls = np.random.randint(1, 7, size=num_trials)
print("Results:", user_rolls)
# Mini-project: Simulate rolling two dice and adding their values
n_pairs = 10000
die1 = np.random.randint(1, 7, size=n_pairs)
die2 = np.random.randint(1, 7, size=n_pairs)
sums = die1 + die2
plt.hist(sums, bins=np.arange(2, 14)-0.5, color="violet", rwidth=0.85)
plt.title("Sum Distribution of Two Dice (10,000 Rolls)")
plt.xlabel("Sum of Two Dice")
plt.ylabel("Frequency")
plt.xticks(range(2, 13))
plt.show()
Key Takeaways#
- Probability is the math of chance.
- Experimental results get closer to theory as we collect more data.
- The Law of Large Numbers helps us trust the long-term results of experiments.
- Coding helps us quickly test and visualize our ideas.
You have learned how to simulate experiments and make sense of the results!
# Challenge: Can you design an experiment with a different 'unfair dice'?
weights = [0.05, 0.10, 0.20, 0.20, 0.20, 0.25]
unfair_rolls = np.random.choice(np.arange(1, 7), size=1000, p=weights)
unfair_counts = pd.Series(unfair_rolls).value_counts().sort_index()
print(unfair_counts)
unfair_counts.plot(kind="bar", color="red")
plt.title("Unfair Dice Roll Frequencies")
plt.xlabel("Dice Number")
plt.ylabel("Count")
plt.show()
Your Turn: Extra Practice#
Try simulating a coin flip, a three-sided spinner, or even drawing colored balls.
Change sample sizes and look for patterns.
Let us know your discoveries in the comments below!
Recap and Next Steps#
You have learned the basics of probability and statistics by simulating dice rolls.
Now you know how to:
- Simulate random experiments
- Visualize distributions
- Understand the Law of Large Numbers
Continue experimenting and share your questions or results with others!
Thanks for joining! Subscribe for more tutorials!#
If you enjoyed this lesson, please like, subscribe, and ring the bell for more Python math adventures.
Happy coding and see you in the next lesson!
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



