代码源自:

https://github.com/PacktPublishing/Bayesian-Analysis-with-Python

内容接前文:

python语言绘图:绘制贝叶斯方法中最大后验密度(Highest Posterior Density, HPD)区间图的近似计算

===========================================================

前文主要讨论的是对于单峰分布的概率分布求近似的HPD,但是对于双峰分布求解HPD并不是很好,如下图(前文内容中的图):

==============================================================

我们求解的近似HPD中间有一个概率密度很低的区间,当然如果HPD可以不是一个连续区间的话我们可以有更好的求解方法呢,下面给出解法:

from __future__ import division
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats
import seaborn as sns
palette = 'muted'
sns.set_palette(palette); sns.set_color_codes(palette) np.random.seed(1)
gauss_a = stats.norm.rvs(loc=4, scale=0.9, size=3000)
gauss_b = stats.norm.rvs(loc=-2, scale=1, size=2000)
mix_norm = np.concatenate((gauss_a, gauss_b)) import numpy as np
import scipy.stats.kde as kde def hpd_grid(sample, alpha=0.05, roundto=2):
"""Calculate highest posterior density (HPD) of array for given alpha.
The HPD is the minimum width Bayesian credible interval (BCI).
The function works for multimodal distributions, returning more than one mode Parameters
---------- sample : Numpy array or python list
An array containing MCMC samples
alpha : float
Desired probability of type I error (defaults to 0.05)
roundto: integer
Number of digits after the decimal point for the results Returns
----------
hpd: array with the lower """
sample = np.asarray(sample)
sample = sample[~np.isnan(sample)]
# get upper and lower bounds
l = np.min(sample)
u = np.max(sample)
density = kde.gaussian_kde(sample)
x = np.linspace(l, u, 2000)
y = density.evaluate(x)
# y = density.evaluate(x, l, u) waitting for PR to be accepted
xy_zipped = zip(x, y / np.sum(y))
xy = sorted(xy_zipped, key=lambda x: x[1], reverse=True)
xy_cum_sum = 0
hdv = []
for val in xy:
xy_cum_sum += val[1]
hdv.append(val[0])
if xy_cum_sum >= (1 - alpha):
break
hdv.sort()
diff = (u - l) / 20 # differences of 5%
hpd = []
hpd.append(round(min(hdv), roundto))
for i in range(1, len(hdv)):
if hdv[i] - hdv[i - 1] >= diff:
hpd.append(round(hdv[i - 1], roundto))
hpd.append(round(hdv[i], roundto))
hpd.append(round(max(hdv), roundto))
ite = iter(hpd)
hpd = list(zip(ite, ite))
modes = []
for value in hpd:
x_hpd = x[(x > value[0]) & (x < value[1])]
y_hpd = y[(x > value[0]) & (x < value[1])]
modes.append(round(x_hpd[np.argmax(y_hpd)], roundto))
return hpd, x, y, modes import numpy as np
from scipy import stats
import matplotlib.pyplot as plt def plot_post(sample, alpha=0.05, show_mode=True, kde_plot=True, bins=50,
ROPE=None, comp_val=None, roundto=2):
"""Plot posterior and HPD Parameters
---------- sample : Numpy array or python list
An array containing MCMC samples
alpha : float
Desired probability of type I error (defaults to 0.05)
show_mode: Bool
If True the legend will show the mode(s) value(s), if false the mean(s)
will be displayed
kde_plot: Bool
If True the posterior will be displayed using a Kernel Density Estimation
otherwise an histogram will be used
bins: integer
Number of bins used for the histogram, only works when kde_plot is False
ROPE: list or numpy array
Lower and upper values of the Region Of Practical Equivalence
comp_val: float
Comparison value Returns
------- post_summary : dictionary
Containing values with several summary statistics """ post_summary = {'mean': 0, 'median': 0, 'mode': 0, 'alpha': 0, 'hpd_low': 0,
'hpd_high': 0, 'comp_val': 0, 'pc_gt_comp_val': 0, 'ROPE_low': 0,
'ROPE_high': 0, 'pc_in_ROPE': 0} post_summary['mean'] = round(np.mean(sample), roundto)
post_summary['median'] = round(np.median(sample), roundto)
post_summary['alpha'] = alpha # Compute the hpd, KDE and mode for the posterior
hpd, x, y, modes = hpd_grid(sample, alpha, roundto)
post_summary['hpd'] = hpd
post_summary['mode'] = modes ## Plot KDE.
if kde_plot:
plt.plot(x, y, color='k', lw=2)
## Plot histogram.
else:
plt.hist(sample, bins=bins, facecolor='b',
edgecolor='w') ## Display mode or mean:
if show_mode:
string = '{:g} ' * len(post_summary['mode'])
plt.plot(0, label='mode =' + string.format(*post_summary['mode']), alpha=0)
else:
plt.plot(0, label='mean = {:g}'.format(post_summary['mean']), alpha=0) ## Display the hpd.
hpd_label = ''
for value in hpd:
plt.plot(value, [0, 0], linewidth=10, color='b')
hpd_label = hpd_label + '{:g} {:g}\n'.format(round(value[0], roundto), round(value[1], roundto))
plt.plot(0, 0, linewidth=4, color='b', label='hpd {:g}%\n{}'.format((1 - alpha) * 100, hpd_label))
## Display the ROPE.
if ROPE is not None:
pc_in_ROPE = round(np.sum((sample > ROPE[0]) & (sample < ROPE[1])) / len(sample) * 100, roundto)
plt.plot(ROPE, [0, 0], linewidth=20, color='r', alpha=0.75)
plt.plot(0, 0, linewidth=4, color='r', label='{:g}% in ROPE'.format(pc_in_ROPE))
post_summary['ROPE_low'] = ROPE[0]
post_summary['ROPE_high'] = ROPE[1]
post_summary['pc_in_ROPE'] = pc_in_ROPE
## Display the comparison value.
if comp_val is not None:
pc_gt_comp_val = round(100 * np.sum(sample > comp_val) / len(sample), roundto)
pc_lt_comp_val = round(100 - pc_gt_comp_val, roundto)
plt.axvline(comp_val, ymax=.75, color='g', linewidth=4, alpha=0.75,
label='{:g}% < {:g} < {:g}%'.format(pc_lt_comp_val,
comp_val, pc_gt_comp_val))
post_summary['comp_val'] = comp_val
post_summary['pc_gt_comp_val'] = pc_gt_comp_val plt.legend(loc=0, framealpha=1)
frame = plt.gca()
frame.axes.get_yaxis().set_ticks([])
return post_summary plot_post(mix_norm, roundto=2, alpha=0.05)
plt.legend(loc=0, fontsize=16)
plt.xlabel(r"$\theta$", fontsize=14)
plt.savefig('B04958_01_09.png', dpi=300, figsize=(5.5, 5.5)) plt.show()

