python 计算概率密度、累计分布、逆函数的例子


Posted in Python onFebruary 25, 2020

计算概率分布的相关参数时,一般使用 scipy 包,常用的函数包括以下几个:

pdf:连续随机分布的概率密度函数

pmf:离散随机分布的概率密度函数

cdf:累计分布函数

百分位函数(累计分布函数的逆函数)

生存函数的逆函数(1 - cdf 的逆函数)

函数里面不仅能跟一个数据,还能跟一个数组。下面用正态分布举例说明:

>>> import scipy.stats as st

>>> st.norm.cdf(0) # 标准正态分布在 0 处的累计分布概率值
0.5

>>> st.norm.cdf([-1, 0, 1])# 标准正态分布分别在 -1, 0, 1 处的累计分布概率值
array([0.15865525, 0.5, 0.84134475])

>>> st.norm.pdf(0) # 标准正态分布在 0 处的概率密度值
0.3989422804014327

>>> st.norm.ppf(0.975)# 标准正态分布在 0.975 处的逆函数值
1.959963984540054

>>> st.norm.lsf(0.975)# 标准正态分布在 0.025 处的生存函数的逆函数值
1.959963984540054

对于非标准正态分布,通过更改参数 loc 与 scale 来改变均值与标准差:

>>> st.norm.cdf(0, loc=2, scale=1) # 均值为 2,标准差为 1 的正态分布在 0 处的累计分布概率值
0.022750131948179195

对于其他随机分布,可能更改的参数不一样,具体需要查官方文档。下面我们举一些常用分布的例子:

>>> st.binom.pmf(4, n=100, p=0.05) # 参数值 n=100, p=0.05 的二项分布在 4 处的概率密度值
0.17814264156968956

>>> st.geom.pmf(4, p=0.05) # 参数值 p=0.05 的几何分布在 4 处的概率密度值
0.04286875

>>> st.poisson.pmf(2, mu=3) # 参数值 mu=3 的泊松分布在 2 处的概率密度值
0.22404180765538775

>>> st.chi2.ppf(0.95, df=10) # 自由度为 10 的卡方分布在 0.95 处的逆函数值
18.307038053275146

>>> st.t.ppf(0.975, df=10) # 自由度为 10 的 t 分布在 0.975 处的逆函数值
2.2281388519649385

>>> st.f.ppf(0.95, dfn=2, dfd=12) # 自由度为 2, 12 的 F 分布在 0.95 处的逆函数值
3.8852938346523933

补充拓展:给定概率密度,生成随机数 python实现

实现的方法可以不止一种:

rejection sampling

invert the cdf

Metropolis Algorithm (MCMC)

本篇介绍根据累积概率分布函数的逆函数(2:invert the CDF)生成的方法。

自己的理解不一定正确,有错误望指正。

目标:

已知 y=pdf(x),现想由给定的pdf, 生成对应分布的x

PDF是概率分布函数,对其积分或者求和可以得到CDF(累积概率分布函数),PDF积分或求和的结果始终为1

步骤(具体解释后面会说):

1、根据pdf得到cdf

2、由cdf得到inverse of the cdf

3、对于给定的均匀分布[0,1),带入inverse cdf,得到的结果即是我们需要的x

求cdf逆函数的具体方法:

对于上面的第二步,可以分成两类:

1、当CDF的逆函数好求时,直接根据公式求取,

2、反之当CDF的逆函数不好求时,用数值模拟方法

自己的理解:为什么需要根据cdf的逆去获得x?

原因一:

因为cdf是单调函数因此一定存在逆函数(cdf是s型函数,而pdf则不一定,例如正态分布,不单调,对于给定的y,可能存在两个对应的x,就不可逆)

原因二:

这仅是我自己的直观理解,根据下图所示(左上为pdf,右上为cdf)

python 计算概率密度、累计分布、逆函数的例子

由步骤3可知,我们首先生成[0,1)的均匀随机数,此随机数作为cdf的y,去映射到cdf的x(若用cdf的逆函数表示则是由x映射到y),可以参考上图的右上,既然cdf的y是均匀随机的,那么对于cdf中同样范围的x,斜率大的部分将会有更大的机会被映射,因为对应的y范围更大(而y是随即均匀分布的),那么,cdf的斜率也就等同于pdf的值,这正好符合若x的pdf较大,那么有更大的概率出现(即重复很多次后,该x会出现的次数最多)

