统计—math 统计Function

3.4 版的新Function。

源代码: Lib/statistics.py


此模块提供用于计算数字(具有Real值)数据的 math 统计量的Function。

该模块无意与第三方库(例如NumPySciPy)或专有的全Function统计软件包(专门针对专业统计人员(例如 Minitab,SAS 和 Matlab))竞争。它针对图形和科学计算器的水平。

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

中心位置的平均值和度量

这些函数根据总体或 samples 计算平均值或典型值。

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

传播方式

这些函数计算出总体或 samples 有多少偏离典型值或平均值的度量。

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

Function details

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

  • statistics. mean(* data *)
    • 返回* data *的 samples 算术平均值,它可以是序列或可迭代的。

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

如果* 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')

Note

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

samples 均值给出了真实总体均值的无偏估计,因此,在所有可能的 samples 中取平均值时,mean(sample)收敛于整个总体的真实均值。如果* data *代表整个总体而不是 samples,则mean(data)等效于计算真实总体平均值μ。

  • statistics. fmean(* data *)
    • 将* data *转换为浮点并计算算术平均值。

它的运行速度比mean()函数快,并且始终返回float。 * data *可以是序列或可迭代的。如果 Importing 数据集为空,则引发StatisticsError

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

3.8 版的新Function。

  • statistics. geometric_mean(* data *)
    • 将* data *转换为浮点并计算几何平均值。

几何平均值使用值的乘积(与使用它们的和的算术平均值相反)指示* data *的中心趋势或典型值。

如果 Importing 数据集为空,包含零或包含负值,则引发StatisticsError。 * data *可以是序列或可迭代的。

无需做出特殊努力即可获得准确的结果。 (但是,将来可能会改变.)

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

3.8 版的新Function。

  • statistics. harmonic_mean(* data *)
    • 返回* data *的谐波均值,它是实数值的序列或可迭代数。

调和平均值,有时也称为子相反平均值,是数据倒数的算术mean()的倒数。例如,三个值* a b c *的谐波平均值将等于3/(1/a + 1/b + 1/c)。如果值之一为零,则结果将为零。

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

假设一辆汽车以 40 km/hr 的速度行驶 10 km,然后又以 60 km/hr 的速度行驶 10 km。平均速度是多少?

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

假设投资者以 2.5、3 和 10 的本益比(市盈率)购买三家公司中每家公司的同等价值的股票,那么该投资组合的平均本益比是多少?

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

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

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

3.6 版的新Function。

  • statistics. median(* data *)
    • 使用常见的“中间两个均值”方法返回数字数据的中值(中间值)。如果* data *为空,则引发StatisticsError。 * data *可以是序列或可迭代的。

中位数是衡量中心位置的可靠方法,并且不受异常值的影响较小。当数据点数为奇数时,返回中间数据点:

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

当数据点的数量为偶数时,pass取两个中间值的平均值来对中位数进行插值:

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

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

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

  • statistics. median_low(* data *)
    • 返回数值数据的低位数。如果* data *为空,则引发StatisticsError。 * data *可以是序列或可迭代的。

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

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

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

  • statistics. median_high(* data *)
    • 返回数据的高中位数。如果* data *为空,则引发StatisticsError。 * data *可以是序列或可迭代的。

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

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

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

  • statistics. median_grouped(* data interval = 1 *)
    • 使用插值返回分组的连续数据的中位数,以第 50 个百分位数计算。如果* data *为空,则引发StatisticsError。 * data *可以是序列或可迭代的。
>>> 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

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

CPython 实现细节: 在某些情况下,median_grouped()可能会强制将数据点强制为浮点数。这种行为将来可能会改变。

See also

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

  • Gnome Gnumeric 电子表格中的SSMEDIAN函数,包括this discussion

  • statistics. mode(* data *)
    • 从离散或标称* data *返回单个最常见的数据点。模式(如果存在)是最典型的值,并用作中心位置的度量。

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

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

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

该模式是唯一的,因为它是此软件包中唯一适用于名义(非数字)数据的统计信息:

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

在 3.8 版中进行了更改:现在,pass返回遇到的第一个模式来处理多峰数据集。以前,当找到多个模式时,它会引发StatisticsError

  • statistics. multimode(* data *)
    • 以最先出现在* data 中的 Sequences 返回最频繁出现的值的列表。如果存在多种模式,将返回多个结果;如果 data *为空,则返回一个空列表:
>>> multimode('aabbbbccddddeeffffgg')
['b', 'd', 'f']
>>> multimode('')
[]

3.8 版的新Function。

  • 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(默认值),则会自动计算算术平均值。

使用此函数可计算整个总体的方差。要估算 samples 的方差,通常最好使用variance()函数。

如果* data *为空,则引发StatisticsError

Examples:

>>> 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)

Note

