Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Python  Module 6 – Modules, packages and the standard library

Random numbers, simulations and statistics

Generate repeatable random data with seeds, pick and shuffle with weights, estimate odds by simulation and summarise data with the statistics module.

  • Beginner
  • 25 minutes
  • Examples run with Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free lesson, Pro answers: 25 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Generate repeatable random data with seeds and separate Random objects
  • Choose, sample and shuffle, with weights and without repeats
  • Estimate a probability by simulation and judge how precise the estimate is
  • Summarise data with the statistics module, from averages to quartiles
  • Choose secrets instead of random for tokens, passwords and codes

Before you start

What you’ll learn · Before you start

What you will learn

  • Generate repeatable random data with seeds and separate Random objects
  • Choose, sample and shuffle, with weights and without repeats
  • Estimate a probability by simulation and judge how precise the estimate is
  • Summarise data with the statistics module, from averages to quartiles
  • Choose secrets instead of random for tokens, passwords and codes

Before you start

On this page

How likely is at least one six in four rolls of a die? Python answers in a second by playing the game 100,000 times and counting, and the same tools pick quiz questions, shuffle a deck and split data for a test. They come from the random module and its pseudo-random: Made by a fixed algorithm that only looks random. The random module's Mersenne Twister turns a seed into such a stream, so anyone who learns the generator's state can work out every number that follows. generator: a fixed algorithm, the Mersenne Twister, turns a starting value called the seed: The starting value of a pseudo-random generator. The same seed gives the same stream of numbers, so random.seed(42) or random.Random(42) makes a simulation or a test repeatable. into a long stream of numbers that pass for random, and the same seed always gives the same stream.

You will make runs repeatable, pick with weights and without repeats, measure how far a simulated answer can be from the truth, and describe the numbers you collect with the statistics module. One rule comes before all of it: random is made for games, simulations and tests, never for passwords or tokens, which come from the secrets module.

Seeds make a run repeatable

random.random() returns a float from 0.0 up to, but not including, 1.0, and every other function of the module draws on the same hidden generator. Python seeds that generator from the operating system’s source of randomness when the module is imported, so two runs of a program normally see different numbers. Call random.seed() with a value of your own and the stream starts again from a known point:

The same seed, the same dice Python · seeds.py
import random

# The same seed gives the same stream, run after run.
random.seed(42)
first = [random.randint(1, 6) for _ in range(10)]
random.seed(42)
again = [random.randint(1, 6) for _ in range(10)]
print(first)
print("same again:", again == first)

# Any other draw from the shared generator moves the stream along.
random.seed(42)
random.random()
print([random.randint(1, 6) for _ in range(10)])

# A Random object has a generator of its own.
dice = random.Random(42)
coins = random.Random(7)
print([dice.randint(1, 6) for _ in range(10)])
print("".join(coins.choice("HT") for _ in range(10)))

Output

[6, 1, 1, 6, 3, 2, 2, 2, 6, 1]
same again: True
[1, 6, 3, 2, 2, 2, 6, 1, 6, 6]
[6, 1, 1, 6, 3, 2, 2, 2, 6, 1]
THTHHHTHHH

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 seeds.py

  • The first two lines are the whole point of a seed: ten rolls after seed(42), then exactly the same ten after a second seed(42).
  • In the third line, one call to random() came first. It used up the two internal numbers behind the first two rolls of the first line, so the rolls start where its third roll was. Any code that draws from the module’s shared generator moves the stream along for everyone else.
  • A random.Random object carries a generator of its own: Random(42) rolls the same dice as seed(42), and nothing outside the object can disturb its stream. Give each simulation or test its own Random instead of seeding the module.

Step through the same run as requests to a generator and the rolls it hands back, and watch where each line of rolls begins:

Interactive · message by message One stream of numbers, drawn in turn Step through seeds.py. Each arrow is a request to a generator or the rolls it hands back; watch where each line of rolls starts.
One stream of numbers, drawn in turn, step 6 of 6. Messages so far: Your code to Shared generator: seed(42); Shared generator to Your code: 6, 1, 1, 6, 3, 2 …; Your code to Shared generator: seed(42) again; Your code to Shared generator: random(); Shared generator to Your code: 1, 6, 3, 2, 2 …; Random(42) to Your code: 6, 1, 1, 6, 3, 2 ….Your codeseeds.pyShared generatortwo numbers usedRandom(42)a generator of its ownseed(42)6, 1, 1, 6, 3, 2 …seed(42) againrandom()1, 6, 3, 2, 2 …6, 1, 1, 6, 3, 2 …

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Seed the module. random.seed(42) fills the shared generator's state from 42. From now on every function of the module, called from any part of the program, takes its numbers from this one stream.
  2. Ten rolls. Ten calls to randint(1, 6) take the next numbers of the stream and turn them into rolls, which the program prints as its first line.
  3. The same seed again. A second seed(42) puts the state back where it started, so the next ten rolls are the same ten, and the program prints same again: True.
  4. Something else draws first. After a third seed(42), one call to random() comes before the rolls. A float is made from two numbers of the stream, so it takes the two that gave the first two rolls.
  5. The rolls start later. The ten rolls now begin where the third roll was: 1, 6, 3, 2 … The stream has not changed. Something else drew from it first, as any code that calls the module can.
  6. A generator of its own. Random(42) fills a state of its own from 42. It rolls 6, 1, 1, 6 … like the first line, and no draw from the shared generator can move it.

The stream never changed; only the point at which the rolls began to read it did. What sits behind the stream is drawn below. The state is 624 numbers of 32 bits, and each output is one of them, scrambled:

A seed fills a state of 624 numbers; each draw scrambles the next one into an output that random(), choice() and the rest use.A seedrandom.seed(42) or Random(42)The generator's state:624 numbers of 32 bitsTake the next state numberand scramble it (a stepthat can be undone)One 32-bit outputrandom(), randint(), choice(),choices(), sample(), shuffle()build on the outputsfillseach drawused byafter 624 outputs:mix the state again

How a seed becomes a stream of numbers

Text description of the diagram