这个代码的代码量比较大,其实功能和前文的逻辑是一致的。

对HPD区间的求解核心代码:

def hpd_grid(sample, alpha=0.05, roundto=2):
"""Calculate highest posterior density (HPD) of array for given alpha.
The HPD is the minimum width Bayesian credible interval (BCI).
The function works for multimodal distributions, returning more than one mode Parameters
---------- sample : Numpy array or python list
An array containing MCMC samples
alpha : float
Desired probability of type I error (defaults to 0.05)
roundto: integer
Number of digits after the decimal point for the results Returns
----------
hpd: array with the lower """
sample = np.asarray(sample)
sample = sample[~np.isnan(sample)]
# get upper and lower bounds
l = np.min(sample)
u = np.max(sample)
density = kde.gaussian_kde(sample)
x = np.linspace(l, u, 2000)
y = density.evaluate(x)
# y = density.evaluate(x, l, u) waitting for PR to be accepted
xy_zipped = zip(x, y / np.sum(y))
xy = sorted(xy_zipped, key=lambda x: x[1], reverse=True)
xy_cum_sum = 0
hdv = []
for val in xy:
xy_cum_sum += val[1]
hdv.append(val[0])
if xy_cum_sum >= (1 - alpha):
break
hdv.sort()
diff = (u - l) / 20 # differences of 5%
hpd = []
hpd.append(round(min(hdv), roundto))
for i in range(1, len(hdv)):
if hdv[i] - hdv[i - 1] >= diff:
hpd.append(round(hdv[i - 1], roundto))
hpd.append(round(hdv[i], roundto))
hpd.append(round(max(hdv), roundto))
ite = iter(hpd)
hpd = list(zip(ite, ite))
modes = []
for value in hpd:
x_hpd = x[(x > value[0]) & (x < value[1])]
y_hpd = y[(x > value[0]) & (x < value[1])]
modes.append(round(x_hpd[np.argmax(y_hpd)], roundto))
return hpd, x, y, modes

同样都是使用蒙特卡洛模拟方法,但是与前文内容这里并不是直接使用原始概率分布来生成采样数据(似然分布)而是将获得的原始分布的数据进行高斯核函数估计出一个概率密度(概率函数),然后用这个估计出的概率函数再重新生成数据,这种方法虽然会造成得到的概率分布和原始概率分布的一定偏差不过该种方法十分适合无法获得原始概率分布的情况,而且经过本人测试使用高斯核函数估计出的概率函数基本和原始的概率分布吻合(十分的神奇)。

