statistics — 数学统计函数 — Python 文档

来自菜鸟教程
Python/docs/3.8/library/statistics
跳转至:导航、​搜索

statistics — 数理统计函数

3.4 版中的新功能。


源代码: :source:`Lib/statistics.py`



该模块提供用于计算数值(Real 值)数据的数理统计的函数。

该模块无意成为第三方库(如 NumPySciPy)或面向专业统计学家(如 Minitab、SAS 和 Matlab)的专有全功能统计软件包的竞争对手. 它针对图形和科学计算器的级别。

除非明确说明,否则这些函数支持 intfloatDecimalFraction。 当前不支持其他类型的行为(无论是否在数字塔中)。 混合类型的集合也是未定义的并且依赖于实现。 如果您的输入数据由混合类型组成,您可以使用 map() 来确保一致的结果,例如:map(float, input_data)

中心位置的平均值和度量

这些函数计算总体或样本的平均值或典型值。

mean() 数据的算术平均值(“平均值”)。
fmean() 快速,浮点算术平均值。
geometric_mean() 数据的几何平均值。
harmonic_mean() 数据的调和平均值。
median() 数据的中位数(中间值)。
median_low() 数据中位数较低。
median_high() 数据中位数高。
median_grouped() 分组数据的中位数或第 50 个百分位数。
mode() 离散或标称数据的单一模式(最常见的值)。
multimode() 离散或标称数据的模式(最常见的值)列表。
quantiles() 将数据划分为具有相等概率的区间。


传播措施

这些函数计算总体或样本倾向于偏离典型值或平均值的程度。

pstdev() 数据的总体标准偏差。
pvariance() 数据的总体方差。
stdev() 数据的样本标准差。
variance() 数据的样本方差。


功能详情

注意:这些函数不需要对提供给它们的数据进行排序。 但是,为了阅读方便,大多数示例都显示了排序序列。

statistics.mean(data)

返回 data 的样本算术平均值,可以是序列或可迭代的。

算术平均值是数据的总和除以数据点的数量。 它通常被称为“平均值”,尽管它只是许多不同的数学平均值之一。 它是对数据中心位置的度量。

如果 data 为空,则会引发 StatisticsError

一些使用示例:

>>> mean([1, 2, 3, 4, 4])
2.8
>>> mean([-1.0, 2.5, 3.25, 5.75])
2.625

>>> from fractions import Fraction as F
>>> mean([F(3, 7), F(1, 21), F(5, 3), F(1, 3)])
Fraction(13, 21)

>>> from decimal import Decimal as D
>>> mean([D("0.5"), D("0.75"), D("0.625"), D("0.375")])
Decimal('0.5625')

笔记

均值受异常值的影响很大,并且不是中心位置的稳健估计量:均值不一定是数据点的典型示例。 有关中心位置的更可靠度量,请参阅 median()mode()

样本均值给出了真实总体均值的无偏估计,因此当对所有可能的样本取平均值时,mean(sample) 收敛于整个总体的真实均值。 如果 data 代表整个总体而不是样本,那么 mean(data) 相当于计算真实总体均值 μ。

statistics.fmean(data)

data 转换为浮点数并计算算术平均值。

这比 mean() 函数运行得更快,并且它总是返回一个 floatdata 可以是序列或可迭代的。 如果输入数据集为空,则引发 StatisticsError

>>> fmean([3.5, 4.0, 5.25])
4.25

3.8 版中的新功能。

statistics.geometric_mean(data)

data 转换为浮点数并计算几何平均值。

几何平均值表示 数据 使用值的乘积(与使用它们的总和的算术平均值相反)的集中趋势或典型值。

如果输入数据集为空、包含零或包含负值,则引发 StatisticsErrordata 可以是序列或可迭代的。

没有特别的努力来获得准确的结果。 (但是,这在未来可能会改变。)

>>> round(geometric_mean([54, 24, 36]), 1)
36.0

3.8 版中的新功能。

statistics.harmonic_mean(data)

返回 data 的调和平均值,实值数的序列或可迭代对象。

调和平均数,有时称为逆向平均数,是数据倒数的算术 mean() 的倒数。 例如,三个值 abc 的调和平均值将等价于 3/(1/a + 1/b + 1/c)。 如果其中一个值为零,则结果为零。

调和平均值是一种平均值,是数据中心位置的度量。 在平均速率或比率时通常是合适的,例如速度。

假设一辆汽车以 40 公里/小时的速度行驶了 10 公里,然后又以 60 公里/小时的速度行驶了 10 公里。 平均速度是多少?

>>> harmonic_mean([40, 60])
48.0