The diagram shows, from top to bottom, how the random module produces its numbers.

  • A seed, given to random.seed() or to random.Random(), fills the generator's state: 624 numbers of 32 bits each.
  • Each draw takes the next number of the state and scrambles it into one 32-bit output. The scrambling step can be undone, which is why the outputs reveal the state.
  • random(), randint(), choice(), choices(), sample() and shuffle() are all built on these outputs: random() uses two of them for one float, and randint() and choice() usually one.
  • After 624 outputs the generator mixes the whole state again and starts taking numbers from the top.

The same seed fills the state with the same 624 numbers, so the same outputs follow, which is what makes a seeded run repeatable.

That design gives a period of 2¹⁹⁹³⁷ − 1 outputs before the stream repeats, and floats with 53 bits of precision. Seeded streams do not depend on the computer: the example above printed the same rolls on CPython 3.14.8 and on the Python that runs in your browser.

Across Python versions the promise is narrower. The documentation guarantees only that random() keeps producing the same stream for the same seed; the algorithms behind randint(), choice(), shuffle() and the rest may change in a new release. A test that compares a seeded shuffle with a stored list can therefore break after an upgrade, while a test that checks properties of the result (the same items, the right length, a share near the expected one) keeps passing. Threads are the other catch: the module’s functions share one generator, so in a program with several threads the order of draws, and with it what each thread sees, can change from run to run.

Key idea

A seed fixes where the stream starts, not who draws from it: give each simulation or test its own random.Random(seed), and check seeded results by their properties.

Checkpoint

Check: Seeds and the shared generator

  1. Question 1 of 2 A program calls random.seed(7) and prints three rolls, then calls random.seed(7) again and prints three more. What do you expect?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The same three rolls twice

    A seed fixes where the stream starts. Seeding again with the same value starts it again, so the same draws give the same numbers, which is what made the first two lines of seeds.py equal.

  2. Question 2 of 2 After random.seed(42), ten rolls printed [6, 1, 1, 6, 3, 2, 2, 2, 6, 1]. Code elsewhere runs random.seed(42), then random.random() once, then ten rolls. Which list does it print?

    Choose one answer.

    A hint

    random() makes one float from two numbers of the stream.

    Show the answer: Question 2 of 2

    Answer: [1, 6, 3, 2, 2, 2, 6, 1, 6, 6]

    Every function of the module shares one generator. The call to random() took two numbers of the stream, the two that had given the rolls 6 and 1, so the rolls begin with the third: 1, 6, 3, 2 and so on.

choices() can repeat an item, sample() never does

A quiz app makes a good test bench: it needs questions picked at random, the hard ones less often, and no question twice in one quiz.

Picking quiz questions by difficulty Python · weighted_quiz.py
import random
from collections import Counter

rng = random.Random(5)
bank = {
    "easy": ["E1", "E2", "E3", "E4"],
    "medium": ["M1", "M2", "M3"],
    "hard": ["H1", "H2"],
}
levels = list(bank)
weights = [5, 3, 2]  # out of every ten picks: five easy, three medium, two hard

# choices(): k picks with replacement, in proportion to the weights
print(rng.choices(levels, weights=weights, k=10))
counts = Counter(rng.choices(levels, weights=weights, k=10_000))
print({level: f"{counts[level] / 10_000:.1%}" for level in levels})

# sample(): k different items, never the same one twice
every_question = [q for level in levels for q in bank[level]]
print(rng.sample(every_question, k=4))

# shuffle(): reorders the list itself and returns None
order = every_question.copy()
result = rng.shuffle(order)
print(order, result)

# randint() includes both ends; randrange() stops before its end
print(rng.randint(1, 3), rng.randrange(1, 3), round(rng.uniform(0, 10), 3))

Output

['medium', 'medium', 'medium', 'hard', 'medium', 'hard', 'easy', 'easy', 'hard', 'medium']
{'easy': '50.0%', 'medium': '30.1%', 'hard': '19.9%'}
['E3', 'M3', 'M2', 'E2']
['M3', 'E4', 'M1', 'E3', 'E2', 'E1', 'M2', 'H1', 'H2'] None
3 2 5.338

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 weighted_quiz.py

  • choices(population, weights=…, k=…) makes k independent picks with replacement: Drawing so that every pick can take any item again, as if each one were put back first. random.choices() draws with replacement; random.sample() draws without, using each position at most once., each in proportion to its weight. Ten picks can look nothing like 5 : 3 : 2 (only two of them came out easy), but 10,000 picks land within a few tenths of a percent of 50, 30 and 20 %. cum_weights takes running totals instead (5, 8, 10), which saves work when you pick from the same weights many times.
  • sample(population, k) picks k different positions, so no question comes up twice. It raises ValueError when k is larger than the population, and since Python 3.11 it accepts only sequences: pass sorted(a_set), not a set. Its counts argument repeats items without building the longer list: sample(["gold", "silver"], counts=[1, 9], k=3) draws three of ten coins, so at most one of the three is gold.
  • shuffle(x) reorders the list in place: Changing an object itself instead of making a new one. list.sort() sorts a list in place and returns None, while sorted() leaves its input as it was and returns a new list. More in “Lists: create, index, slice and modify” and returns None, the None the fourth line printed. For a shuffled copy, use sample(x, k=len(x)). For a list of more than 2,080 items the number of possible orders is larger than the generator’s period, so most orders can never come up.
  • randint(1, 3) can return 3, because it includes both ends. randrange(1, 3) cannot: like range(), it stops before its end. uniform(0, 10) returns a float between the two.

Which call fits depends on three things about your draw. Answer them in the table: it rules out the calls that do not fit, with the reason from the run above.

Interactive · answer and compare Which call fits your draw? Answer three questions about the items you draw. The table marks the calls that fit and says why the others do not.
May an item come up again, as a die can show 6 twice?
Should some items come up more often than others?
Must the original sequence keep its order?

Answer the questions above: the table then marks what fits your case and says why the rest does not.