代码实现——方法一,公式法

import numpy as np
import math
import random
import matplotlib.pyplot as plt
import collections

count_dict = dict()
bin_count = 20

def inverseCDF():
 """
 return the x value in PDF
 """
 uniform_random = random.random()
 return inverse_cdf(uniform_random)
 

def pdf(x):
 return 2 * x
 
# cdf = x^2, 其逆函数很好求,因此直接用公式法
def inverse_cdf(x):
 return math.sqrt(x)


def draw_pdf(D):
	global bin_count
 D = collections.OrderedDict(sorted(D.items()))
 plt.bar(range(len(D)), list(D.values()), align='center')
 # 因为映射bin的时候采用的floor操作,因此加上0.5
 value_list = [(key + 0.5) / bin_count for key in D.keys()]
 plt.xticks(range(len(D)), value_list)
 plt.xlabel('x', fontsize=5)
 plt.ylabel('counts', fontsize=5)
 plt.title('counting bits')
 plt.show()

for i in range(90000):
 x = inverseCDF()
 # 用bin去映射,否则不好操作
 bin = math.floor(x * bin_count) # type(bin): int
 count_dict[bin] = count_dict.get(bin, 0) + 1

draw_pdf(count_dict)

结果:

python 计算概率密度、累计分布、逆函数的例子

代码实现——方法二,数值法

数值模拟cdf的关键是创建lookup table,

table的size越大则结果越真实(即区间划分的个数)

import numpy as np
import math
import random
import matplotlib.pyplot as plt
import collections

lookup_table_size = 40
CDFlookup_table = np.zeros((lookup_table_size))

count_dict = dict()
bin_count = 20

def inverse_cdf_numerically(y):
 global lookup_table_size
 global CDFlookup_table
 value = 0.0
 for i in range(lookup_table_size):
  x = i * 1.0 / (lookup_table_size - 1)
  value += pdf2(x)
  CDFlookup_table[i] = value
 CDFlookup_table /= value # normalize the cdf

 if y < CDFlookup_table[0]: 
  t = y / CDFlookup_table[0]
  return t / lookup_table_size
 index = -1
 for j in range(lookup_table_size):
  if CDFlookup_table[j] >= y:
   index = j
   break
 # linear interpolation
 t = (y - CDFlookup_table[index - 1]) / \
  (CDFlookup_table[index] - CDFlookup_table[index - 1])
 fractional_index = index + t # 因为index从0开始,所以不是 (index-1)+t
 return fractional_index / lookup_table_size


def inverseCDF():
 """
 return the x value in PDF
 """
 uniform_random = random.random()
 return inverse_cdf_numerically(uniform_random)


def pdf2(x):
 return (x * x * x - 10.0 * x * x + 5.0 * x + 11.0) / (10.417)

def draw_pdf(D):
 global bin_count
 D = collections.OrderedDict(sorted(D.items()))
 plt.bar(range(len(D)), list(D.values()), align='center')
 value_list = [(key + 0.5) / bin_count for key in D.keys()]
 plt.xticks(range(len(D)), value_list)
 plt.xlabel('x', fontsize=5)
 plt.ylabel('counts', fontsize=5)
 plt.title('counting bits')
 plt.show()


for i in range(90000):
 x = inverseCDF()
 bin = math.floor(x * bin_count) # type(bin): int
 count_dict[bin] = count_dict.get(bin, 0) + 1

draw_pdf(count_dict)

真实函数与模拟结果

python 计算概率密度、累计分布、逆函数的例子

扩展:生成伯努利、正太分布

import numpy as np
import matplotlib.pyplot as plt
"""
reference:
https://blog.demofox.org/2017/07/25/counting-bits-the-normal-distribution/
"""


def plot_bar_x():
 # this is for plotting purpose
 index = np.arange(counting.shape[0])
 plt.bar(index, counting)
 plt.xlabel('x', fontsize=5)
 plt.ylabel('counts', fontsize=5)
 plt.title('counting bits')
 plt.show()


# if dice_side=2, is binomial distribution
# if dice_side>2 , is multinomial distribution
dice_side = 2
# if N becomes larger, then multinomial distribution will more like normal distribution
N = 100

counting = np.zeros(((dice_side - 1) * N + 1))