假设投资者购买三家公司中每家公司的等值股份,市盈率(市盈率)分别为 2.5、3 和 10。 投资者投资组合的平均市盈率是多少?

>>> harmonic_mean([2.5, 3, 10])  # For an equal investment portfolio.
3.6

StatisticsError 如果 data 为空,或者任何元素小于零,则会引发 StatisticsError

当前算法在输入中遇到零时会提前退出。 这意味着不测试后续输入的有效性。 (这种行为将来可能会改变。)

3.6 版中的新功能。

statistics.median(data)

使用常见的“中间两个平均值”方法返回数值数据的中值(中间值)。 如果 data 为空,则引发 StatisticsErrordata 可以是一个序列或可迭代的。

中位数是对中心位置的可靠度量,受异常值的影响较小。 当数据点数为奇数时,返回中间数据点:

>>> median([1, 3, 5])
3

当数据点数为偶数时,通过取两个中间值的平均值来插值中位数:

>>> median([1, 3, 5, 7])
4.0

这适用于您的数据是离散的,并且您不介意中位数可能不是实际数据点的情况。

如果数据是序数(支持顺序操作)但不是数字(不支持加法),请考虑使用 median_low()median_high() 代替。

statistics.median_low(data)

返回数值数据的低中位数。 如果 data 为空,则引发 StatisticsErrordata 可以是一个序列或可迭代的。

低中位数始终是数据集的成员。 当数据点数为奇数时,返回中间值。 当它是偶数时,返回两个中间值中较小的一个。

>>> median_low([1, 3, 5])
3
>>> median_low([1, 3, 5, 7])
3

当您的数据是离散的并且您希望中位数是实际数据点而不是插值时,请使用低中位数。

statistics.median_high(data)

返回数据的高中位数。 如果 data 为空,则引发 StatisticsErrordata 可以是一个序列或可迭代的。

高中位数始终是数据集的成员。 当数据点数为奇数时,返回中间值。 当它是偶数时,返回两个中间值中较大的一个。

>>> median_high([1, 3, 5])
3
>>> median_high([1, 3, 5, 7])
5

当您的数据是离散的并且您希望中位数是实际数据点而不是插值时,请使用高中位数。

statistics.median_grouped(data, interval=1)

使用插值返回分组连续数据的中位数,计算为第 50 个百分位数。 如果 data 为空,则引发 StatisticsErrordata 可以是一个序列或可迭代的。

>>> median_grouped([52, 52, 53, 54])
52.5

在下面的例子中,数据被四舍五入,所以每个值代表数据类的中点,例如 1 是类 0.5-1.5 的中点,2 是 1.5-2.5 的中点,3 是 2.5-3.5 的中点,以此类推。 根据给定的数据,中间值属于 3.5-4.5 类,并使用插值来估计它:

>>> median_grouped([1, 2, 2, 3, 4, 4, 4, 4, 4, 5])
3.7

可选参数 interval 表示类间隔,默认为 1。 自然地改变类间隔会改变插值:

>>> median_grouped([1, 3, 3, 5, 7], interval=1)
3.25
>>> median_grouped([1, 3, 3, 5, 7], interval=2)
3.5

此函数不检查数据点是否至少间隔 间隔

也可以看看

  • “行为科学统计”,Frederick J Gravetter 和 Larry B Wallnau(第 8 版)。

  • Gnome Gnumeric 电子表格中的 SSMEDIAN 函数,包括 这个讨论


statistics.mode(data)

从离散或标称 数据 返回单个最常见的数据点。 众数(当它存在时)是最典型的值,用作中心位置的度量。

如果有多个相同频率的模式,则返回data中遇到的第一个。 如果需要其中的最小或最大,请使用 min(multimode(data))max(multimode(data))。 如果输入 data 为空,则会引发 StatisticsError

mode 假设离散数据并返回单个值。 这是学校通常教授的模式的标准处理方式:

>>> mode([1, 1, 2, 3, 3, 3, 3, 4])
3

该模式的独特之处在于它是此包中唯一也适用于名义(非数字)数据的统计数据:

>>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
'red'

3.8 版更改: 现在通过返回遇到的第一个模式来处理多模式数据集。 以前,当发现不止一种模式时,它会引发 StatisticsError

statistics.multimode(data)

按照它们在 data 中首次遇到的顺序返回最常出现的值的列表。 如果有多种模式,将返回多个结果,如果 data 为空,则返回一个空列表:

>>> multimode('aabbbbccddddeeffffgg')
['b', 'd', 'f']
>>> multimode('')
[]

3.8 版中的新功能。