当与整个总体调用时,得出总体方差σ²。相反,当调用 samples 时,这是偏差 samples 方差 s²,也称为具有 N 个自由度的方差。

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

  • statistics. stdev(* data xbar = None *)
    • 返回 samples 标准偏差(samples 方差的平方根)。有关参数和其他详细信息,请参见variance()
>>> stdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
1.0810874155219827
  • statistics. variance(* data xbar = None *)
    • 返回* data *的 samples 方差,它是至少两个实数值的可迭代数。方差或均值的第二阶矩是数据变异性(扩展或离散)的量度。较大的差异表示数据已散布;较小的方差表明它紧密围绕均值聚集。

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

当数据是总体 samples 时,请使用此Function。要计算整个总体的方差,请参见pvariance()

如果* data *的值少于两个,则加StatisticsError

Examples:

>>> 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

此函数不会try验证您是否已将实际平均值传递为* 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)

Note

这是具有 Bessel 校正的 samples 方差 s²,也称为具有 N-1 自由度的方差。假设数据点具有代表性(例如独立且均匀分布),则结果应为真实总体方差的无偏估计。

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

  • 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

计算分位数的方法可以根据数据是否包括总体中的最低和最高值而有所不同。

默认的“方法”是“排他的”,用于从总体中抽取的极端值可能比 samples 中发现的值更多的数据。落在* m 个排序数据点的第 i *个以下的总体部分被计算为i / (m + 1)。给定九个 samples 值,该方法对它们进行排序并分配以下百分位数:10%,20%,30%,40%,50%,60%,70%,80%,90%。

方法设置为“包括”可用于描述总体数据或已知包含总体中最极端值的 samples。 * data 中的最小值被视为第 0 个百分位,最大值被视为第 100 个百分位。落在 m 个排序数据点的第 i *个以下的总体部分被计算为(i - 1) / (m - 1)。给定 11 个 samples 值,该方法对它们进行排序并分配以下百分位数: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 版的新Function。

Exceptions

定义了一个 exception:

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

NormalDist objects

NormalDist是用于创建和处理random variable的正态分布的工具。它是一类,将数据测量的均值和标准差视为单个实体。

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

  • 类别 statistics. NormalDist(* mu = 0.0 sigma = 1.0 *)

如果* sigma *为负数,则加StatisticsError

  • mean

  • median

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

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

  • variance

    • 正态分布的variance的只读属性。等于标准偏差的平方。
  • 类方法 from_samples(数据)

    • 使用fmean()stdev()从* data 估计的 mu sigma *参数构成正态分布实例。
  • data 可以是任何iterable,并且应包含可以转换为float类型的值。如果 data *不包含至少两个元素,请加StatisticsError,因为估计中心值至少需要一点,而估计散度则需要至少两点。
  • samples(* n **,* seed = None *)
    • 为给定的平均值和标准偏差生成* n *个随机 samples。返回list个(共float个)值。

如果给定* seed *,则创建基础随机数生成器的新实例。即使在多线程环境中,这对于创建可重现的结果也很有用。

  • pdf(* x *)
    • 使用概率密度函数(pdf)计算随机变量* X 接近给定值 x 的相对可能性。从 math 上讲,它是比率P(x <= X < x+dx) / dx的极限,因为 dx *接近零。

相对可能性被计算为 samples 在狭窄范围内出现的概率除以范围的宽度(因此,单词“密度”)。由于可能性是相对于其他点的,因此其值可以大于 1.0.

查找随机变量* X 的值 x ,以使该变量小于或等于该值的概率等于给定的概率 p *。

  • overlap(其他)

  • 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 版的新Function。

NormalDist 示例和食谱

NormalDist可以轻松解决经典的概率问题。

例如,假设SAT 考试的历史数据显示分数的正态分布是平均值为 1060,标准偏差为 195,则在四舍五入到最接近的整数后,确定测试分数在 1100 和 1200 之间的学生所占的百分比:

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

找到 SAT 分数的quartilesdeciles

>>> 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可以为蒙特卡洛模拟生成 Importingsamples:

>>> 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]

当 samples 量较大且成功试验的概率接近 50%时,可以使用正态分布来近似Binomial distributions

例如,一个开源会议有 750 名与会者和两个可容纳 500 人的会议室。这里有一个关于 Python 的 Topic,另一个是关于 Ruby 的 Topic。在以前的会议中,有 65%的与会者更喜欢听 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

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

维基百科上有一个一个朴素的贝叶斯分类器的好例子。面临的挑战是根据对身高,体重和足部大小等正态分布 Feature 的测量来预测一个人的性别。

我们获得了一个训练数据集,其中包含八个人的测量值。假设测量值呈正态分布,因此我们用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])

接下来,我们遇到一个新人物,其 Feature 度量已知,但性别未知:

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

从 50%的prior probability是男性或女性开始,我们将后验计算为给定性别下 Feature 量测可能性的乘积的先前时间:

>>> 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))

finally预测将到达最大的后验。这称为最大后验或 MAP:

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