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实现m3u8格式转换为mp4视频格式
Feb 28 Python
Python3利用Dlib19.7实现摄像头人脸识别的方法
May 11 Python
pandas.loc 选取指定列进行操作的实例
May 18 Python
python 将md5转为16字节的方法
May 29 Python
python 读取目录下csv文件并绘制曲线v111的方法
Jul 06 Python
python把数组中的数字每行打印3个并保存在文档中的方法
Jul 17 Python
python 3.6.2 安装配置方法图文教程
Sep 18 Python
GitHub 热门:Python 算法大全,Star 超过 2 万
Apr 29 Python
django连接oracle时setting 配置方法
Aug 29 Python
python实现二分类和多分类的ROC曲线教程
Jun 15 Python
Python实现简单的猜单词
Jun 15 Python
Python Pandas 删除列操作
Mar 16 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备份数据库生成SQL文件并下载的函数代码
2012/02/05 PHP
PHP CURL CURLOPT参数说明(curl_setopt)
2013/09/30 PHP
PHP基于PDO实现的SQLite操作类【包含增删改查及事务等操作】
2017/06/21 PHP
laravel5.6 框架操作数据 Eloquent ORM用法示例
2020/01/26 PHP
window.open的功能全解析
2006/10/10 Javascript
jQuery.get、jQuery.getJSON、jQuery.post无法返回JSON问题的解决方法
2011/07/28 Javascript
JS中获取数据库中的值的方法
2013/07/14 Javascript
JQuery中extend使用介绍
2014/03/13 Javascript
javascript搜索框点击文字消失失焦时文本出现
2014/09/18 Javascript
jQuery实现在列表的首行添加数据
2015/05/19 Javascript
JavaScript实现网站访问次数统计代码
2015/08/12 Javascript
Bootstrap响应式侧边栏改进版
2016/09/17 Javascript
表单input项使用label同时引用Bootstrap库导致input点击效果区增大问题
2016/10/11 Javascript
js实现百度登录框鼠标拖拽效果
2017/03/07 Javascript
详解js删除数组中的指定元素
2018/10/31 Javascript
Angular封装表单控件及思想总结
2019/12/11 Javascript
JavaScript实现4位随机验证码的生成
2021/01/28 Javascript
[54:53]完美世界DOTA2联赛PWL S2 GXR vs PXG 第二场 11.18
2020/11/18 DOTA
python调用cmd命令行制作刷博器
2014/01/13 Python
Django返回json数据用法示例
2016/09/18 Python
django基础学习之send_mail功能
2019/08/07 Python
Python3实现mysql连接和数据框的形成(实例代码)
2020/01/17 Python
Jupyter Notebook的连接密码 token查询方式
2020/04/21 Python
Pytorch转keras的有效方法,以FlowNet为例讲解
2020/05/26 Python
Pandas中DataFrame交换列顺序的方法实现
2020/12/14 Python
基于DOM+CSS3实现OrgChart组织结构图插件
2016/03/02 HTML / CSS
HTML5使用ApplicationCache接口实现离线缓存技术解决离线难题
2012/12/13 HTML / CSS
Kiwi.com中国:找到特价机票并发现新目的地
2019/10/27 全球购物
年度献血先进个人事迹材料
2014/02/14 职场文书
银行求职信怎么写
2014/05/26 职场文书
小学校本培训方案
2014/06/06 职场文书
2015年禁毒宣传活动总结
2015/03/25 职场文书
MySQL CHAR和VARCHAR该如何选择
2021/05/31 MySQL
Python NumPy灰度图像的压缩原理讲解
2021/08/04 Python
详解jQuery的核心函数和事件处理
2022/02/18 jQuery
Redis如何使用乐观锁(CAS)保证数据一致性
2022/03/25 Redis