statistics.pstdev(data, mu=None)

返回总体标准差(总体方差的平方根)。 有关参数和其他详细信息,请参阅 pvariance()

>>> pstdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
0.986893273527251
statistics.pvariance(data, mu=None)

返回 data 的总体方差,一个非空序列或可迭代的实数值。 方差,或关于均值的二阶矩,是对数据可变性(传播或分散)的度量。 大的方差表明数据是分散的; 小的方差表明它紧密地聚集在均值附近。

如果给出了可选的第二个参数 mu,它通常是 data 的平均值。 它还可用于计算非均值点周围的二阶矩。 如果缺少或 None(默认值),则自动计算算术平均值。

使用此函数计算整个总体的方差。 要估计样本的方差,variance() 函数通常是更好的选择。

如果 data 为空,则引发 StatisticsError

例子:

>>> data = [0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25]
>>> pvariance(data)
1.25

如果您已经计算了数据的平均值,则可以将其作为可选的第二个参数 mu 传递以避免重新计算:

>>> mu = mean(data)
>>> pvariance(data, mu)
1.25

支持小数和分数:

>>> from decimal import Decimal as D
>>> pvariance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
Decimal('24.815')

>>> from fractions import Fraction as F
>>> pvariance([F(1, 4), F(5, 4), F(1, 2)])
Fraction(13, 72)

笔记

当用整个总体调用时,这给出了总体方差 σ²。 当改为调用样本时,这是有偏样本方差 s²,也称为具有 N 自由度的方差。

如果您以某种方式知道真实的总体均值 μ,则可以使用此函数来计算样本的方差,将已知总体均值作为第二个参数。 如果数据点是总体的随机样本,则结果将是总体方差的无偏估计。

statistics.stdev(data, xbar=None)

返回样本标准差(样本方差的平方根)。 有关参数和其他详细信息,请参阅 variance()

>>> stdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
1.0810874155219827
statistics.variance(data, xbar=None)

返回 data 的样本方差,它是至少两个实数值的迭代。 方差,或关于均值的二阶矩,是对数据可变性(传播或分散)的度量。 大的方差表明数据是分散的; 小的方差表明它紧密地聚集在均值附近。

如果给出了可选的第二个参数 xbar,它应该是 data 的平均值。 如果缺失或 None(默认值),则会自动计算平均值。

当您的数据是来自总体的样本时,请使用此函数。 要计算整个总体的方差,请参阅 pvariance()

如果 data 的值少于两个,则引发 StatisticsError

例子:

>>> data = [2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]
>>> variance(data)
1.3720238095238095

如果您已经计算了数据的平均值,则可以将其作为可选的第二个参数 xbar 传递以避免重新计算:

>>> m = mean(data)
>>> variance(data, m)
1.3720238095238095

此函数不会尝试验证您是否已通过 xbar 的实际平均值。 对 xbar 使用任意值会导致无效或不可能的结果。

支持小数和小数值:

>>> from decimal import Decimal as D
>>> variance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
Decimal('31.01875')

>>> from fractions import Fraction as F
>>> variance([F(1, 6), F(1, 2), F(5, 3)])
Fraction(67, 108)

笔记

这是具有贝塞尔校正的样本方差 s²,也称为具有 N-1 自由度的方差。 前提是数据点具有代表性(例如 独立同分布),结果应该是真实总体方差的无偏估计。

如果您以某种方式知道实际总体均值 μ,您应该将其作为 mu 参数传递给 pvariance() 函数以获得样本的方差。

statistics.quantiles(data, *, n=4, method='exclusive')

data 分成 n 个等概率连续区间。 返回分隔间隔的 n - 1 切割点列表。

将四分位数的 n 设置为 4(默认值)。 对于十分位数,将 n 设置为 10。 对于百分位数,将 n 设置为 100,这将提供 99 个切割点,将 data 分成 100 个相同大小的组。 如果 n 不小于 1,则引发 StatisticsError

data 可以是包含样本数据的任何可迭代对象。 对于有意义的结果,data 中的数据点数应大于 n。 如果没有至少两个数据点,则引发 StatisticsError

切割点从两个最近的数据点线性插值。 例如,如果切割点落在两个样本值 100112 之间距离的三分之一处,则该切割点的计算结果为 104

用于计算分位数的 方法 可以根据 数据 是否包含或排除总体中的最低和最高可能值而有所不同。

默认的 方法 是“独占的”,用于从可能具有比样本中发现的更多的极端值的总体中采样的数据。 低于 m 排序数据点的 i-th 的总体部分计算为 i / (m + 1)。 给定九个样本值,该方法对它们进行排序并分配以下百分位数:10%、20%、30%、40%、50%、60%、70%、80%、90%。

