ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

python常见统计分析处理函数解读

python常见统计分析处理函数解读

前言


提到"统计分析",很多人第一反应是安装 NumPy 或 pandas。但如果只是要算一组 数据的平均值、中位数、标准差,标准库里的statistics模块就够了,不用 装任何第三方库。它从 Python 3.4 起就存在,import statistics即可使用。


这里有个常见误解:以为"标准差"只有一个数。实际上统计学里要区分样本 标准差和总体标准差——statistics.stdev()算的是样本标准差,分母是 n-1;statistics.pstdev()算的是总体标准差,分母是 n。用错一个字母,结果就 不一样,而报错往往是"数值对不上"这种很隐蔽的症状。


本文按"集中趋势 / 离散程度 / 两组数据的关系"三类,讲清楚statistics里 常用函数的签名、返回值类型和版本要求,并说明它和 NumPy 的适用边界。 文中所有函数签名都以 Python 官方文档为准,涉及 3.8 / 3.10 / 3.12 才加入的 特性会单独标注。


一、集中趋势:平均、中位数、众数


这一组回答"数据围绕哪个中心值分布"。


# 适用于 Python 3.8+

import statistics

data = [2, 4, 4, 4, 5, 5, 7, 9]

print(statistics.mean(data)) # 5.0 算术平均
print(statistics.median(data)) # 4.5 中位数(偶数个取中间两数平均)
print(statistics.mode(data)) # 4 出现次数最多的值

几个必须记住的差别:



  • mean(data)返回的类型跟着输入走。如果传入的是Fraction或


Decimal,它会做精确运算并返回同样的类型;传普通整数列表时返回float。 想要"一定是浮点、且更快",用fmean(data, weights=None)(3.8 加入), 它永远返回float。



  • median()是一族函数。median_low()在偶数个元素时取偏低的中位数,


median_high()取偏高的;median_grouped(data, interval=1.0)用于分组 数据(已经按组统计过的频率表)。



  • mode()只返回一个值。如果数据有多个并列的众数,从 3.8 起它返回


先遇到的那个,而不是报错。想拿到全部众数,用multimode(data)(3.8 加入),返回一个列表。


# 适用于 Python 3.8+

import statistics

scores = [60, 70, 70, 80, 80, 90]
print(statistics.mode(scores)) # 70 (先遇到的)
print(statistics.multimode(scores)) # [70, 80] 全部众数

另外还有三种平均:geometric_mean(data)(几何平均,3.8 加入,常用于比率、 增长率)、harmonic_mean(data, weights=None)(调和平均,3.6 加入,常用于 平均速度)、以及fmean(快速算术平均)。


二、离散程度:方差与标准差


这一组回答"数据散得有多开"。关键是分清样本还是总体。


# 适用于 Python 3.8+

import statistics

data = [2, 4, 4, 4, 5, 5, 7, 9]

print(statistics.pstdev(data)) # 总体标准差 (除以 n)
print(statistics.stdev(data)) # 样本标准差 (除以 n-1)
print(statistics.pvariance(data)) # 总体方差
print(statistics.variance(data)) # 样本方差



函数含义分母何时用



pstdev(data, mu=None)总体标准差n数据就是全部总体

stdev(data, xbar=None)样本标准差n-1用样本估计总体

pvariance(data, mu=None)总体方差n同上

variance(data, xbar=None)样本方差n-1同上



参数mu/xbar允许你把"已知的真实均值"传进去,避免函数再算一遍。默认 是None,表示由函数自己从数据里算。样本方差必须至少有两个数据点,否则 会抛statistics.StatisticsError;总体方差有一个点就够了。


三、分位数:把数据切成若干段


quantiles(data, *, n=4, method='exclusive')(3.8 加入)把数据切成 n 段, 返回 n-1 个切点。默认n=4就是四分位。


# 适用于 Python 3.8+

import statistics

data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(statistics.quantiles(data, n=4)) # [2.75, 5.5, 8.25] (exclusive)
print(statistics.quantiles(data, n=4, method='inclusive')) # [3.25, 5.5, 7.75]
print(statistics.quantiles(data, n=10)) # 十分位

注意这两个参数只能按关键字传(*之后的参数不能按位置传):n和method必须写成n=4、method='inclusive'这样的形式。method可取'exclusive'(默认,适用于样本)或'inclusive'(适用于总体)。


四、两组数据的关系


