statistics模块 — 统计函数

Python标准库精讲专题 · 数字与数学篇 · 掌握统计函数工具

专题:Python标准库精讲系统学习

关键词:Python, 标准库, statistics, 统计, 平均数, 中位数, 标准差, 方差, 协方差, 相关系数

一、statistics模块概述

statistics是Python标准库中专门用于数学统计的内置模块,自Python 3.4起正式加入标准库。它提供了一系列用于处理数值数据的统计函数,涵盖集中趋势度量、离散程度度量、统计关系分析以及概率分布对象等核心功能。

与第三方库NumPy相比,statistics模块的优势在于无需额外安装、开箱即用,适合日常轻量级统计计算。其设计遵循"为常见统计问题提供便捷函数"的理念,API简洁直观,对初学者非常友好。

需要注意的是,statistics模块针对中小规模数据集设计,当处理百万级以上数据或需要矩阵运算时,建议使用NumPy/SciPy等专业科学计算库。

适用范围对比:

statistics模块 → 日常数据分析、教学示例、轻量统计计算(几百到几万条数据)

NumPy/SciPy → 大数据量、矩阵运算、高级统计分析、机器学习

statistics模块的函数可以分为四大类:

二、集中趋势函数

集中趋势(Central Tendency)描述数据集的"中心"位置,是最常用的统计量。statistics模块提供了丰富的集中趋势函数,覆盖了算术平均、几何平均、调和平均、中位数、众数等不同维度。

2.1 平均数函数

mean(data) — 算术平均数。最经典的平均数计算,等同于 sum(data)/len(data)。要求输入数据为数值类型(int/float),非数值类型会抛出 TypeError。

>>> import statistics as st >>> st.mean([1, 2, 3, 4, 5]) 3 >>> st.mean([1.5, 2.5, 3.5]) 2.5 >>> st.mean([]) # 空序列会抛出 StatisticsError Traceback (most recent call last): statistics.StatisticsError: mean requires at least one data point

fmean(data, weights=None) — 快速浮点平均数(Python 3.8+)。比 mean() 速度更快,以浮点格式返回结果,可选权重参数支持加权平均计算。

>>> st.fmean([1, 2, 3, 4, 5]) 3.0 >>> st.fmean([1, 2, 3, 4, 5], weights=[1, 1, 2, 1, 1]) # 加权平均 2.8333333333333335

geometric_mean(data) — 几何平均数(Python 3.8+)。计算 n 个数值乘积的 n 次方根,适用于比率数据、增长率计算。要求所有数据为正值。

>>> st.geometric_mean([2, 8]) # sqrt(2*8) = 4.0 4.0 >>> st.geometric_mean([1, 2, 4, 8]) # (1*2*4*8)^(1/4) = 64^(1/4) = 2.828... 2.8284271247461903

harmonic_mean(data, weights=None) — 调和平均数。适用于速率、密度等具有倒数关系的数据。当数据中存在 0 时无法计算。

>>> st.harmonic_mean([10, 20, 30]) # 3 / (1/10 + 1/20 + 1/30) ≈ 16.36 16.363636363636363

三种平均数的选择原则:

算术平均数 — 适用于加法关系的数据,如身高、体重、考试成绩

几何平均数 — 适用于乘法关系的数据,如投资回报率、人口增长率

调和平均数 — 适用于比率关系的数据,如平均速度、平均密度

2.2 中位数函数

median(data) — 中位数。将数据排序后取中间值。若数据个数为奇数,返回中间那个数;若为偶数,返回中间两个数的算术平均数。

>>> st.median([1, 3, 5, 7, 9]) # 奇数个 → 中间值 5 >>> st.median([1, 3, 5, 7]) # 偶数个 → (3+5)/2 4.0

median_low(data) — 低中位数。偶数个数据时返回较小的中间值,而非平均值。

median_high(data) — 高中位数。偶数个数据时返回较大的中间值。

>>> st.median_low([1, 3, 5, 7]) # 偶数个,较小中间值 3 >>> st.median_high([1, 3, 5, 7]) # 偶数个,较大中间值 5