生成新的概率分布函数:

density = kde.gaussian_kde(sample)

生成新的样本数据:

    x = np.linspace(l, u, 2000)
y = density.evaluate(x)

对新生成的样本数据数据的对应概率密度进行规则化:( 这样可以保证即使采样的数据量不是十分大的情况下生成的数据对应的概率密度区间的面积和为1,方便下面对0.95HPD区间面积加和求解时的计算)

xy_zipped = zip(x, y / np.sum(y))

对0.95的HPD区间求解,原理就是将区间各点概率从大到小排序然后求得加总后等于0.95的最少的区间点,这也是上一步对各点概率进行规则化的主要原因。这步求得的点对应的概率加和为0.95,并且保证样本点数目最少,这样也保证对应的区间尽可能的小以满足近似HPD最小区间的要求。

    xy = sorted(xy_zipped, key=lambda x: x[1], reverse=True)
xy_cum_sum = 0
hdv = []
for val in xy:
xy_cum_sum += val[1]
hdv.append(val[0])
if xy_cum_sum >= (1 - alpha):
break
hdv.sort()

设置一个区间阈值diff,如果上一步求得的区间中如果有两个排序后相邻的点之间距离大于这个阈值就认为这两个点是不连续的(分属两个区间中),然后记录这两个点。计算结束后记录上步求得的HPD区间中的两个边界点。这样求得的hpd列表中每两个数代表一个区间,这样就保证最后求得的HPD区间可以是不连续的。

    diff = (u - l) / 20  # differences of 5%
hpd = []
hpd.append(round(min(hdv), roundto))
for i in range(1, len(hdv)):
if hdv[i] - hdv[i - 1] >= diff:
hpd.append(round(hdv[i - 1], roundto))
hpd.append(round(hdv[i], roundto))
hpd.append(round(max(hdv), roundto))

这一步中求得的hpd列表为[-4.06, 0.16, 1.82, 6.18],其中[-4.06, 0.16,]代表一个区间,[1.82, 6.18]代表另一个区间。

上面的核心代码中还有求解所谓的众数的代码,由于这个概率分布时连续的因此所谓的众数就是概率密度最大的数。

ite = iter(hpd)
hpd = list(zip(ite, ite))
modes = []
for value in hpd:
x_hpd = x[(x > value[0]) & (x < value[1])]
y_hpd = y[(x > value[0]) & (x < value[1])]
modes.append(round(x_hpd[np.argmax(y_hpd)], roundto))
return hpd, x, y, modes

上面的代码不难,不过有个很有意思的python代码,其实搞python代码快10多个年头了即使是今天还会遇到一些没发现过的pythonic的代码,上面就有这种:

ite为列表hpd的迭代器。

zip(ite,ite)是惰性计算,在list(zip(ite,ite))时才会从迭代器ite中提取数据,虽然zip每次从两个迭代器中提取数据但是这两个迭代器都是一个ite迭代器,那么就会zip每次从两个ite中提取数据实际都是一个ite提供的,因此最终的提取结果就是hpd中的数据依次提取两个,最后的提取结果就是[(-4.06, 0.16), (1.82, 6.18)]。如果不这样写可能就得这么写这个代码了:

hpd2=[ ]

for i in range(1, len(hpd)):

hpd2.append((hpd[i-1], hpd[i]))

print(hpd2)

=========================================================