这一组函数只在 Python 3.10 及以上才有,用法是把两个等长序列一起传进去。


# 适用于 Python 3.10+

import statistics

x = [1, 2, 3, 4, 5]
y = [2, 4, 6, 8, 10]

print(statistics.covariance(x, y)) # 5.0 样本协方差
print(statistics.correlation(x, y)) # 1.0 皮尔逊相关系数
slope, intercept = statistics.linear_regression(x, y)
print(slope, intercept) # 2.0 0.0


  • covariance(x, y, /)—— 样本协方差,两个参数是仅位置参数(/之前的


参数不能按关键字传)。



  • correlation(x, y, /, *, method='linear')—— 默认算皮尔逊相关系数;


从3.12 起可以把method设为'rank',改算斯皮尔曼等级相关系数。



  • linear_regression(x, y, /, *, proportional=False)—— 返回斜率与截距的


二元组(slope, intercept);从3.11 起有proportional参数, 为真时强制回归线过原点。


五、正态分布与 z 分数


statistics.NormalDist(mu=0.0, sigma=1.0)是一个表示正态分布的类(3.8 加入), 支持加减乘除、求累积分布、求分位数等。


# 适用于 Python 3.8+

import statistics

normal = statistics.NormalDist(mu=100, sigma=15)

print(round(normal.cdf(115), 4)) # 0.8413 累积概率
print(round(normal.inv_cdf(0.5), 1)) # 100.0 中位数即 mu
print(round(normal.zscore(130), 2)) # zscore 从 3.9 起可用

zscore(x)(3.9 起加入)返回(x - mean) / stdev。NormalDist还能用from_samples(data)从数据里估计出均值和标准差。


六、和 NumPy 的分工




场景推荐原因



少量数据的常规统计statistics纯标准库,无需安装

需要精确的分数 / 小数运算statistics支持Fraction/Decimal

大数组、逐元素向量化运算NumPystatistics是纯 Python,逐个遍历

复杂分布、假设检验需第三方库标准库只提供基本正态分布



statistics是纯 Python 实现,对几万以内的数据完全够用;但要处理百万级 数组或需要广播运算,就该用 NumPy。这不是"哪个更好"的问题,而是用途不同。


常见坑点



  1. 把 stdev 和 pstdev 用反


``python data = [2, 4, 6, 8] # ❌ 数据本身就是全部总体,却用了样本公式 statistics.stdev(data) # ✅ 数据就是总体时用 pstdev statistics.pstdev(data)``



  1. 样本统计量数据太少


``python # ❌ 只有一个数据点,stdev 会抛 StatisticsError statistics.stdev([5]) # ✅ 样本标准差至少需要两个点 statistics.stdev([5, 7])``



  1. 对空序列调 mean / median


``python # ❌ 空列表直接抛 StatisticsError statistics.mean([]) # ✅ 先判空,给出自己的默认值 data = [] result = statistics.mean(data) if data else 0``



  1. 以为 mode 在有多个众数时会报错


``python # ❌ 以为会抛异常,其实 3.8+ 只返回第一个 # ✅ 要全部众数就用 multimode statistics.multimode([1, 1, 2, 2])``



  1. 把仅位置参数按关键字传


``python # ❌ covariance 的参数标记了 /,不能这么写 statistics.covariance(x=x, y=y) # ✅ 按位置传 statistics.covariance(x, y)``



  1. 把 quantiles 的 n 当位置参数


``python # ❌ n 在 * 之后,只能按关键字传 statistics.quantiles(data, 4) # ✅ statistics.quantiles(data, n=4)``



  1. 在 3.9 上调用 3.10 才有的函数


``python # ❌ correlation 是 3.10 加入的,旧版本没有 # ✅ 先确认版本,或用第三方库 import sys if sys.version_info >= (3, 10): statistics.correlation(x, y)``


总结




需求函数最低版本



算术平均mean/fmean3.4 / 3.8

中位数median家族3.4

众数mode/multimode3.4 / 3.8

样本标准差stdev/variance3.4

总体标准差pstdev/pvariance3.4

分位数quantiles3.8

协方差 / 相关covariance/correlation3.10

线性回归linear_regression3.10

正态分布NormalDist3.8



statistics的价值在于"零依赖、语义清晰、能精确运算",代价是它是纯 Python、 不适合超大数组。记住stdev与pstdev的区别、以及各函数的加入版本,就 能避开绝大多数误用。




RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进