← 返回Python标准库精讲目录
← 返回学习笔记首页
专题: Python标准库精讲系统学习
关键词: Python, 标准库, statistics, 统计, 平均数, 中位数, 标准差, 方差, 协方差, 相关系数
一、statistics模块概述
statistics是Python标准库中专门用于数学统计的内置模块,自Python 3.4起正式加入标准库。它提供了一系列用于处理数值数据的统计函数,涵盖集中趋势度量、离散程度度量、统计关系分析以及概率分布对象等核心功能。
与第三方库NumPy相比,statistics模块的优势在于无需额外安装、开箱即用,适合日常轻量级统计计算。其设计遵循"为常见统计问题提供便捷函数"的理念,API简洁直观,对初学者非常友好。
需要注意的是,statistics模块针对中小规模数据集设计,当处理百万级以上数据或需要矩阵运算时,建议使用NumPy/SciPy等专业科学计算库。
适用范围对比:
statistics模块 → 日常数据分析、教学示例、轻量统计计算(几百到几万条数据)
NumPy/SciPy → 大数据量、矩阵运算、高级统计分析、机器学习
statistics模块的函数可以分为四大类:
集中趋势函数 :mean、median、mode 系列
离散程度函数 :stdev、variance 系列
统计关系函数 :covariance、correlation、linear_regression
概率分布对象 :NormalDist 正态分布类
二、集中趋势函数
集中趋势(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 / fmean 3.4 / 3.8+ 算术平均数,最基础的平均
median / median_low / median_high 3.4 中位数,抗异常值能力强
mode / multimode 3.4 / 3.8+ 众数,适合分类数据
geometric_mean / harmonic_mean 3.8+ 几何/调和平均,特殊场景使用
离散程度 pstdev / pvariance 3.4 总体标准差/方差,分母为n
stdev / variance 3.4 样本标准差/方差,分母为n-1
统计关系 covariance 3.10+ 协方差,量纲相关
correlation 3.10+ 皮尔逊相关系数,[-1,1]
linear_regression 3.10+ 一元线性回归拟合
概率分布 NormalDist 3.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多个函数的调用,更在于建立起对"描述性统计"整体框架的认知——当你面对一组数据时,应该从哪些维度去描述它、每种指标反映了数据的什么特征、如何选择合适的统计量。这种统计思维是数据分析和机器学习的重要基础。