Four ways to draw from a sequence, against what a draw may need (numbers from the quiz run above)
Call Never the same item twice Some items more likely More picks than items Original left as it was
choices(seq, k=n) Typical use: simulated customers, weighted quiz levels Poor every pick is independent: ten picks drew medium five times Good weights or cum_weights: 10,000 picks came out 50.0, 30.1 and 19.9 % Good k may be any size Good returns a new list
sample(seq, k=n) Typical use: a raffle, a quiz without repeats, a test set Good each position is used once Mixed no weights, but counts repeats items, as in counts=[1, 9] Poor k above the length raises ValueError Good returns a new list
shuffle(lst) Typical use: a deck of cards you deal from Good every item exactly once Poor no weights Mixed the list's own items, no more Poor reorders the list in place and returns None
sample(x, k=len(x)) Typical use: a shuffled copy of a list, a tuple or a string Good every item exactly once Poor no weights Mixed exactly len(x) items Good a new list; works on tuples and strings too
How the answers decide
  • “May an item come up again, as a die can show 6 twice?” No, each item at most once: rules out choices(seq, k=n). Each pick of choices() is independent, so an item can come up twice: ten weighted picks in the quiz drew medium five times.
  • “May an item come up again, as a die can show 6 twice?” Yes, every pick is independent: rules out sample(seq, k=n), shuffle(lst) and sample(x, k=len(x)). sample() and the shuffles use every position once, so a die simulated with them could never show 6 twice.
  • “Should some items come up more often than others?” Yes, they have weights: rules out shuffle(lst) and sample(x, k=len(x)) and adds a caveat to sample(seq, k=n). Only choices() takes weights. sample() can only repeat items with counts, as counts=[1, 9] does for one gold coin among ten.
  • “Must the original sequence keep its order?” Yes, or it is a tuple or a string: rules out shuffle(lst). shuffle() reorders the list itself and returns None, and a tuple or a string cannot be reordered at all; sample(x, k=len(x)) shuffles a copy.

In short: choices() for independent picks, with weights if you need them; sample() for different items; shuffle() for a list you no longer need in its old order; sample(x, k=len(x)) for a shuffled copy. choice(seq) is the simple case of one item, for one winner or one move in a game.

Keeping the result of shuffle()

order = rng.shuffle(order) replaces your list with None, because shuffle() reorders the list itself and returns nothing. Write rng.shuffle(order) on a line of its own, or order = rng.sample(order, k=len(order)) when you want a new list and the old one unchanged.

The module also draws from distributions: uniform(a, b) gives any value in a range, gauss(mu, sigma) a value on a bell curve and expovariate() a waiting time, and since Python 3.12 binomialvariate(n, p) gives a whole number, the successes in n tries. Python 3.13 also added a command line: python -m random 6 prints a whole number from 1 to 6, and python -m random tea coffee picks one of the words.

Checkpoint

Check: choices(), sample() and shuffle()

  1. Question 1 of 2 What happens when the quiz runs rng.sample(["E1", "E2", "E3"], k=4)?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: It raises ValueError, because there are not 4 different items to pick

    sample(population, k) picks k different positions, so k may not be larger than the population: here it raises ValueError. choices() picks with replacement and accepts any k.

  2. Question 2 of 2 Which values can rng.randrange(1, 3) return?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: 1 and 2

    randrange(1, 3) works like range(1, 3) and gives 1 or 2. randint(1, 3) can also return 3, because it includes both ends.

A simulation estimates a probability by counting

A simulation answers a probability question by repeating the experiment many times and counting how often the event happened. Take an old gambling question: roll a die four times; how likely is at least one six? Each trial below is one game of four rolls, and the program prints the estimates of four runs, of 100, 1,000, 10,000 and 100,000 games:

At least one six in four rolls Python · dice_simulation.py
import math
import random


def at_least_one_six(rng, rolls=4):
    """One experiment: roll a die four times. Did a six come up?"""
    return any(rng.randint(1, 6) == 6 for _ in range(rolls))


exact = 1 - (5 / 6) ** 4
print(f"exact: {exact:.4f}")
rng = random.Random(2)
for trials in (100, 1_000, 10_000, 100_000):
    hits = sum(at_least_one_six(rng) for _ in range(trials))
    estimate = hits / trials
    typical = math.sqrt(exact * (1 - exact) / trials)
    print(f"{trials:>7,} trials: {estimate:.4f}  off by {abs(estimate - exact):.4f}  typical error {typical:.4f}")

Output

exact: 0.5177
    100 trials: 0.5100  off by 0.0077  typical error 0.0500
  1,000 trials: 0.5320  off by 0.0143  typical error 0.0158
 10,000 trials: 0.5158  off by 0.0019  typical error 0.0050
100,000 trials: 0.5176  off by 0.0002  typical error 0.0016

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 dice_simulation.py

The estimates close in on 0.5177, the exact answer the program prints first. It comes from counting the other way: a game has no six only if all four rolls miss, each with probability 5/6, so the chance of at least one six is 1 − (5/6)⁴. The number of sixes in four rolls follows the binomial distribution: The number of successes in n independent tries that each succeed with probability p. The chance of exactly k successes is C(n, k) × pᵏ × (1 − p)ⁿ⁻ᵏ; the sixes in four rolls of a die follow it with n = 4 and p = 1/6., which the next figure draws for n tries that each succeed with probability p. It starts at the dice game: 4 tries, a chance of 0.166667 (1/6) and at least 1 success.

Interactive · change it and see Sixes in four rolls of a die Each of n independent tries succeeds with probability p. The bars are the chances of each number of successes; the highlighted ones are "at least k".
Probability of each number of successes: probability against successes.00.20.40.6successesprobability01234

In 4 tries with p = 0.17, the chance of at least 1 successes is 0.5177; on average there are 0.67.

P(X ≥ 1) 0.5177
P(X = 1) 0.3858
Mean np and standard deviation 0.67 ± 0.75
The numbers as a table
The most likely outcomes
SuccessesProbability
00.4823
10.3858
20.1157
30.0154

The highlighted bars add up to 0.5177, the answer the simulation is aiming at, and the bar at 0 holds the rest, (5/6)⁴ ≈ 0.4823. Where both exist, the exact answer is the best test of the simulation’s code. The simulation earns its place when the exact answer is hard to work out: the same few lines count any rule you can write as code, while a formula has to be found again for every new rule.

Change the game