median_grouped(data, interval=1) — 分组中位数。用于已分组(区间化)的数据,通过插值估计中位数的精确位置。interval 参数指定组距,默认为 1。

>>> st.median_grouped([1, 2, 2, 3, 4, 4, 4, 5], interval=1) 3.5

2.3 众数函数

mode(data) — 众数。返回数据中出现次数最多的值。若多个值出现次数相同,返回第一个遇到的。

multimode(data) — 多众数(Python 3.8+)。返回所有出现次数最多的值组成的列表,可处理多众数情况。

>>> st.mode([1, 1, 2, 3, 3, 3, 4]) # 出现最多的值 3 >>> st.multimode([1, 1, 2, 3, 3]) # 所有出现最多的值 [1, 3] >>> st.multimode(['a', 'a', 'b', 'c']) # 支持非数值数据 ['a']

均值、中位数、众数是描述数据集中趋势的三个核心指标。均值利用了全部数据但易受异常值影响;中位数不受极端值影响,适合偏态分布;众数适用于分类数据和离散数据。

三、离散程度函数

离散程度(Dispersion)描述数据的波动性和分散程度。statistics 模块提供了总体和样本两个维度的标准差/方差计算。

3.1 总体 vs 样本:关键区别

理解总体(Population)和样本(Sample)的区别是正确使用统计函数的前提。总体方差的分母为 n,样本方差的分母为 n-1(贝塞尔校正),后者通过增加方差估计值来补偿样本对总体方差的低估。

函数含义分母适用场景
pvariance(data, mu=None)总体方差n数据代表整个群体
pstdev(data, mu=None)总体标准差n同上,方差的平方根
variance(data, xbar=None)样本方差n-1数据是总体的一个子集
stdev(data, xbar=None)样本标准差n-1同上,方差的平方根

3.2 总体标准差与总体方差

>>> data = [1, 2, 3, 4, 5] >>> st.pvariance(data) # 总体方差 = ((1-3)^2 + ... + (5-3)^2) / 5 2.0 >>> st.pstdev(data) # 总体标准差 = sqrt(2) 1.4142135623730951

3.3 样本标准差与样本方差

>>> st.variance(data) # 样本方差 = ((1-3)^2 + ... + (5-3)^2) / 4 2.5 >>> st.stdev(data) # 样本标准差 = sqrt(2.5) 1.5811388300841898

何时使用总体 vs 样本?

如果你有一整个班级 50 人的考试成绩,想知道这个"班级"的分数分布 → 用总体函数 pstdev/pvariance

如果你从全校 2000 人中随机抽取了 50 人,想通过这 50 人估计"全校"的分数分布 → 用样本函数 stdev/variance

牢记:实际情况中我们几乎总是在处理样本数据,因此 stdev/variance 的使用频率远高于总体版本。

四、统计关系函数

统计关系函数用于分析两组数据之间的关联性。自 Python 3.10 起,statistics 模块新增了协方差、皮尔逊相关系数和线性回归函数,使其具备了基础的双变量统计分析能力。

4.1 协方差 covariance(x, y, /)

协方差衡量两个变量一起变动的方向和强度。正值表示同向变动,负值表示反向变动,绝对值越大关联越强。但协方差的数值受量纲影响,不易直接解读。

>>> # 房价(万元)与面积(平方米)的关系 >>> price = [200, 350, 500, 280, 420] >>> area = [ 80, 120, 160, 100, 140] >>> st.covariance(price, area) 2887.5 # 正协方差,表明面积越大房价越高

4.2 皮尔逊相关系数 correlation(x, y, /)

皮尔逊相关系数是标准化后的协方差,取值范围在 [-1, 1] 之间。+1 表示完全正相关,-1 表示完全负相关,0 表示无线性相关。它消除了量纲影响,是衡量线性相关程度的常用指标。

>>> st.correlation(price, area) 0.972... # 接近1,表明房价与面积呈强正线性相关 >>> # 经验判断标准: >>> # |r| >= 0.8 强相关 >>> # 0.5 <= |r| < 0.8 中等相关 >>> # 0.3 <= |r| < 0.5 弱相关 >>> # |r| < 0.3 极弱或不相关

4.3 线性回归 linear_regression(x, y, /, proportional=False)

