NormalDist对象示例和用法
NormalDist适合用来解决经典概率问题。
举例来说,如果 SAT 考试的历史数据 显示分数呈平均值为 1060 且标准差为 195 的正态分布,则可以确定考试分数处于 1100 和 1200 之间的学生的百分比舍入到最接近的整数应为:
求 SAT 分数的 四分位 和 十分位:
为了估算一个不易解析的模型分布,NormalDist 可以生成用于蒙特卡洛模拟(Monte Carlo simulation)的输入样本:
当样本量较大且成功试验的概率接近50%时,正态分布可用于近似二项式分布。 例如,一次开源会议有 750 名与会者和两个可分别容纳 500 人的会议厅。会上有一场关于 Python 的演讲和一场关于 Ruby 的演讲。在往届会议中,65% 的与会者更愿意去听关于 Python 的演讲。假定人群的偏好没有发生改变,那么 Python 演讲的会议厅不超出其容量上限的可能性是多少? 代码(文本代码附录1)和运行结果如下:
在机器学习问题中也经常会出现正态分布。 维基百科有一个朴素贝叶斯分类器(Naive Bayesian Classifier)的好例子。通过测量正常分布的特征(包括身高、体重和脚大小)来挑战性地预测一个人的性别。 我们得到了由八个人的测量值组成的训练数据集。假定这些测量值是正态分布的,因此我们用 NormalDist 来总结数据: 接下来,我们遇到一个特征测量值已知但性别未知的新人: 从是男是女各 50% 的 先验概率 出发,我们通过将该先验概率乘以给定性别的特征度量值的可能性累积值来计算后验概率: 最终预测值应为最大后验概率值。这种算法被称为 maximum a posteriori 或 MAP(完整代码附录2):
总论
该模块提供了用于实数 (Real-valued) 数据的数理统计的函数。
此模块并不能与诸如 NumPy , SciPy 等第三方库,或者诸如 Minitab , SAS , Matlab 等专有全功能专业统计师软件包相媲美。此模块处于绘制图表和科学计算器的水平。
除非明确指出,否则这些函数仅支持int、float、Decimal和Fraction。当前不支持其他类型的运算(无论是否在数字塔中)。混合类型的集合也是未定义的,并且依赖于实现。如果输入数据由混合类型组成,则可以使用map()确保集合元素的数据类型一致,例如:map(float,input_data) 。
一些数据集使用NaN(不是数字)值来表示缺失的数据。由于NaN具有不寻常的比较语义,它们会在统计函数中产生令人惊讶的或未定义的行为,这些统计函数对数据进行排序或统计出现次数。受影响的函数有median()、median_low()、median_high()、median_grouped()、mode()、multimode()和quantiles()。在调用这些函数之前,应排除NaN值(文本附录3):
这些函数用于计算一个总体或样本的平均值或者典型值。
mean() | 数据的算术平均数(“平均数”)。 |
fmean() | 快速浮点算术平均值,可选加权。 |
geometric_mean() | 数据的几何平均数 |
harmonic_mean() | 数据的调和均值 |
median() | 数据的中位数(中间值) |
median_low() | 数据的低中位数 |
median_high() | 数据的高中位数 |
median_grouped() | 分组数据的中位数,即第50个百分点。 |
mode() | 离散的或标称的数据的单个众数(出现最多的值)。 |
multimode() | 离散的或标称的数据的众数(出现最多的值)列表。 |
quantiles() | 将数据以相等的概率分为多个间隔。 |
这些函数用于计算总体或样本与典型值或平均值的偏离程度。
pstdev() | 数据的总体标准差 |
pvariance() | 数据的总体方差 |
stdev() | 数据的样本标准差 |
variance() | 数据的样本方差 |
这些函数计算两个输入之间关系的统计值。
covariance() | 两个序列的样本协方差。 |
correlation() | 两个序列的皮尔逊相关系数。 |
linear_regression() | 简单线性回归的斜率和截距。 |
附录1:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
from statistics import * #导入统计模块所有东西
n = 750 # 样本数量p = 0.65 # 参加Python的概率q = 1.0 - p # 参加Ruby的概率k = 500 # 房间容量
# 使用累积概率正态分布的近似from math import sqrt #导入math模块的sqrt(平方根)#μ=n*p,样本数量×概率#σ=sqrt(n*p*q) 样本数量与两个概率的乘积后开方,高级数学推导出来的计算公式#以μ和σ构建正态分布对象,调用该对象的积累概率分布方法,+0.5保证边界计入统计#保留小数点后4位rst1 = round(NormalDist(mu=n*p, sigma=sqrt(n*p*q)).cdf(k + 0.5), 4)print("累积概率:",rst1)
# 使用累积二项分布from math import comb, fsum #导入二项式系数和浮点数累加函数#二项式的每一项两个变量的指数之和等于n:r+(n-r)=n,r=0到k。#math.comb(n,r)是n次二项式的第r项系数(从0开始)rst2 = round(fsum(comb(n, r) * p**r * q**(n-r) for r in range(k+1)), 4)print("累积二项:", rst2)
# 使用模拟进行近似from random import seed, choices #导入随机数模块的seed和choices函数seed(8675309) #投种子def trial(): #一次会议,返回选择Python的人数 #choices(选择序列,权重序列,选择次数) return choices(('Python', 'Ruby'), (p, q), k=n).count('Python')#如果参加Python的人数没超过500,成功,统计算1,否则算0 #计算10000次的平均值 rst3=mean(trial() <= k for i in range(10_000)) print("算法模拟:", rst3)
附录2:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
from statistics import *
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 # heightwt = 130 # weightfs = 8 # foot size
prior_male = 0.5prior_female = 0.5posterior_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)) print('male' if posterior_male > posterior_female else 'female')
附录3:
>>> from statistics import median
>>> from math import isnan
>>> from itertools import filterfalse
>>> data = [20.7, float('NaN'),19.2, 18.3, float('NaN'), 14.4]
>>> sorted(data) # This has surprising behavior
[20.7, nan, 14.4, 18.3, 19.2, nan]
>>> median(data) # This result is unexpected
16.35
>>> sum(map(isnan, data)) # Number of missing values
2
>>> clean = list(filterfalse(isnan, data)) # Strip NaN values
>>> clean
[20.7, 19.2, 18.3, 14.4]
>>> sorted(clean) # Sorting now works as expected
[14.4, 18.3, 19.2, 20.7]
>>> median(clean) # This result is now well defined
18.75