python语言绘图:绘制贝叶斯方法中最大后验密度(Highest Posterior Density, HPD)区间图的近似计算(续)的更多相关文章

  1. 概率编程:《贝叶斯方法概率编程与贝叶斯推断》中文PDF+英文PDF+代码

    贝叶斯推理的方法非常自然和极其强大.然而,大多数图书讨论贝叶斯推理,依赖于非常复杂的数学分析和人工的例子,使没有强大数学背景的人无法接触.<贝叶斯方法概率编程与贝叶斯推断>从编程.计算的角 ...

  2. 使用pycharm手动搭建python语言django开发环境(四) django中buffer类型与str类型的联合使用

    在django中,如果用到buffer类型时,buffer的编码格式是utf-8类型.使用str()进行转为字符串类型会异常. 异常会有如下提示:'ascii' codec can't decode ...

  3. 统计学习方法与Python实现(三)——朴素贝叶斯法

    统计学习方法与Python实现(三)——朴素贝叶斯法 iwehdio的博客园:https://www.cnblogs.com/iwehdio/ 1.定义 朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设 ...

  4. 第四章 朴素贝叶斯法(naive_Bayes)

    总结 朴素贝叶斯法实质上是概率估计. 由于加上了输入变量的各个参量条件独立性的强假设,使得条件分布中的参数大大减少.同时准确率也降低. 概率论上比较反直觉的一个问题:三门问题:由于主持人已经限定了他打 ...

  5. Python实现 利用朴素贝叶斯模型(NBC)进行问句意图分类

    目录 朴素贝叶斯分类(NBC) 程序简介 分类流程 字典(dict)构造:用于jieba分词和槽值替换 数据集构建 代码分析 另外:点击右下角魔法阵上的[显示目录],可以导航~~ 朴素贝叶斯分类(NB ...

  6. Python语言程序设计(3)--实例2-python蟒蛇绘制-turtle库

    1. 2. 3.了解turtle库 Turtle,也叫海龟渲染器,使用Turtle库画图也叫海龟作图.Turtle库是Python语言中一个很流行的绘制图像的函数库.海龟渲染器,和各种三维软件都有着良 ...

  7. 基于python语言的经典排序法(冒泡法和选择排序法)

    前 每逢周末就遇雨期,闲暇之余,捣鼓了下python,心心念想学习,今天就在电脑上装了个2.7,学习了下经典算法,冒泡与选择排序法 第一次写关于python的文章,说的不当之处,多多指正,我积极改正 ...

  8. 【机器学习实战笔记(3-2)】朴素贝叶斯法及应用的python实现

    文章目录 1.朴素贝叶斯法的Python实现 1.1 准备数据:从文本中构建词向量 1.2 训练算法:从词向量计算概率 1.3 测试算法:根据现实情况修改分类器 1.4 准备数据:文档词袋模型 2.示 ...

  9. 了解 Python 语言中的时间处理

    python 语言对于时间的处理继承了 C语言的传统,时间值是以秒为单位的浮点数,记录的是从1970年1月1日零点到现在的秒数,这个秒数可以转换成我们日常可阅读形式的日期和时间:我们下面首先来看一下p ...

  10. Python语言程序设计之一--for循环中累加变量是否要清零

    最近学到了Pyhton中循环这一章.之前也断断续续学过,但都只是到了函数这一章就停下来了,写过的代码虽然保存了下来,但是当时的思路和总结都没有记录下来,很可惜.这次我开通了博客,就是要把这些珍贵的学习 ...

随机推荐

  1. 增补博客 第三篇 python 英文统计

    编写程序实现对特定英文文章(文本文件)的单词数和有效行数的统计,其中要求空行不计数: def count_words_and_lines(file_path): word_count = 0 line ...

  2. 短链接口设计&禁用Springboot执行器端点/env的安全性

    短链接口设计 //短链接服务 跳转方式,实现短链接转长链接的请求. @GetMapping("/{code}") public String redirectUrl(@PathVa ...

  3. 58同城的登录(RSA算法)

    Tips:当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解` 58同城的登录(RSA算法) 日期:2016-11-23 ...

  4. Niagara 物联网技术基础应用(文章修复中,不定时更新)

    新手指南 前言 鉴于市面上有关Niagara物联网技术资料较少,笔者结合自生参加竞赛的经历编写此指南,该指南旨在让新手快速上手Niagara workbench 主要分以下几个模块讲解: 物联网软件平 ...

  5. IDEA安装配置

    1.安装IDEA选择免费体验 2.下载对应版本的破解补丁 agent.jar -2.1 将agent.jar补丁和important.txt放置到idea安装目录 3.修改VMoption javaa ...

  6. 从github下好dirsearch后出现要下载文件依赖错误

    pip3 install -r requirements.txt

  7. 一款.NET开源的i茅台自动预约小助手

    前言 今天大姚给大家分享一款.NET开源.基于WPF实现的i茅台APP接口自动化每日自动预约(抢茅台)小助手:HyggeImaotai. 项目介绍 该项目通过接口自动化模拟i茅台APP实现每日自动预约 ...

  8. Linux greybus

    背景 在研究高通平台驱动震动马达时,我需要为内核驱动实现以下功能:/sys/class/timed_output/vibrator/enable":sysfs文件系统注册接口.提供show. ...

  9. 嵌入式知识分享——GDB程序调试方法说明

    前  言 本指导文档适用开发环境: Windows开发环境:Windows 7 64bit.Windows 10 64bit Linux开发环境:Ubuntu 18.04.4 64bit 虚拟机:VM ...

  10. GUI测试稳定性的关键技术

    标签(空格分隔): GUI测试稳定性 GUI测试稳定性的关键技术 GUI 自动化测试稳定性,最典型的表现形式就是,同样的测试用例在同样的环境上,时而测试通过,时而测试失败. 这也是影响 GUI 测试健 ...