执行简单线性回归,拟合 y = slope * x + intercept 模型。返回一个 namedtuple,包含 slope(斜率)、intercept(截距)两个属性。当 proportional=True 时,强制截距为 0,拟合 y = slope * x 模型。

>>> # 根据面积预测房价 >>> result = st.linear_regression(area, price) >>> result.slope 2.820512820512821 # 面积每增加1平米,房价平均增加2.82万元 >>> result.intercept -28.71794871794869 >>> # 预测面积150平米的房价 >>> predicted = result.slope * 150 + result.intercept >>> predicted 394.359... # 约394万元

需要注意的是,correlation 和 linear_regression 仅能检测线性关系。对于非线性关系(如 y=x^2),即使变量之间完全相关,这两个函数也可能返回很低的值。在实际分析中,先绘制散点图观察数据分布是一个好习惯。

五、统计对象选择

statistics 模块提供了一个面向对象的概率分布类 — NormalDist,它封装了正态分布(高斯分布)的完整功能,包括概率密度函数、累积分布函数、分位数计算和随机采样等。

5.1 NormalDist 的创建与基本属性

NormalDist(mu=0, sigma=1) 用均值 mu 和标准差 sigma 创建一个正态分布对象,默认为标准正态分布。

>>> # 创建一个均值170、标准差6的正态分布(模拟成年男性身高分布) >>> height_dist = st.NormalDist(mu=170, sigma=6) >>> height_dist.mean 170 >>> height_dist.stdev 6 >>> height_dist.variance 36

5.2 概率密度函数 pdf(x)

返回 x 处的概率密度值。对于连续分布,pdf 的值不是概率,而是概率密度。曲线下的面积才代表概率。

>>> height_dist.pdf(170) # 均值处的概率密度最高 0.06649038006681569 >>> height_dist.pdf(176) # 偏离均值1个标准差 0.04318035388873635 >>> height_dist.pdf(158) # 偏离均值2个标准差 0.008863696823766015

5.3 累积分布函数 cdf(x)

返回 P(X <= x),即随机变量小于等于 x 的累积概率。这是实际应用中最常用的函数之一。

>>> # 身高 <= 170cm 的概率(即中等及以下身高人群比例) >>> height_dist.cdf(170) 0.5 >>> # 身高 <= 176cm 的概率(一个标准差内) >>> height_dist.cdf(176) 0.8413447460685429 >>> # 身高 <= 158cm 的概率(两个标准差外) >>> height_dist.cdf(158) 0.022750131948179195

5.4 分位函数 inv_cdf(p)

cdf 的反函数。给定概率 p,返回使得 P(X <= x) = p 的 x 值。用于计算百分位数。

>>> # 身高分布的 50% 分位数(即中位数) >>> height_dist.inv_cdf(0.5) 170.0 >>> # 身高分布的 95% 分位数(95% 的人身高低于此值) >>> height_dist.inv_cdf(0.95) 179.86913707137946 # 约 180cm >>> # 身高分布的 2.5% 分位数 >>> height_dist.inv_cdf(0.025) 158.24008768796923 # 约 158cm

5.5 随机采样 samples(n, /, *, seed=None)

从分布中生成 n 个随机样本。可选 seed 参数控制随机种子,确保结果可重现。

>>> # 模拟生成10个成年男性身高样本 >>> height_dist.samples(10, seed=42) [171.27, 174.91, 167.30, 166.01, 173.92, 163.98, 166.17, 169.10, 171.34, 179.27]

5.6 NormalDist 的运算

NormalDist 支持加法和减法运算,结果仍然是正态分布(正态分布对独立随机变量的线性组合具有封闭性)。

>>> # 两个独立正态分布之和 >>> d1 = st.NormalDist(100, 15) # IQ 分布 >>> d2 = st.NormalDist(0, 5) # 额外加分 >>> (d1 + d2).mean # 总分均值 = 100 + 0 = 100 100 >>> (d1 + d2).stdev # 总分标准差 = sqrt(15^2 + 5^2) ≈ 15.81 15.811388300841896

NormalDist 实用场景:

1. 考试成绩等级划分 — 用 inv_cdf 计算分数线

