• statistics —- 数学统计函数
    • 中心位置的平均值和度量
    • 传播措施
    • 函数细节
    • 异常
    • NormalDist 对象
      • NormalDist Examples and Recipes

    statistics —- 数学统计函数

    3.4 新版功能.

    源代码:Lib/statistics.py


    该模块提供了用于计算数字 (Real-valued) 数据的数理统计量的函数。

    此模块并不是诸如 NumPy , SciPy 等第三方库或者诸如 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

    一些用法示例:

    1. >>> mean([1, 2, 3, 4, 4])
    2. 2.8
    3. >>> mean([-1.0, 2.5, 3.25, 5.75])
    4. 2.625
    5.  
    6. >>> from fractions import Fraction as F
    7. >>> mean([F(3, 7), F(1, 21), F(5, 3), F(1, 3)])
    8. Fraction(13, 21)
    9.  
    10. >>> from decimal import Decimal as D
    11. >>> mean([D("0.5"), D("0.75"), D("0.625"), D("0.375")])
    12. Decimal('0.5625')

    注解

    均值非常受异常值的影响并且这不是中心位置的可靠估计:均值不一定是数据点的典型示例。如需要更可靠的的估计,请参考 median()mode()

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

    • statistics.fmean(data)
    • 将浮点数转换成 data 并且计算算术平均数。

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

    1. >>> fmean([3.5, 4.0, 5.25])
    2. 4.25

    3.8 新版功能.

    • statistics.geometricmean(_data)
    • 将浮点数转换成 data 并且计算几何平均数。

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

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

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

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

    3.8 新版功能.

    • statistics.harmonicmean(_data)
    • 返回 data 调和均值,该参数可以是序列或包含实数值的可迭代对象。

    调和均值,也叫次相反均值,所有数据的倒数的算术平均数 mean() 的倒数。比如说,数据 abc 的调和均值等于 3/(1/a + 1/b + 1/c) 。如果其中一个值为零,结果为零。

    调和均值是一种均值类型,是数据中心位置的度量。它通常适合于求比率和比例的平均值,比如速率。

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

    1. >>> harmonic_mean([40, 60])
    2. 48.0

    假设一名投资者在三家公司各购买了等价值的股票,以 2.5, 3 , 10 的 P/E (价格/收益) 率。投资者投资组合的平均市盈率是多少?

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

    如果 data 为空或者 任何一个元素的值小于零,会引发 StatisticsError

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

    3.6 新版功能.

    • statistics.median(data)
    • 使用普通的“取中间两数平均值”方法返回数值数据的中位数(中间值)。 如果 data 为空,则将引发 StatisticsErrordata 可以是序列或可迭代对象。

    中位数是衡量中间位置的可靠方式,并且较少受到极端值的影响。 当数据点的总数为奇数时,将返回中间数据点:

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

    当数据点的总数为偶数时,中位数将通过对两个中间值求平均进行插值得出:

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

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

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

    • statistics.medianlow(_data)
    • 返回数值数据的低中位数。 如果 data 为空则将引发 StatisticsErrordata 可以是序列或可迭代对象。

    低中位数一定是数据集的成员。 当数据点总数为奇数时,将返回中间值。 当其为偶数时,将返回两个中间值中较小的那个。

    1. >>> median_low([1, 3, 5])
    2. 3
    3. >>> median_low([1, 3, 5, 7])
    4. 3

    当你的数据是离散的,并且你希望中位数是一个实际数据点而非插值结果时可以使用低中位数。

    • statistics.medianhigh(_data)
    • 返回数据的高中位数。 如果 data 为空则将引发 StatisticsErrordata 可以是序列或可迭代对象。

    高中位数一定是数据集的成员。 当数据点总数为奇数时,将返回中间值。 当其为偶数时,将返回两个中间值中较大的那个。

    1. >>> median_high([1, 3, 5])
    2. 3
    3. >>> median_high([1, 3, 5, 7])
    4. 5

    当你的数据是离散的,并且你希望中位数是一个实际数据点而非插值结果时可以使用高中位数。

    • statistics.mediangrouped(_data, interval=1)
    • 返回分组的连续数据的中位数,根据第 50 个百分点的位置使用插值来计算。 如果 data 为空则将引发 StatisticsErrordata 可以是序列或可迭代对象。
    1. >>> median_grouped([52, 52, 53, 54])
    2. 52.5

    在下面的示例中,数据已经过舍入,这样每个值都代表数据分类的中间点,例如 1 是 0.5—1.5 分类的中间点,2 是 1.5—2.5 分类的中间点,3 是 2.5—3.5 的中间点等待。 根据给定的数据,中间值应落在 3.5—4.5 分类之内,并可使用插值法来进行估算:

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

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

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

    此函数不会检查数据点之间是否至少相隔 interval 的距离。

    CPython implementation detail: 在某些情况下,median_grouped() 可以会将数据点强制转换为浮点数。 此行为在未来有可能会发生改变。

    参见

    • "Statistics for the Behavioral Sciences", Frederick J Gravetter andLarry B Wallnau (8th Edition).

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

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

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

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

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

    此模式的独特之处在于它是这个包中唯一还可应用于标称(非数字)数据的统计信息:

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

    在 3.8 版更改: 现在会通过返回所遇到的第一个模式来处理多模数据集。 之前它会在遇到超过一个的模式时引发 StatisticsError

    • statistics.multimode(data)
    • 返回最频繁出现的值的列表,并按它们在 data 中首次出现的位置排序。 如果存在多种模式则将返回一个以上的模式,或者如果 data 为空则将返回空列表:
    1. >>> multimode('aabbbbccddddeeffffgg')
    2. ['b', 'd', 'f']
    3. >>> multimode('')
    4. []

    3.8 新版功能.

    • statistics.pstdev(data, mu=None)
    • 返回总体标准差(总体方差的平方根)。 请参阅 pvariance() 了解参数和其他细节。
    1. >>> pstdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
    2. 0.986893273527251
    • statistics.pvariance(data, mu=None)
    • 返回非空序列或包含实数值的可迭代对象 data 的总体方差。 方差或称相对于均值的二阶距,是对数据变化幅度(延展度或分散度)的度量。 方差值较大表明数据的散布范围较大;方差值较小表明它紧密聚集于均值附近。

    如果给出了可选的第二个参数 mu,它通常是 data 的均值。 它也可以被用来计算相对于一个非均值点的二阶距。 如果该参数省略或为 None (默认值),则会自动进行算术均值的计算。

    使用此函数可根据所有数值来计算方差。 要根据一个样本来估算方差,通常 variance() 函数是更好的选择。

    如果 data 为空则会引发 StatisticsError

    示例:

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

    如果你已经计算过数据的平均值,你可以将其作为可选的第二个参数 mu 传入以避免重复计算:

    1. >>> mu = mean(data)
    2. >>> pvariance(data, mu)
    3. 1.25

    同样也支持使用 Decimal 和 Fraction 值:

    1. >>> from decimal import Decimal as D
    2. >>> pvariance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
    3. Decimal('24.815')
    4.  
    5. >>> from fractions import Fraction as F
    6. >>> pvariance([F(1, 4), F(5, 4), F(1, 2)])
    7. Fraction(13, 72)

    注解

    当调用时附带完整的总体数据时,这将给出总体方差 σ²。 而当调用时只附带一个样本时,这将给出偏置样本方差 s²,也被称为带有 N 个自由度的方差。

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

    • statistics.stdev(data, xbar=None)
    • 返回样本标准差(样本方差的平方根)。 请参阅 variance() 了解参数和其他细节。
    1. >>> stdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])
    2. 1.0810874155219827
    • statistics.variance(data, xbar=None)
    • 返回包含至少两个实数值的可迭代对象 data 的样本方差。 方差或称相对于均值的二阶矩,是对数据变化幅度(延展度或分散度)的度量。 方差值较大表明数据的散布范围较大;方差值较小表明它紧密聚集于均值附近。

    如果给出了可选的第二个参数 xbar,它应当是 data 的均值。 如果该参数省略或为 None (默认值),则会自动进行均值的计算。

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

    如果 data 包含的值少于两个则会引发 StatisticsError

    示例:

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

    如果你已经计算过数据的平均值,你可以将其作为可选的第二个参数 xbar 传入以避免重复计算:

    1. >>> m = mean(data)
    2. >>> variance(data, m)
    3. 1.3720238095238095

    此函数不会试图检查你所传入的 xbar 是否为真实的平均值。 使用任意值作为 xbar 可能导致无效或不可能的结果。

    同样也支持使用 Decimal 和 Fraction 值:

    1. >>> from decimal import Decimal as D
    2. >>> variance([D("27.5"), D("30.25"), D("30.25"), D("34.5"), D("41.75")])
    3. Decimal('31.01875')
    4.  
    5. >>> from fractions import Fraction as F
    6. >>> variance([F(1, 6), F(1, 2), F(5, 3)])
    7. Fraction(67, 108)

    注解

    这是附带贝塞尔校正的样本方差 s²,也称为具有 N-1 自由度的方差。 假设数据点具有代表性(即为独立且均匀的分布),则结果应当是对总体方差的无偏估计。

    如果你通过某种方式知道了真实的总体平均值 μ 则应当调用 pvariance() 函数并将该值作为 mu 形参传入以得到一个样本的方差。

    • 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

    method 用于计算分位值,它会由于 data 是包含还是排除总体的最低和最高可能值而有所不同。

    默认 method 是 “唯一的” 并且被用于在总体中数据采样这样可以有比样本中找到的更多的极端值。落在 m 个排序数据点的第 i-th 个以下的总体部分被计算为 i / (m + 1) 。给定九个样本值,方法排序它们并且分配一下的百分位: 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90% 。

    method 设为 "inclusive" 可用于描述总体数据或已明确知道包含有总体数据中最极端值的样本。 data 中的最小值会被作为第 0 个百分位而最大值会被作为第 100 个百分位。 总体数据里处于 m 个已排序数据点中 第 i 个 以下的部分会以 (i - 1) / (m - 1) 来计算。 给定 11 个样本值,该方法会对它们进行排序并赋予以下百分位: 0%, 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90%, 100%。

    1. # Decile cut points for empirically sampled data
    2. >>> data = [105, 129, 87, 86, 111, 111, 89, 81, 108, 92, 110,
    3. ... 100, 75, 105, 103, 109, 76, 119, 99, 91, 103, 129,
    4. ... 106, 101, 84, 111, 74, 87, 86, 103, 103, 106, 86,
    5. ... 111, 75, 87, 102, 121, 111, 88, 89, 101, 106, 95,
    6. ... 103, 107, 101, 81, 109, 104]
    7. >>> [round(q, 1) for q in quantiles(data, n=10)]
    8. [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

    • 一个只读特征属性,表示特定正态分布的 模式)。

    • stdev

    • 一个只读特征属性,表示特定正态分布的 标准差。

    • variance

    • 一个只读特征属性,表示特定正态分布的 方差。 等于标准差的平方。

    • classmethod fromsamples(_data)

    • 传入使用 fmean()stdev() 基于 data 估算出的 musigma 形参创建一个正态分布实例。

    The data can be any iterable and should consist of valuesthat can be converted to type float. If data does notcontain at least two elements, raises StatisticsError because ittakes at least one point to estimate a central value and at least twopoints to estimate dispersion.

    • samples(n, *, seed=None)
    • Generates n random samples for a given mean and standard deviation.Returns a list of float values.

    If seed is given, creates a new instance of the underlying randomnumber generator. This is useful for creating reproducible results,even in a multi-threading context.

    • pdf(x)
    • Using a probability density function (pdf), computethe relative likelihood that a random variable X will be near thegiven value x. Mathematically, it is the limit of the ratio P(x <=X < x+dx) / dx as dx approaches zero.

    The relative likelihood is computed as the probability of a sampleoccurring in a narrow range divided by the width of the range (hencethe word "density"). Since the likelihood is relative to other points,its value can be greater than 1.0.

    • cdf(x)
    • Using a cumulative distribution function (cdf),compute the probability that a random variable X will be less than orequal to x. Mathematically, it is written P(X <= x).

    • invcdf(_p)

    • Compute the inverse cumulative distribution function, also known as thequantile functionor the percent-pointfunction. Mathematically, it is written x : P(X <= x) = p.

    Finds the value x of the random variable X such that theprobability of the variable being less than or equal to that valueequals the given probability p.

    • overlap(other)
    • Measures the agreement between two normal probability distributions.Returns a value between 0.0 and 1.0 giving the overlapping area forthe two probability density functions.

    • quantiles(n=4)

    • Divide the normal distribution into n continuous intervals withequal probability. Returns a list of (n - 1) cut points separatingthe intervals.

    Set n to 4 for quartiles (the default). Set n to 10 for deciles.Set n to 100 for percentiles which gives the 99 cuts points thatseparate the normal distribution into 100 equal sized groups.

    Instances of NormalDist support addition, subtraction,multiplication and division by a constant. These operationsare used for translation and scaling. For example:

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

    Dividing a constant by an instance of NormalDist is not supportedbecause the result wouldn't be normally distributed.

    Since normal distributions arise from additive effects of independentvariables, it is possible to add and subtract two independent normallydistributed random variablesrepresented as instances of NormalDist. For example:

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

    3.8 新版功能.

    NormalDist Examples and Recipes

    NormalDist readily solves classic probability problems.

    For example, given historical data for SAT exams showing that scoresare normally distributed with a mean of 1060 and a standard deviation of 192,determine the percentage of students with test scores between 1100 and1200, after rounding to the nearest whole number:

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

    Find the quartiles and deciles for the SAT scores:

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

    To estimate the distribution for a model than isn't easy to solveanalytically, NormalDist can generate input samples for a MonteCarlo simulation:

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

    Normal distributions commonly arise in machine learning problems.

    Wikipedia has a nice example of a Naive Bayesian Classifier.The challenge is to predict a person's gender from measurements of normallydistributed features including height, weight, and foot size.

    We're given a training dataset with measurements for eight people. Themeasurements are assumed to be normally distributed, so we summarize the datawith NormalDist:

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

    Next, we encounter a new person whose feature measurements are known but whosegender is unknown:

    1. >>> ht = 6.0 # height
    2. >>> wt = 130 # weight
    3. >>> fs = 8 # foot size

    Starting with a 50% prior probability of being male or female,we compute the posterior as the prior times the product of likelihoods for thefeature measurements given the gender:

    1. >>> prior_male = 0.5
    2. >>> prior_female = 0.5
    3. >>> posterior_male = (prior_male * height_male.pdf(ht) *
    4. ... weight_male.pdf(wt) * foot_size_male.pdf(fs))
    5.  
    6. >>> posterior_female = (prior_female * height_female.pdf(ht) *
    7. ... weight_female.pdf(wt) * foot_size_female.pdf(fs))

    The final prediction goes to the largest posterior. This is known as themaximum a posteriori or MAP:

    1. >>> 'male' if posterior_male > posterior_female else 'female'
    2. 'female'