Set the tries to 24 and the chance to 0.027778, which is 1/36, the chance of a double six when two dice are thrown together. The chance of at least one double six in 24 throws reads 0.4914, just under one half, even though 24 × 1/36 is two thirds.

Checkpoint

Check: Estimating by simulation

  1. Question 1 of 2 A simulation plays the four-roll game 1,000 times, and 532 of the games have at least one six. What is its estimate?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 0.532

    A simulation repeats the experiment and counts: 532 games of 1,000 had a six, so it estimates the probability as 0.532. The program above printed 0.5320 after its 1,000 games, which is how far one run can land from 0.5177.

  2. Question 2 of 2 What is the exact chance that four rolls of a die show no six at all? Give it to four decimal places.

    Type a number.

    A hint

    Each roll misses the six with probability 5/6, and the rolls are independent.

    Show the answer: Question 2 of 2

    Answer: 0.4823 (anything from 0.4822 to 0.4824 counts)

    All four rolls must miss, each with probability 5/6, so the chance is (5/6)⁴ = 625/1296 ≈ 0.4823. It is the bar at 0 in the figure, and 1 − 0.4823 = 0.5177 is the chance of at least one six.

Four times the trials halve the error

The estimates in the table are never exact, but their error shrinks in a predictable way. For a probability p estimated from n independent trials, the typical error, called the standard error: The typical distance between an estimate and the true value. For a probability p estimated from n independent trials it is √(p(1 − p) / n), so four times as many trials halve it., is:

p(1−p)n\sqrt{\frac{p(1-p)}{n}}

In words: the error is largest when p is near one half and shrinks with the square root of the number of trials. For the dice game and 1,000 trials it is √(0.5177 × 0.4823 ÷ 1,000) ≈ 0.0158, the typical error the program printed in that row.

An estimate’s error behaves like a draw from a bell curve centred on 0 whose spread is the standard error, so in about two runs out of three the estimate lands within one standard error of the truth, and in about 19 out of 20 within two. The figure draws the errors of 1,000-trial runs in percentage points, with a spread of 1.58 points and a band of ±1.58 shaded:

Interactive · change it and see How far a 1,000-trial estimate lands from the truth, in points Set the mean and the standard deviation, then the two ends of the range. The shaded area is the probability that a value falls between them.
The bell curve with the range shaded: density against x.−6−4−2024600.10.20.3xdensitydensityμ

For a normal distribution with mean 0 and standard deviation 1.58, the probability of a value between −1.58 and 1.58 is 0.6827 (68.3 %), from z = −1.00 to z = 1.00.

P(−1.58 ≤ X ≤ 1.58) 0.6827
z-score of a −1.00
z-score of b 1.00
The numbers as a table
Probability within k standard deviations of the mean
RangeProbability
μ ± 1σ0.6827
μ ± 2σ0.9545
μ ± 3σ0.9973

The band holds 0.6827 of all runs; widen it to ±3.16 points, two standard errors, and it holds 0.9545. Every row of the program’s table landed within one standard error of its own size: the 1,000-trial run, for one, was off by 1.43 points, inside the band of ±1.58 drawn here.

Ten times the trials

Set σ to 0.5, about the standard error of 10,000 trials, and keep the band at ±1.58. It now holds 0.9984 of all runs: ten times the trials make the error about 3.2 times smaller (√10).

Because n sits under a square root, halving the error takes four times as many trials. Seeding the Random object makes the whole table repeatable: run it again and every estimate is the same. Another seed gives other estimates, spread around the exact answer by about the same typical error.

Key idea

A simulated probability is typically off by √(p(1 − p)/n): ten times the trials shrink the error about 3.2 times, and halving it costs four times the trials.

Checkpoint

Check: How precise an estimate is

  1. Question 1 of 2 A simulation is run with ten times as many trials. About how many times smaller is its typical error?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: About 3.2 times

    The standard error is √(p(1 − p)/n). Multiplying n by 10 divides the error by √10 ≈ 3.2: the typical error of 0.0158 at 1,000 trials becomes 0.0050 at 10,000.

  2. Question 2 of 2 The dice game has p ≈ 0.5177. What is the standard error of an estimate from 10,000 trials? Give it to four decimal places.

    Type a number.

    A hint

    Work out p(1 − p), divide by the number of trials, then take the square root.

    Show the answer: Question 2 of 2

    Answer: 0.005 (anything from 0.0049 to 0.0051 counts)

    √(0.5177 × 0.4823 ÷ 10,000) = √0.00002497 ≈ 0.0050, the typical error the program printed for 10,000 trials. Its estimate, 0.5158, was off by 0.0019, well inside one standard error.

Dice Roller (d4 to d100) Roll dice and compare the exact odds of every total with your own simulation.

statistics finds the middle, the spread and the quartiles

The statistics module describes a list of numbers: where its middle is, how spread out it is and how it divides into quarters. Here are the marks of a class of twenty:

A class's marks, summarised Python · marks_summary.py
import statistics as st

marks = [72, 85, 64, 91, 58, 77, 85, 69, 94, 81, 66, 85, 73, 88, 47, 79, 70, 83, 61, 90]

print("students ", len(marks))
print("mean     ", st.mean(marks))
print("median   ", st.median(marks))
print("mode     ", st.mode(marks))
print("stdev    ", round(st.stdev(marks), 2), "  pstdev", round(st.pstdev(marks), 2))
print("quartiles", st.quantiles(marks, n=4))
print("inclusive", st.quantiles(marks, n=4, method="inclusive"))
print("deciles  ", st.quantiles(marks, n=10))

grades = ["B", "A", "C", "A", "B"]
print("tied     ", st.mode(grades), st.multimode(grades))

# Two tests taken by the same eight students
mid = [55, 62, 70, 48, 81, 66, 74, 90]
final = [58, 70, 72, 52, 85, 63, 80, 94]
print("correlation", round(st.correlation(mid, final), 3))
fit = st.linear_regression(mid, final)
print(f"final = {fit.slope:.3f} × mid + {fit.intercept:.2f}")

for summary, data in ((st.mean, []), (st.stdev, [42])):
    try:
        summary(data)
    except st.StatisticsError as error:
        print("StatisticsError:", error)

Output

