Probability distribution objects in scipy.stats turn a named statistical model into density values, cumulative probabilities, quantiles, and simulated observations. Python analysis code can use the same object to check how unusual a value is, find a cutoff, or generate values from one parameterized model.
Freezing a distribution stores parameters once. For scipy.stats.norm, loc is the mean and scale is the standard deviation; other distributions can add shape parameters while still exposing the same common method names.
Continuous distributions need careful wording because pdf() is density at a point, not probability mass at exactly that value. Use cdf() for probability at or below a threshold, sf() for upper-tail probability, ppf() for inverse cumulative cutoffs, and rvs() with a NumPy generator when repeatable sample values matter.
import numpy as np from scipy.stats import norm np.set_printoptions(precision=2, suppress=True) scores = norm(loc=70, scale=8) lo, hi = scores.interval(0.90) rng = np.random.default_rng(20260625) sample = scores.rvs(size=5, random_state=rng) q = np.array([0.1, 0.5, 0.9]) print(f"mean/std: {scores.mean():.1f} {scores.std():.1f}") print(f"pdf(75): {scores.pdf(75):.4f}") print(f"cdf(75): {scores.cdf(75):.4f}") print(f"sf(85): {scores.sf(85):.4f}") print(f"central 90%: {lo:.2f} to {hi:.2f}") print(f"ppf(0.90): {scores.ppf(0.90):.2f}") print("sample:", sample) print("cdf(ppf(q)):", np.round(scores.cdf(scores.ppf(q)), 1))
norm(loc=70, scale=8) freezes a normal distribution, so each later method call uses the same mean and standard deviation.
$ python3 probability_distribution_demo.py mean/std: 70.0 8.0 pdf(75): 0.0410 cdf(75): 0.7340 sf(85): 0.0304 central 90%: 56.84 to 83.16 ppf(0.90): 80.25 sample: [78.71 79.82 84.9 63.33 77.79] cdf(ppf(q)): [0.1 0.5 0.9]
A density can be greater than 1 for some continuous distributions. It is not the probability of exactly one value.
sf() is the survival function. It represents the probability above the threshold and can be more accurate than subtracting cdf() from 1 for extreme upper tails.
ppf(0.90) returns the cutoff where 90 percent of the distribution is at or below that value. interval(0.90) returns equal-tail bounds around the median.
Use a fixed generator seed only for repeatable checks. Use an unseeded generator or a documented project seed policy for simulation work.
q = np.array([0.1, 0.5, 0.9]) scores.cdf(scores.ppf(q))
Confirm cdf(ppf(q)) returns the original probability levels apart from normal floating-point rounding.
$ rm probability_distribution_demo.py