方法 设置为“包含”用于描述总体数据或用于已知包含总体中最极端值的样本。 data 中的最小值被视为第 0 个百分位数,最大值被视为第 100 个百分位数。 低于 m 排序数据点的 i-th 的总体部分计算为 (i - 1) / (m - 1)。 给定 11 个样本值,该方法对它们进行排序并分配以下百分位数:0%、10%、20%、30%、40%、50%、60%、70%、80%、90%、100%。

# Decile cut points for empirically sampled data
>>> data = [105, 129, 87, 86, 111, 111, 89, 81, 108, 92, 110,
...         100, 75, 105, 103, 109, 76, 119, 99, 91, 103, 129,
...         106, 101, 84, 111, 74, 87, 86, 103, 103, 106, 86,
...         111, 75, 87, 102, 121, 111, 88, 89, 101, 106, 95,
...         103, 107, 101, 81, 109, 104]
>>> [round(q, 1) for q in quantiles(data, n=10)]
[81.0, 86.2, 89.0, 99.4, 102.5, 103.6, 106.0, 109.8, 111.0]

3.8 版中的新功能。


例外

定义了一个异常:

exception statistics.StatisticsError
ValueError 的子类,用于统计相关异常。


NormalDist 对象

NormalDist 是用于创建和操作 随机变量 的正态分布的工具。 它是一个将数据测量的均值和标准差视为单个实体的类。

正态分布源自 中心极限定理 ,在统计学中有着广泛的应用。

class statistics.NormalDist(mu=0.0, sigma=1.0)

返回一个新的 NormalDist 对象,其中 mu 表示 算术平均值sigma 表示 标准偏差

如果 sigma 为负,则引发 StatisticsError

mean

正态分布的 算术平均值 的只读属性。

median

正态分布的 中值 的只读属性。

mode

正态分布的 mode 的只读属性。

stdev

正态分布的 标准偏差 的只读属性。

variance

正态分布的 方差 的只读属性。 等于标准差的平方。

classmethod from_samples(data)

使用 fmean() 和 stdev()[ 从 data 估计的 musigma 参数制作正态分布实例X155X]。

data 可以是任何 iterable 并且应该由可以转换为类型 float 的值组成。 如果 data 不包含至少两个元素,则引发 StatisticsError,因为它至少需要一个点来估计中心值,至少需要两个点来估计离散度。

samples(n, *, seed=None)

为给定的均值和标准差生成 n 个随机样本。 返回 float 值的 list

如果给出 seed,则创建底层随机数生成器的新实例。 这对于创建可重现的结果非常有用,即使在多线程上下文中也是如此。

pdf(x)

使用 概率密度函数 (pdf),计算随机变量 X 将接近给定值 x 的相对可能性。 在数学上,当 dx 接近零时,它是比率 P(x <= X < x+dx) / dx 的极限。

相对似然计算为样本出现在狭窄范围内的概率除以范围的宽度(因此称为“密度”)。 由于似然是相对于其他点,其值可以大于1.0。

cdf(x)

使用 累积分布函数 (cdf),计算随机变量 X 小于或等于 x 的概率。 在数学上,它被写成 P(X <= x)

inv_cdf(p)

计算逆累积分布函数,也称为 分位数函数percent-point 函数。 在数学上,它被写成 x : P(X <= x) = p

求随机变量 X 的值 x,使得变量小于或等于该值的概率等于给定的概率 p

overlap(other)

测量两个正态概率分布之间的一致性。 返回一个介于 0.0 和 1.0 之间的值,给出 两个概率密度函数 的重叠区域。

quantiles(n=4)

以等概率将正态分布划分为 n 个连续区间。 返回分隔间隔的 (n - 1) 个切割点列表。

将四分位数的 n 设置为 4(默认值)。 对于十分位数,将 n 设置为 10。 对于百分位数,将 n 设置为 100,这给出了将正态分布分成 100 个大小相等的组的 99 个切割点。

NormalDist 的实例支持常量的加减乘除。 这些操作用于平移和缩放。 例如:

>>> temperature_february = NormalDist(5, 2.5)             # Celsius
>>> temperature_february * (9/5) + 32                     # Fahrenheit
NormalDist(mu=41.0, sigma=4.5)

不支持将常量除以 NormalDist 的实例,因为结果不会呈正态分布。

由于正态分布是由自变量的加法效应引起的,因此可以 加减两个独立的正态分布随机变量 ,表示为 NormalDist 的实例。 例如:

>>> birth_weights = NormalDist.from_samples([2.5, 3.1, 2.1, 2.4, 2.7, 3.5])
>>> drug_effects = NormalDist(0.4, 0.15)
>>> combined = birth_weights + drug_effects
>>> round(combined.mean, 1)
3.1
>>> round(combined.stdev, 1)
0.5

3.8 版中的新功能。

NormalDist 例子和食谱

NormalDist 很容易解决经典的概率问题。

例如,给定 SAT 考试的历史数据 显示分数呈正态分布,平均值为 1060,标准差为 195,在四舍五入到最接近的整数:

>>> sat = NormalDist(1060, 195)
>>> fraction = sat.cdf(1200 + 0.5) - sat.cdf(1100 - 0.5)
>>> round(fraction * 100.0, 1)
18.4

找到 SAT 分数的 四分位数分位数

>>> list(map(round, sat.quantiles()))
[928, 1060, 1192]
>>> list(map(round, sat.quantiles(n=10)))
[810, 896, 958, 1011, 1060, 1109, 1162, 1224, 1310]

为了估计不容易解析求解的模型分布,NormalDist 可以为 蒙特卡罗模拟 生成输入样本:

>>> def model(x, y, z):
...     return (3*x + 7*x*y - 5*y) / (11 * z)
...
>>> n = 100_000
>>> X = NormalDist(10, 2.5).samples(n, seed=3652260728)
>>> Y = NormalDist(15, 1.75).samples(n, seed=4582495471)
>>> Z = NormalDist(50, 1.25).samples(n, seed=6582483453)
>>> quantiles(map(model, X, Y, Z))       
[1.4591308524824727, 1.8035946855390597, 2.175091447274739]

当样本量很大且试验成功的概率接近 50% 时,正态分布可用于近似 二项式分布

例如,一个开源会议有 750 名与会者和两个可容纳 500 人的房间。 有一个关于 Python 的讨论,另一个关于 Ruby 的讨论。 在之前的会议中,65% of 的与会者更喜欢听 Python 演讲。 假设人口偏好没有改变,Python 房间保持在其容量限制内的概率是多少?

>>> n = 750             # Sample size
>>> p = 0.65            # Preference for Python
>>> q = 1.0 - p         # Preference for Ruby
>>> k = 500             # Room capacity

>>> # Approximation using the cumulative normal distribution
>>> from math import sqrt
>>> round(NormalDist(mu=n*p, sigma=sqrt(n*p*q)).cdf(k + 0.5), 4)
0.8402

>>> # Solution using the cumulative binomial distribution
>>> from math import comb, fsum
>>> round(fsum(comb(n, r) * p**r * q**(n-r) for r in range(k+1)), 4)
0.8402

>>> # Approximation using a simulation
>>> from random import seed, choices
>>> seed(8675309)
>>> def trial():
...     return choices(('Python', 'Ruby'), (p, q), k=n).count('Python')
>>> mean(trial() <= k for i in range(10_000))
0.8398

正态分布通常出现在机器学习问题中。

维基百科有一个 朴素贝叶斯分类器 的好例子。 面临的挑战是通过测量正态分布特征(包括身高、体重和脚的大小)来预测一个人的性别。

我们得到了一个训练数据集,其中包含八个人的测量数据。 假设测量值是正态分布的,所以我们用 NormalDist 总结数据:

>>> height_male = NormalDist.from_samples([6, 5.92, 5.58, 5.92])
>>> height_female = NormalDist.from_samples([5, 5.5, 5.42, 5.75])
>>> weight_male = NormalDist.from_samples([180, 190, 170, 165])
>>> weight_female = NormalDist.from_samples([100, 150, 130, 150])
>>> foot_size_male = NormalDist.from_samples([12, 11, 12, 10])
>>> foot_size_female = NormalDist.from_samples([6, 8, 7, 9])

接下来,我们遇到一个新人,其特征测量值已知但性别未知:

>>> ht = 6.0        # height
>>> wt = 130        # weight
>>> fs = 8          # foot size

从男性或女性的 50% 先验概率 开始,我们将后验计算为给定性别的特征测量的似然乘积的先验乘积:

>>> prior_male = 0.5
>>> prior_female = 0.5
>>> posterior_male = (prior_male * height_male.pdf(ht) *
...                   weight_male.pdf(wt) * foot_size_male.pdf(fs))

>>> posterior_female = (prior_female * height_female.pdf(ht) *
...                     weight_female.pdf(wt) * foot_size_female.pdf(fs))

最后的预测去最大的后验。 这被称为 最大后验 或 MAP:

>>> 'male' if posterior_male > posterior_female else 'female'
'female'