students  20
mean      75.9
median    78.0
mode      85
stdev     12.48   pstdev 12.17
quartiles [66.75, 78.0, 85.0]
inclusive [68.25, 78.0, 85.0]
deciles   [58.3, 64.4, 69.3, 72.4, 78.0, 82.2, 85.0, 87.4, 90.9]
tied      B ['B', 'A']
correlation 0.974
final = 1.009 × mid + 2.87
StatisticsError: mean requires at least one data point
StatisticsError: stdev requires at least two data points

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 marks_summary.py

The figure draws the same twenty marks as dots on one line, with the box between the first and third quartile: One of the three cut points that split sorted data into four groups of the same size; the middle one is the median. statistics.quantiles(data, n=4) returns all three. that the program printed, the median across it and the mean below:

The twenty marks as dots on a line from 40 to 100, a box from 66.75 to 85.0 with the median at 78.0, and the mean at 75.9.Twenty marks, their quartiles and meanQ1 66.75Q3 85.0median 78.0405060708090100mean 75.9

The marks of examples/marks_summary.py, with the program's quartiles and mean

Text description of the diagram

The figure draws the twenty marks of the class as dots on one line from 40 to 100. Marks that are close together are stacked, so the three marks of 85 form a column of three dots.

  • Above the dots, a box runs from the first quartile, 66.75, to the third quartile, 85.0. A thick line across the box marks the median, 78.0. About half of the marks lie inside the box: eleven of the twenty, counting the three marks of 85 on its edge.
  • Lines reach out from the box to the lowest mark, 47, and the highest, 94.
  • A diamond on the line marks the mean, 75.9. It sits to the left of the median because the one low mark, 47, pulls the mean down more than it moves the middle value.

The quartiles are those of statistics.quantiles(marks, n=4) with its default method, "exclusive".

  • mean() is the average and median() the middle value, here 75.9 and 78.0. One low mark, 47, pulls the mean down more than the median, which is why the mean’s diamond sits left of the median’s line, and why medians describe skewed data such as incomes better.
  • mode() is the most common value. With a tie it returns the first of the tied values in the data, so "B" wins here; multimode() returns all of them.
  • stdev() is the sample standard deviation. Its sum of squares is divided by n − 1 rather than n, a correction for the group being only part of everyone you care about; pstdev() divides by n and describes exactly the data you have. Use pstdev() when the class is all you want to describe, and stdev() when it stands for every student who sat the test.
  • quantiles(data, n=4) returns the three cut points that split the data into quarters; n=10 gives deciles. The default method, "exclusive", assumes the real population can go beyond your lowest and highest values; "inclusive" treats them as the true minimum and maximum, so its outer quartiles are never further out: here the lower one moves from 66.75 to 68.25.
  • correlation() measures how closely two lists follow a straight line together, from −1 to 1, and linear_regression() fits that line: here a student’s final mark is about 1.009 times their mid-term mark plus 2.87.
  • With too few values there is nothing to compute: mean([]) and stdev([42]) raise StatisticsError, a kind of ValueError.

Move one mark

Press Edit, change the mark 47 to 67 and run the program. The mean rises by a whole mark, to 76.9, while the median stays at 78.0: 67 is still below the two middle marks, 77 and 79.

The functions accept ints, floats, Decimal and Fraction values, and they keep exact types exact: the mean of Fraction values is a Fraction. Mixing types in one list is not supported, so convert first, for example with map(float, data). The module aims at the level of a graphing or scientific calculator and leaves large-scale work to libraries such as NumPy and SciPy.

Checkpoint

Check: Averages, spread and quartiles

  1. Question 1 of 2 In the class's marks, the lowest mark, 47, is changed to 67. What happens to the mean, 75.9, and the median, 78.0?

    Choose one answer.

    A hint

    The median depends on the two middle marks of the sorted list.

    Show the answer: Question 1 of 2

    Answer: The mean rises to 76.9, and the median stays 78.0

    The mean uses every value, so 20 more points raise it by 1, to 76.9. The median of 20 marks is the average of the 10th and 11th sorted marks, 77 and 79, and a mark that moves from 47 to 67 stays below them. That is why medians describe data with a few extreme values better.

  2. Question 2 of 2 A teacher wants the spread of exactly these 20 marks, for this class only. Which function fits?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: statistics.pstdev(marks), 12.17

    When the data are everything you want to describe, use the population standard deviation, pstdev(). When they are a sample that stands for more students, use stdev(), which divides by n − 1.

Descriptive Statistics Calculator Paste a list of numbers to see its mean, median, standard deviations and quartiles side by side.

random is not for secrets

The documentation says it plainly: the generators of random should not be used for security. The stream is predictable, and not only to someone who knows the seed. Each output is a state number put through a scrambling step that can be undone, so 624 outputs in a row hand over the whole state. This program watches a generator seeded by the operating system, whose seed nobody knows, and predicts it; then it runs the same check on the generator that the secrets module uses:

Predicting a Random generator from its outputs Python · predict_next.py
import random
import secrets
import string