2. 质量控制 — 用 cdf 计算不合格品率

3. 风险评估 — 用 cdf 计算极端事件概率

4. 随机模拟 — 用 samples 生成测试数据

5. 正态分布近似 — 用 NormalDist 近似二项分布等

六、实战案例与总结

6.1 案例:学生成绩分析

假设我们有一个班级的期末考试成绩数据,综合分析其集中趋势、离散程度和分布特征。

import statistics as st # 学生成绩数据 scores = [88, 92, 76, 85, 94, 67, 78, 83, 90, 71, 86, 79, 82, 95, 73, 88, 91, 84, 77, 69] # 集中趋势分析 print(f"平均分: {st.mean(scores):.1f}") print(f"中位数: {st.median(scores):.1f}") print(f"众数: {st.multimode(scores)}") # 离散程度分析 print(f"标准差: {st.stdev(scores):.1f}") print(f"方差: {st.variance(scores):.1f}") # 假设及格线为60分,估计合格率 score_dist = st.NormalDist(st.mean(scores), st.stdev(scores)) pass_rate = 1 - score_dist.cdf(60) print(f"预计合格率: {pass_rate*100:.1f}%") # 前10%的分数线 top10 = score_dist.inv_cdf(0.9) print(f"前10%分数线: {top10:.1f}分")
# 输出结果 平均分: 81.4 中位数: 83.0 众数: [88] 标准差: 8.2 方差: 67.2 预计合格率: 99.5% 前10%分数线: 91.9分

6.2 案例:线性回归预测

import statistics as st # 广告投入与销售额数据(万元) ad_spend = [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5] sales = [12, 15, 18, 22, 25, 28, 31, 34, 38, 41] # 相关性分析 r = st.correlation(ad_spend, sales) print(f"相关系数: {r:.4f}") # 接近1,高度正相关 # 建立回归模型 model = st.linear_regression(ad_spend, sales) print(f"回归方程: y = {model.slope:.2f}x + {model.intercept:.2f}") # 预测广告投入6万元时的销售额 predict = model.slope * 6.0 + model.intercept print(f"广告6万元预计销售额: {predict:.1f}万元")
# 输出结果 相关系数: 0.9987 回归方程: y = 6.36x + 5.73 广告6万元预计销售额: 43.9万元

6.3 核心要点总结

类别函数/类适用版本一句话记忆
集中趋势mean / fmean3.4 / 3.8+算术平均数,最基础的平均
median / median_low / median_high3.4中位数,抗异常值能力强
mode / multimode3.4 / 3.8+众数,适合分类数据
geometric_mean / harmonic_mean3.8+几何/调和平均,特殊场景使用
离散程度pstdev / pvariance3.4总体标准差/方差,分母为n
stdev / variance3.4样本标准差/方差,分母为n-1
统计关系covariance3.10+协方差,量纲相关
correlation3.10+皮尔逊相关系数,[-1,1]
linear_regression3.10+一元线性回归拟合
概率分布NormalDist3.8+正态分布对象,pdf/cdf/samples

学习建议:

1. 掌握 mean、median、stdev、correlation 四个最常用函数,覆盖80%日常统计需求

2. 区分总体和样本函数是入门阶段最容易出错的地方,理解 n-1 的含义比死记硬背更重要

3. NormalDist 是 Python 3.8 之后的亮点功能,将统计函数从"单次计算"升级为"分布建模",值得重点掌握

4. 对于更复杂的统计任务(假设检验、ANOVA、多变量回归),建议学习 SciPy.stats 和 statsmodels

6.4 进一步思考

statistics 模块的设计理念是"小而精",它为 Python 开发者提供了无需任何第三方依赖的基础统计能力。在实际工程中,我们往往将 statistics 模块用于数据探索性分析(EDA)阶段,快速获取数据的统计特征,再根据需求决定是否引入更专业的统计库。

掌握 statistics 模块的价值不仅在于学会10多个函数的调用,更在于建立起对"描述性统计"整体框架的认知——当你面对一组数据时,应该从哪些维度去描述它、每种指标反映了数据的什么特征、如何选择合适的统计量。这种统计思维是数据分析和机器学习的重要基础。