for i in range(30000):
 sum = 0
 for j in range(N):
  dice_result = np.random.randint(0, dice_side)
  sum += dice_result

 counting[sum] += 1

# normalization
counting /= np.sum(counting)
plot_bar_x()

以上这篇python 计算概率密度、累计分布、逆函数的例子就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python列表计数及插入实例
Dec 17 Python
Python实现爬取知乎神回复简单爬虫代码分享
Jan 04 Python
详解Python验证码识别
Jan 25 Python
python爬虫实现教程转换成 PDF 电子书
Feb 19 Python
Python 含参构造函数实例详解
May 25 Python
python中pylint使用方法(pylint代码检查)
Apr 06 Python
Python requests库用法实例详解
Aug 14 Python
django admin 自定义替换change页面模板的方法
Aug 23 Python
Python安装whl文件过程图解
Feb 18 Python
python的dict判断key是否存在的方法
Dec 09 Python
python中pdb模块实例用法
Jan 15 Python
Python爬虫实战之爬取京东商品数据并实实现数据可视化
Jun 07 Python
python GUI库图形界面开发之PyQt5窗口背景与不规则窗口实例
Feb 25 #Python
python统计函数库scipy.stats的用法解析
Feb 25 #Python
Python Websocket服务端通信的使用示例
Feb 25 #Python
Python GUI库PyQt5样式QSS子控件介绍
Feb 25 #Python
浅谈python累加求和+奇偶数求和_break_continue
Feb 25 #Python
Python GUI库PyQt5图形和特效样式QSS介绍
Feb 25 #Python
python 伯努利分布详解
Feb 25 #Python
You might like
小文件php+SQLite存储方案
2010/09/04 PHP
PHP 函数执行效率的小比较
2010/10/17 PHP
分享下php5类中三种数据类型的区别
2015/01/26 PHP
WordPress中注册菜单与调用菜单的方法详解
2015/12/18 PHP
php实现留言板功能(会话控制)
2017/05/23 PHP
Dojo 学习笔记入门篇 First Dojo Example
2009/11/15 Javascript
20个最新的jQuery插件
2012/01/13 Javascript
js和jquery使按钮失效为不可用状态的方法
2014/01/26 Javascript
js+css实现导航效果实例
2015/02/10 Javascript
jquery+css实现绚丽的横向二级下拉菜单-附源码下载
2015/08/23 Javascript
原生js获取iframe中dom元素--父子页面相互获取对方dom元素的方法
2016/08/05 Javascript
轻松掌握JavaScript状态模式
2016/09/07 Javascript
jsTree使用记录实例
2016/12/01 Javascript
jQuery Validate插件自定义验证规则的方法
2016/12/27 Javascript
js 判断数据类型的几种方法
2017/01/13 Javascript
JavaScript+Html5实现按钮复制文字到剪切板功能(手机网页兼容)
2017/03/30 Javascript
p5.js实现斐波那契螺旋的示例代码
2018/03/22 Javascript
JS高阶函数原理与用法实例分析
2019/01/15 Javascript
在Node.js下运用MQTT协议实现即时通讯及离线推送的方法
2019/01/24 Javascript
微信公众平台 客服接口发消息的实现代码(Java接口开发)
2019/04/17 Javascript
JS中队列和双端队列实现及应用详解
2020/09/29 Javascript
Python实现注册登录系统
2017/08/08 Python
高质量Python代码编写的5个优化技巧
2017/11/16 Python
利用pyshp包给shapefile文件添加字段的实例
2019/12/06 Python
windows python3安装Jupyter Notebooks教程
2020/04/13 Python
python 写一个文件分发小程序
2020/12/05 Python
Python Socket多线程并发原理及实现
2020/12/11 Python
python switch 实现多分支选择功能
2020/12/21 Python
推荐10个CSS3 制作的创意下拉菜单效果
2014/02/11 HTML / CSS
CSS3 边框效果
2019/11/04 HTML / CSS
利用HTML5的新特点实现图片文件异步上传
2014/05/29 HTML / CSS
公司成立感言
2014/01/11 职场文书
人事助理自荐信
2014/02/02 职场文书
党的群众路线教育实践活动学习心得体会
2014/03/03 职场文书
公司投资建议书
2014/05/16 职场文书
企业战略合作意向书
2015/05/08 职场文书