def undo_right(value, shift):
    """Undo value ^= value >> shift on a 32-bit number."""
    result = value
    for _ in range(32 // shift):
        result = value ^ (result >> shift)
    return result


def undo_left(value, shift, mask):
    """Undo value ^= (value << shift) & mask on a 32-bit number."""
    result = value
    for _ in range(32 // shift):
        result = value ^ ((result << shift) & mask)
    return result & 0xFFFFFFFF


def unscramble(output):
    """Turn one 32-bit output back into the state number it was made from."""
    y = undo_right(output, 18)
    y = undo_left(y, 15, 0xEFC60000)
    y = undo_left(y, 7, 0x9D2C5680)
    return undo_right(y, 11)


def predicts(generator):
    """Watch 624 outputs, copy the state they reveal, and check the copy's next five numbers."""
    seen = [generator.getrandbits(32) for _ in range(624)]
    copy = random.Random()
    copy.setstate((3, tuple(unscramble(n) for n in seen) + (624,), None))
    upcoming = [generator.getrandbits(32) for _ in range(5)]
    return upcoming == [copy.getrandbits(32) for _ in range(5)], copy


server = random.Random()  # seeded by the operating system: nobody knows its seed
hit, copy = predicts(server)
print("next 5 numbers predicted:", hit)

alphabet = string.ascii_letters + string.digits
token = "".join(server.choice(alphabet) for _ in range(20))
guess = "".join(copy.choice(alphabet) for _ in range(20))
print("20-character token guessed:", token == guess)

# The same check on the generator behind the secrets module: its outputs reveal nothing
hit, _ = predicts(secrets.SystemRandom())
print("secrets.SystemRandom predicted:", hit)

Output

next 5 numbers predicted: True
20-character token guessed: True
secrets.SystemRandom predicted: False

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 predict_next.py

After seeing 624 numbers, the copy predicts the next five exactly, and with them a 20-character “reset token” built with choice(). The same attempt on secrets.SystemRandom fails, because its numbers come from the operating system’s most secure source and have no state to copy. The difference in a table:

Property random secrets
Numbers come from the Mersenne Twister, started from a seed the operating system’s most secure source
The same seed again gives the same numbers there is no seed
624 outputs in a row reveal every number that follows reveal nothing, as the last line shows
Made for games, simulations and tests passwords, tokens, one-time codes and keys

For anything that guards an account or money (passwords, reset links, session ids, one-time codes, API keys) use the secrets module:

Tokens, passwords and codes with secrets Python · secret_tokens.py
import secrets
import string

# The values change on every run, so this prints only their shape.
token = secrets.token_urlsafe(32)  # 32 random bytes, Base64-encoded for URLs
print(len(token), set(token) <= set(string.ascii_letters + string.digits + "-_"))

alphabet = string.ascii_letters + string.digits
password = "".join(secrets.choice(alphabet) for _ in range(16))
print(len(password), password.isalnum())

code = f"{secrets.randbelow(1_000_000):06d}"  # a six-digit one-time code
print(len(code), code.isdigit())

# Compare a submitted token with the stored one in constant time
print(secrets.compare_digest(token, token), secrets.compare_digest(token, token[:-1] + "?"))

Output

43 True
16 True
6 True
True False

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 secret_tokens.py

  • secrets.token_urlsafe(32) gives 32 random bytes as 43 characters that are safe in a URL. The documentation names 32 bytes, 256 bits, as enough for typical uses; token_hex() and token_bytes() work the same way.
  • secrets.choice() picks a character, and secrets.randbelow(n) a whole number from 0 to n − 1, here padded to a six-digit code.
  • secrets.compare_digest() compares two secrets in constant time, so the time an answer takes does not reveal how many leading characters were right.

The program prints only lengths and checks because the tokens change on every run, which is exactly what they should do.

Checkpoint

Check: secrets instead of random

  1. Question 1 of 2 A login sends a six-digit one-time code by text message. Which line makes the code?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: f"{secrets.randbelow(1_000_000):06d}"

    A code that guards an account must be unpredictable, so it comes from secrets. secrets.randbelow(1_000_000) gives 0 to 999,999, and formatting with :06d keeps six digits, as secret_tokens.py does.

  2. Question 2 of 2 Why compare a submitted token with secrets.compare_digest() instead of ==?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Its time does not depend on how many leading characters match, so timing reveals nothing

    == can stop at the first character that differs, so a wrong guess that starts right takes a little longer. secrets.compare_digest() takes the same time either way, as the last line of secret_tokens.py uses it.

Password Generator Make passwords and passphrases with your browser's secure random generator and see their strength in bits.

Practise: shared birthdays and a marks summary

How many people must be in a room before two of them probably share a birthday? Fewer than most people guess: 23 is enough for a chance just above one half. Simulate it with a generator of your own, then summarise a list of marks; the sample tests allow for the random error of a simulation.

Exercise · Easy · Python

Simulate shared birthdays and summarise marks

Write two functions in simulate.py.

simulate_birthday(n, trials, seed) estimates the chance that at least two people in a group of n share a birthday. Treat a year as 365 equally likely days and ignore leap days. Each trial gives the n people random birthdays; count the trials in which two or more birthdays are the same, and return that count divided by trials. Draw every number from random.Random(seed), so that the same arguments always give the same answer.

summarise(marks) returns a dictionary describing a list of marks, with these keys:

  • "count": how many marks there are
  • "mean" and "median"
  • "stdev": the sample standard deviation
  • "lowest" and "highest"
  • "quartiles": the three cut points of statistics.quantiles() with its default method

With fewer than two marks the standard deviation does not exist: let summarise() raise a ValueError then.

  • simulate_birthday(23, 4000, seed=1) is close to the exact answer, 0.5073
  • simulate_birthday(1, 100, seed=1) is 0.0, and simulate_birthday(366, 10, seed=1) is 1.0
  • summarise([72, 85, 64, 91, 58, 77, 85, 69, 94, 81])["quartiles"] is [67.75, 79.0, 86.5]

The sample tests compare the estimates with the exact answers, allowing for the random error of a simulation.

Starter code · simulate.py

import random
import statistics


def simulate_birthday(n, trials, seed):
    """Estimate the chance that at least two of n people share a birthday (365 equally likely days)."""
    # Replace this line with your code.
    return 0.0


def summarise(marks):
    """Return the count, mean, median, sample stdev, lowest, highest and quartiles of the marks."""
    # Replace this line with your code.
    return {}
The sample tests · test_simulate.py
import math

from simulate import simulate_birthday, summarise


def test_twenty_three_people():
    """estimates about a 50.7 % chance for 23 people"""
    estimate = simulate_birthday(23, 4000, seed=1)
    assert math.isclose(estimate, 0.5073, abs_tol=0.03)


def test_other_group_sizes():
    """gets close to the exact answers for 10 and 50 people"""
    assert math.isclose(simulate_birthday(10, 4000, seed=4), 0.1169, abs_tol=0.03)
    assert math.isclose(simulate_birthday(50, 2000, seed=3), 0.9704, abs_tol=0.03)


def test_certain_cases():
    """gives 0.0 for one person and 1.0 for 366 people"""
    assert simulate_birthday(1, 100, seed=1) == 0.0
    assert simulate_birthday(366, 10, seed=1) == 1.0


def test_repeatable():
    """returns the same estimate for the same seed"""
    assert simulate_birthday(30, 500, seed=7) == simulate_birthday(30, 500, seed=7)


def test_summary():
    """describes ten marks"""
    summary = summarise([72, 85, 64, 91, 58, 77, 85, 69, 94, 81])
    assert summary["count"] == 10
    assert math.isclose(summary["mean"], 77.6)
    assert summary["median"] == 79.0
    assert math.isclose(summary["stdev"], 11.7587, abs_tol=0.0001)
    assert summary["lowest"] == 58
    assert summary["highest"] == 94
    assert summary["quartiles"] == [67.75, 79.0, 86.5]


def test_too_few_marks():
    """raises a ValueError for a single mark"""
    try:
        summarise([50])
    except ValueError:
        return
    assert False, "expected a ValueError for one mark"
A hint

Make one generator with rng = random.Random(seed) and use only it. In each trial, build a list of n numbers with rng.randrange(365); two people share a birthday exactly when the list has fewer different values than people, which len(set(days)) < n tests. For summarise(), the statistics module has mean, median, stdev and quantiles, and stdev() already raises statistics.StatisticsError, a kind of ValueError, when it gets fewer than two values.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Eighteen questions on the six ideas of this lesson follow. A session opens with the idea your answers show you know least, moves up a level after each right answer, and says why every choice is right or wrong the moment you pick it:

Practice that adapts to you

Practise this lesson

18 questions about 6 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 18 What does the random module's documentation promise about a seeded stream across Python versions?

    Choose one answer.

    Show the answer: Question 1 of 18

    Answer: Only random() keeps producing the same stream for the same seed

    The documentation guarantees only that random() keeps its stream for a seed. So a test that compares a seeded shuffle with a stored list can break after an upgrade, while a test of properties keeps passing.

  2. Question 2 of 18 Two simulations in one program both call the module's functions after random.seed(1). Simulation B's results change whenever simulation A is edited to draw one more number. What fixes it?

    Choose one answer.

    Show the answer: Question 2 of 18

    Answer: Give each simulation its own random.Random(1)

    The module's functions share one hidden generator, so every draw moves the stream for everyone. A Random object per simulation, each with its own seed, keeps their streams apart, as Random(42) did in seeds.py.

  3. Question 3 of 18 A raffle must draw 3 different winners from a list of 50 names. Which call fits?

    Choose one answer.

    Show the answer: Question 3 of 18

    Answer: random.sample(names, k=3)

    sample() picks without replacement, so the same name cannot win twice. choices() and repeated choice() pick with replacement and may return one name more than once, and shuffle() takes only the list and returns None.

  4. Question 4 of 18 What does this print?

    Read the code, then choose one answer.

    import random
    cards = ["A", "K", "Q", "J"]
    cards = random.shuffle(cards)
    print(cards)
    Show the answer: Question 4 of 18

    Answer: None

    shuffle() reorders the list it is given and returns None, and the assignment then replaces the name cards with that None. Call random.shuffle(cards) on a line of its own, or use random.sample(cards, k=len(cards)) for a shuffled copy.

  5. Question 5 of 18 rng.choices(levels, weights=[5, 3, 2], k=10_000) picks from easy, medium and hard. About how many of the picks are hard?

    Type a number.

    A hint

    The weights add up to 10. What share of them belongs to hard?

    Show the answer: Question 5 of 18

    Answer: 2000 picks (anything from 1900 to 2100 counts)

    A pick is hard with probability 2 ÷ (5 + 3 + 2) = 0.2, so about 2,000 of 10,000 picks are hard. The quiz run gave 19.9 %, that is 1,990; a few dozen either way is normal for a random draw.

  6. Question 6 of 18 You need a shuffled copy of a tuple of 9 question ids, and the tuple must stay as it is. Which call do you write?

    Choose one answer.

    Show the answer: Question 6 of 18

    Answer: rng.sample(ids, k=len(ids))

    For a shuffled copy, sample(x, k=len(x)) works on lists, tuples and strings and leaves the original as it was. shuffle() is for a list that you no longer need in its old order.

  7. Question 7 of 18 After 100,000 games the simulation prints an estimate of 0.5176. What does that number stand for?

    Choose one answer.

    Show the answer: Question 7 of 18

    Answer: The share of the simulated games that had at least one six

    A simulation estimates a probability as the share of trials in which the event happened. After 100,000 games that share, 0.5176, is within 0.0002 of the exact answer.

  8. Question 8 of 18 What is the exact chance of at least one six in three rolls of a die? Give it to four decimal places.

    Type a number.

    A hint

    Work out the chance of no six first.

    Show the answer: Question 8 of 18

    Answer: 0.4213 (anything from 0.4212 to 0.4214 counts)

    No six in three rolls has probability (5/6)³ = 125/216 ≈ 0.5787, so at least one six has 1 − 125/216 = 91/216 ≈ 0.4213. In the binomial figure that is 3 tries, p = 0.166667, at least 1.

  9. Question 9 of 18 Which formula gives the standard error of a probability p estimated from n independent trials?

    Choose one answer.

    Show the answer: Question 9 of 18

    Answer: √(p(1 − p) / n)

    The standard error is √(p(1 − p)/n). For the dice game and 1,000 trials that is √(0.5177 × 0.4823 ÷ 1,000) ≈ 0.0158.

  10. Question 10 of 18 A simulation with 10,000 trials gives a typical error of about 0.005. How many trials give a typical error of about 0.0025?

    Type a number.

    Show the answer: Question 10 of 18

    Answer: 40000 trials

    The typical error is the square root of p(1 − p) / n, so it falls with the square root of the number of trials. Halving it needs 2² = 4 times as many trials: 40,000.

  11. Question 11 of 18 Your simulation of the four-roll game prints 0.6000 after 100,000 games. What does that tell you?

    Choose one answer.

    Show the answer: Question 11 of 18

    Answer: The code is wrong, because 0.6 is over 50 standard errors from 0.5177

    A simulation's estimate should land within a few standard errors of the truth. 0.6000 against 0.5177 is a gap of about 51 standard errors of 0.0016, so look for a bug, such as counting the wrong event.

  12. Question 12 of 18 The class's median mark is 78.0 and its mean only 75.9. Why is the mean lower?

    Choose one answer.

    Show the answer: Question 12 of 18

    Answer: The one low mark, 47, pulls the mean down more than it moves the median

    A mark far below the rest lowers the mean but only shifts the median by one position. In the figure the mean's diamond sits left of the median's line for that reason.

  13. Question 13 of 18 Which of these calls raise statistics.StatisticsError on Python 3.14?

    Choose every answer that is right.

    Show the answer: Question 13 of 18

    Answer:

    • statistics.stdev([42])
    • statistics.mean([])

    The sample standard deviation needs at least two values and every mean needs at least one. The median of one value is that value, the population standard deviation of one value is 0.0, and since Python 3.13 quantiles() accepts a single data point and returns it as every cut point.

  14. Question 14 of 18 The 20 marks are a sample of all the students in a state who sat the same test. Which number estimates the spread of all their marks?

    Choose one answer.

    Show the answer: Question 14 of 18

    Answer: stdev(marks), 12.48, which divides by n − 1

    stdev() divides the sum of squares by n − 1, the usual correction when a sample stands for a population, and gives 12.48. pstdev() gives 12.17 and describes the class alone.

  15. Question 15 of 18 For the class's 20 marks, quantiles(marks, n=4) gave a lower quartile of 66.75 and method="inclusive" gave 68.25. When is the inclusive method the right one?

    Choose one answer.

    Show the answer: Question 15 of 18

    Answer: When the data hold the true lowest and highest values, as the marks of a whole class you describe do

    The default method, exclusive, assumes the population can go beyond your lowest and highest values; inclusive treats them as the true minimum and maximum, so its outer quartiles are never further out. For the class the lower quartile moves from 66.75 to 68.25, while the median, 78.0, and the upper quartile, 85.0, stay.

  16. Question 16 of 18 Why can the outputs of random.Random() be predicted even when nobody knows its seed?

    Choose one answer.

    Show the answer: Question 16 of 18

    Answer: Each output is one state number put through a step that can be undone, so 624 outputs give away the whole state

    The Mersenne Twister's outputs are its state numbers, scrambled by a reversible step. predict_next.py undoes the step for 624 outputs, copies the state and predicts the next numbers exactly.

  17. Question 17 of 18 A web app emails a link with a token to reset a password. How should it make the token?

    Choose one answer.

    Show the answer: Question 17 of 18

    Answer: secrets.token_urlsafe(32)

    Tokens that guard an account must be unpredictable, and the random generators are not: 624 of their outputs reveal everything that follows. secrets draws from the operating system's secure source. (SystemRandom ignores any seed, and a token is checked by storing it, not by making it again.)

  18. Question 18 of 18 A shop prints 8-character coupon codes worth money, and nobody should be able to guess one. Which code makes them?

    Choose one answer.

    Show the answer: Question 18 of 18

    Answer: "".join(secrets.choice(alphabet) for _ in range(8))

    An unguessable code needs both a secure source and enough possibilities. secrets.choice() gives the first, and 8 characters from 62 give the second. A secure source with few possible values, or random with many, is not enough.

Interview questions

Fresher · What is the difference between random.sample() and random.choices()?

sample(population, k) draws without replacement: it returns k items from k different positions, so an item that appears once in the population appears at most once in the result, and k may not be larger than the population. choices(population, weights=None, k=1) draws with replacement: each of the k picks is independent, so items can repeat, k can be any size, and weights or cumulative weights make some items more likely than others. Use sample() for a raffle, a quiz without repeated questions or splitting data into a test set; use choices() for simulations in which the same outcome can happen again, such as customers choosing products. For a shuffled copy of a whole list, sample(x, k=len(x)) does the job.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    A test suite calls random.seed(1234) once at start-up, and one test compares random.shuffle() of ten user ids with an order stored in the test. Since the suite started running tests in parallel workers, that test fails now and then. Explain why, say what a Python upgrade could do to it, and rewrite the test.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    A festival sale gives a coupon to 1 order in 50 at random, a store expects 400 orders a day, and the budget covers 14 coupons. Estimate by simulation how likely a day needs 15 or more, to within half a percentage point. How many trials do you run, and how do you know the code is right?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • random produces a repeatable stream from a seed, shared by every function of the module; give each simulation or test its own random.Random(seed), and test seeded code by its properties, because only random() is promised to keep its stream across versions.
  • choices() picks with replacement and weights, sample() without repeats, and shuffle() reorders a list in place and returns None; randint() includes both ends and randrange() stops before its end.
  • A simulation estimates a probability as the share of trials in which the event happened, and an exact answer such as 1 − (5/6)⁴ is the best check of its code.
  • A simulation’s typical error is √(p(1 − p) / n): ten times the trials shrink it about 3.2 times, and halving it costs four times the trials.
  • statistics gives the mean, median, mode, sample and population standard deviations, quantiles, correlation and a regression line, and raises StatisticsError when there are too few values.
  • Never use random for secrets, because 624 outputs reveal its state: use secrets.token_urlsafe(), secrets.choice(), secrets.randbelow() and secrets.compare_digest().

Terms in this lesson

binomial distribution
The number of successes in n independent tries that each succeed with probability p. The chance of exactly k successes is C(n, k) × pᵏ × (1 − p)ⁿ⁻ᵏ; the sixes in four rolls of a die follow it with n = 4 and p = 1/6.
pseudo-random
Made by a fixed algorithm that only looks random. The random module's Mersenne Twister turns a seed into such a stream, so anyone who learns the generator's state can work out every number that follows.
quartile
One of the three cut points that split sorted data into four groups of the same size; the middle one is the median. statistics.quantiles(data, n=4) returns all three.
seed
The starting value of a pseudo-random generator. The same seed gives the same stream of numbers, so random.seed(42) or random.Random(42) makes a simulation or a test repeatable.
standard error
The typical distance between an estimate and the true value. For a probability p estimated from n independent trials it is √(p(1 − p) / n), so four times as many trials halve it.
with replacement
Drawing so that every pick can take any item again, as if each one were put back first. random.choices() draws with replacement; random.sample() draws without, using each position at most once.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.