The statistics module computes descriptive measures without third-party dependencies. Choosing the measure matters: one unusually high latency can pull the mean away from typical behavior.
from statistics import fmean, median, quantiles
latencias_ms = [91, 105, 110, 118, 140, 420]
media = fmean(latencias_ms)
mediana = median(latencias_ms)
q1, q2, q3 = quantiles(latencias_ms, n=4)
print(media, mediana, q3)
fmean() returns a floating-point mean, median() finds the center, and quantiles() partitions the data. The third quartile describes the upper range without reducing it to the maximum. Handle missing values and confirm units first.
Practical guidance
Distinguish populations from samples: pvariance() and pstdev() use a full population, while variance() and stdev() estimate from a sample. Do not publish a mean alone; disclose dataset size, time window, dispersion, and exclusions. For money, consider Decimal and domain rounding rules.
For tabular work, continue with the pandas guide. For large arrays, read about NumPy in Python.
The official statistics module documentation, accessed July 22, 2026, documents the API and its guarantees.
Prepare data before summarizing
A correct statistic over poor data is still misleading. Confirm units, period, source, and meaning. Remove missing observations with an explicit rule. NaN values produce surprising output in order-based functions, so filter them first.
from math import isnan
from statistics import fmean, median
raw = [12.4, float("nan"), 13.1, 19.8]
values = [value for value in raw if not isnan(value)]
print(fmean(values), median(values))
Never mix seconds with milliseconds or unrelated populations. Record exclusions and their reasons. Removing an outlier merely because it changes the mean hides information; determine whether it is a measurement error or a real event.
Mean, median, and mode
mean() preserves compatible numeric types. fmean() returns floating point and is often faster. Mean uses every observation but reacts strongly to extremes. Median uses position and often describes skewed income or latency better. Reporting both can expose a tail hidden by either one alone.
mode() returns one mode, while multimode() returns all most frequent values. For continuous measurements, nearly every value may occur once, making mode uninformative. For categories, include absolute count with the percentage.
Population, sample, and spread
Equal means can hide different risk. pvariance() and pstdev() describe the complete observed population. variance() and stdev() apply sample correction. Choose from the collection design, not from which result looks preferable.
from statistics import fmean, stdev
sample = [18.2, 17.9, 18.5, 19.1, 17.7]
summary = {
"n": len(sample),
"mean": fmean(sample),
"standard_deviation": stdev(sample),
}
print(summary)
Variance has squared units; standard deviation returns to the original unit. Always report n, because spread from very few observations is unstable.
Quantiles and conventions
quantiles(data, n=4) produces three quartile cut points. With n=100, it produces 99 internal percentile cuts. The method argument selects interpolation. exclusive and inclusive use different conventions; document the method when comparing spreadsheets or libraries.
P95 latency means roughly 95% of observations are at or below that cut, not that every request meets it. Extreme percentiles from tiny samples suggest unsupported precision. Report window, count, and method beside the result.
Numeric types and precision
Do not mix Decimal and float without a policy. For money, Decimal preserves decimal representation, but accounting and rounding remain domain decisions.
from decimal import Decimal
from statistics import mean
prices = [Decimal("19.90"), Decimal("20.10"), Decimal("20.00")]
average = mean(prices).quantize(Decimal("0.01"))
print(average)
Fraction works for several operations when exact rational output matters. Keep each dataset numerically homogeneous and test the selected function.
Relationships between variables
covariance() measures how two variables vary together. correlation() normalizes association near -1 to 1. Correlation does not prove causation: outliers, time trends, or a third variable can create an apparent relationship.
linear_regression() fits a simple line and returns slope and intercept. Plot points and inspect residuals before interpretation. A line may summarize a curved relationship poorly. These helpers suit small explorations but do not replace experimental design, confidence intervals, or specialized models.
Errors and edge cases
Several functions raise StatisticsError for empty or insufficient input. Validate at the boundary and choose a coherent response.
from statistics import StatisticsError, median
def median_or_none(values):
try:
return median(values)
except StatisticsError:
return None
Choose deliberately among None, an exception, or an omitted field. Zero usually looks like a real observation and is misleading. Iterators can also be consumed, so materialize them when calculating several measures from the same input.
Testing and reporting
Test odd and even counts, repeats, negatives, outliers, one item, and empty input. Use math.isclose() for floating-point output instead of fragile exact equality. Quantile tests should state the method.
When publishing analysis, include source, period, unit, count, exclusions, and spread. A histogram or boxplot may expose skew and clusters hidden by summaries. Preserve raw data or a reproducible transformation for audit.
When another tool fits
statistics is excellent for small iterables and dependency-free scripts. NumPy handles large vectorized arrays; pandas adds labels, grouping, and tabular cleaning; scientific libraries provide inference and advanced models. Upgrade for a concrete need, not because a simple average demands a larger stack.
The final checklist is concise: decide population or sample, clean transparently, match measures to distribution, report count and spread, document the quantile method, and never turn association into a causal claim.