101贝叶斯方法数据分析实战--概率分布及 PyMC 初探

概率分布及 PyMC 初探

概率分布

首先,让我们回忆一下,什么是概率分布?设Z是一个随机变量,则,必定存在一个与Z有关的概率分布函数。 给定Z的任意取值,我们都可以得到该Z对应的概率值。

我们把随机变量分为以下 3 种类别:
Z 为离散的。离散随机变量的取值只能存在于某个特定的列表中。像人民币(只有5毛、1元、20元、100元等面值)、投票数等都属于离散的随机变量。
Z 为连续的。连续型随机变量的值可以是任意精确度的数值。像温度和时间等都属于连续型变量。因此对于这些数值,我们可以将其精确到任意程度。连续型变量和离散型变量是一组相对的变量。
Z 为混合的。混合型随机变量的值,可以为以上两种形式。也就是结合了上面两种随机变量形式的变量。

离散情况

如果 Z 是离散的,则它的分布就是概率质量函数。该函数度量的是, Z 取值为 k 时的概率,即 P(Z = k)。换句话说,概率分布函数描述了随机变量 Z。也就是说,如果知道了 Z 的概率质量方程,我们就能够完全的掌握 Z 的表现情况。下面我们会介绍一些常见的概率质量方程。


image.png

λ 被称为分布的一个参数,可以为任意正数,它决定了我们这个分布的强度。
k不同于λ, 可以为任意非负整数,即k必须为 0,1,2 之类的值。这是非常重要的,比如,当我们在模拟人口分布时,我们是不可以假设有 3.42 个或者 5.212 个人的。
让我们来使用一下这个分布函数,并且观察一下λ对该概率函数的影响。这里我们会使用到上一个试验中用到的 scipy.stats 库,该库已经为我们定义了这些分布函数。让我们先导入它们。

import scipy.stats as stats
from IPython.core.pylabtools import figsize
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
# 定义 possion 函数
poi = stats.poisson
# 定义 两个 lambda 值
lambda_ = [1.5, 4.25]
# 定义 k值为0-15
k = np.arange(16)
k

接下来,让我们把 k 值传入概率质量函数中,得到每个 k 对应的概率值:

# 所有的分布函数类中都存在 pmf 函数用于计算相应的概率值
# 通过传入不同的 labmda 值,求出两组概率值
P_lambda_0 = poi.pmf(k, lambda_[0])
P_lambda_1 = poi.pmf(k, lambda_[1])
P_lambda_0, P_lambda_1

如上,我们已经得到了每个k相应的概率值。为了更好的了解λ 对于整个函数的影响,这里,我们对我们求到的值进行可视化。
首先,让我们导入 Matplotlib 库,并画出相关图像:

import matplotlib as mpl
from matplotlib import pyplot as plt
%matplotlib inline
# 设置所画图像的大小
figsize(12.5, 4)
# 将两个lambda对应的概率设置为两种,不同的值
colours = ["#348ABD", "#A60628"]


plt.bar(k, P_lambda_0, color=colours[0],
        label="$\lambda = %.1f$" % lambda_[0], alpha=0.60,
        edgecolor=colours[0], lw="3")

plt.bar(k, P_lambda_1, color=colours[1],
        label="$\lambda = %.1f$" % lambda_[1], alpha=0.60,
        edgecolor=colours[1], lw="3")

plt.xticks(k + 0.4, k)
plt.legend()
plt.ylabel("probability of $k$")
plt.xlabel("$k$")
plt.title("Probability mass function of a Poisson random variable; differing \
$\lambda$ values")

从上图中可以看到,对于Poisson分布来说,随着λ 的增大,得到较大值的概率会增大。相反地,当 λ 减小时,得到较小值的概率会增大。其次,虽然x轴在 15 的时候就停止了,但是分布并没有在这里截止。他可以延伸到任意非负的整数。

image.png

连续情况
相对于离散情况下的概率质量函数,连续情况下的分布函数被称为概率密度函数。虽然听起来大同小异,但是它们之间存在着本质的不同。举一个连续型随机变量的例子:指数密度函数。
image.png

类似于Poisson随机变量,指数随机变量只可以取非负值。但是与Poisson分布不同的是,这里的指数可以取任意非负值,包括如 4.35 、1.1234.35、1.123 等的非整数。因此,只有像时间数据、温度数据等可以为任意精度的连续型变量才适合该函数。
image.png

按照画Poisson函数的思路,我们也通过 Python 画出不同λ 对指数密度函数表现形式的影响。由于这是连续型变量,所以我们不能使用条形图而选择折线图来表示连续型。代码如下:

a = np.linspace(0, 4, 100)
expo = stats.expon
lambda_ = [0.5, 1]

for l, c in zip(lambda_, colours):
    plt.plot(a, expo.pdf(a, scale=1./l), lw=3,
             color=c, label="$\lambda = %.1f$" % l)
    plt.fill_between(a, expo.pdf(a, scale=1./l), color=c, alpha=.33)

plt.legend()
plt.ylabel("PDF at $z$")
plt.xlabel("$z$")
# 设置y轴范围
plt.ylim(0, 1.2)
plt.title("Probability density function of an Exponential random variable;\
 differing $\lambda$")

值得注意的是,概率密度函数方程的某一个点的值并不等于它在这个点的概率。
什么是λ
这个问题,我们可以理解为统计的动机是什么。在现实世界中,我们并不知道λ 的存在,我们能直观感受的就是变量Z。因此,为了确定参数λ,我们就必须深入到整个事件的背景中去。这个问题,其实很难,因为并不存在Z到λ 的对应公式。
对于λ的估计有很多设计好的方法,但因为λ不是一个可以真正观察到的东西。因此,谁也不能说哪一种方法是最好的。
贝叶斯推断提出,就是为了对λ取值进行估计。与其不断的猜测 λ的精确取值,不如用一个概率分布来描述λ 的可能取值。
这看起来或许有些奇怪。毕竟,λ是一个定值,它不一定是随机的!我们怎么能对一个非随机变量值赋予一个概率呢?不,这样的思维方式其实是老旧的频率派的思考方式。在贝叶斯的哲学体系下,我们可以通过所统计的数据,对λ赋予概率值(后面会详细阐述)。因此,对参数λ估计是完全可以接受的。
总结一下,贝叶斯推断的主要思路,就是先给λ赋上一个先验分布,然后找到我们能观测到的数据和 λ之间的关系式,进而建立模型。然后将我们观测到的数据集放入模型中进行训练,最后得到λ的后验分布。

实例:从短信数据推断行为

接下来,我们来模拟一个有趣的实例。这是一个关于用户发送和收到短信的例子。
这里我们为你提供了一个用户收发短信条数的数据集合,让我们将它加载到本地:

!wget -nc "https://labfile.oss.aliyuncs.com/courses/1520/lab2-1.csv"

接下来,我们还是利用 Python 先对这些数据进行可视化,再来对其行为进行推断。

from matplotlib import pyplot as plt
from IPython.core.pylabtools import figsize
import numpy as np
%matplotlib inline
# 利用 numpy 加载数据,该文件夹里存的就是每天短信的条数 count_data
count_data = np.loadtxt("lab2-1.csv")
n_count_data = len(count_data)
n_count_data, count_data

根据上面的结果,该文件共存储了该用户 74 天内发送和收到的短信条数。接下来,让我们来观察用户的短信使用行为是否随着时间有所改变。短信的条数是循序渐进?还是突然的变化?

figsize(12.5, 3.5)
plt.bar(np.arange(n_count_data), count_data, color="#348ABD")
plt.xlabel("Time (days)")
plt.ylabel("count of text-msgs received")
plt.title("Did the user's texting habits change over time?")
plt.xlim(0, n_count_data)

从上图中,我们可以很好的发现,用户在后半段时间收发短信的条数明显变多,即他的收发短信行为可能发生了改变。但是,从图中,我们很难判断出他到底是何时发生的行为改变。因此,我们需要利用贝叶斯推断进行计算。

image.png

或许,我们不能确定参数λ 的真实取值。然而,整个观察周期的后期收到的短信的几率升高了。换句话说,λ 在某个时段增加了。因为,前文中提到过,当λ 取大值的时候,更容易得到较大的结果值。
image.png

当然,如果实际上,λ 根本没有发生变化。那么这两个结果的后验就会相等,即λ1=λ2。
对于这些不知道的λ ,我们充满了兴趣。我们只需要利用贝叶斯推断求出两个λ 和τ的值即可。
在贝叶斯推断下,我们需要对不同的λ分配相应的先验概率。对于参数λ1和λ2来说,什么才是一个好的先验概率呢?
前面提到过λ可以取任意正数,像我们前面见到的那样,指数分布对任意正数都存在一个连续密度函数。这或许对模拟λi来说,是一个很好的选择。 因此,我们将两个λ的先验分布赋为指数分布。
其中α被称为超参数。这里由于引入了指数分布,我们就有相当于引入了一次位置参数α。当然,我们也可以为α 继续制定分布。但是,显然这会非常复杂,因此,这里我们直接対它进行一个灵活的设定。这里,我们建议将其设定为样本中计算平均值的逆。为什么这样做呢?
image.png

使用这个值,我们可以比较客观的减少超参数对模型造成的影响。另外,我也非常建议你能够构建两个不同的α值来反映出不同的先验估计。即,整个观测过程中,用户行为是发生了变化的。
对于参数τ ,由于受到噪声数据的影响,很难为它挑选适合的先验。
我们的利器:PyMC
PyMC 是一个做贝叶斯分析的 Python 库。它运行速度快,维护也很好。它唯一的缺点是,它的说明文档在某些领域有所缺失,尤其是在一些能够区分菜鸟和高手的领域。
下面用 PyMC 模拟上面的问题。这种类型的编程被称之为概率编程。当然,叫这个名字并不是说代码是随机产生的。之所以名字里面包含了概率,是因为使用了编译变量作为模型的组件来创建概率模型。模型组件是 PyMC 中的第一类原语,即模型中的所有参数。
Cronin 对概率编程有一段激动人心的描述:
换一种方式考虑整件事情,跟传统的编程仅仅向前运行不同的是,概率编程既可以向前也可以向后运行。它通过向前运行来计算其中包含的所有关于世界的假设结果。它通过数据向后运行,以约束所有可能的解释。在实践中,许多概率编程系统将这些向前和向后的操作,巧妙地交织在一起,以给出有效的最佳解释。
或许上面的解释会让你云里雾里,“概率编程”一词也会让人产生很多不必要的困惑。因此,接下来我们会尽力克制使用这个概念,以简单的方式来介绍这个 PyMC。
其实 PyMC 代码是非常易读的。唯一新颖的东西就是语法,接下来我们会使用这些语法,根据上面我们提到的(τ,λ1,λ2)的计算公式,来完成模型组件的搭建。
首先,让我们导入 PyMC3 和 Theano 库。

import pymc3 as pm
# 定义一个变量模型,后面的所有随机变量都会写入其中
model = pm.Model()

接下来,让我们根据公式,将(τ,λ1,λ2)等随机变量写入 model 中。

with model:  # 利用with定义一个上下文管理器,以 model 作为上下文。
           # 在这个上下文中定义的变量都会被添加到这个模型中去

    # α 变量为样本中计算平均值的逆(即倒数的意思)
    alpha = 1.0/count_data.mean()

    # 两个 λ的值都服从指数密度函数分布,函数参数为α
    lambda_1 = pm.Exponential("lambda_1", alpha)
    lambda_2 = pm.Exponential("lambda_2", alpha)

    # τ,即λ发生改变的时间,为 0 - 73 中的任意一天(总共74天)
    # 因为τ是代表的天数,是离散的,这里通过 DiscreteUniform 设置它为离散型变量
    # 即产生随机数
    tau = pm.DiscreteUniform("tau", lower=0, upper=n_count_data - 1)
model

在上面代码中,我们创建了对应于参数λ1和λ2的 PyMC 变量。并且设置它们为 PyMC 的随机变量,这些变量服从于它们自己的分布函数。


image.png

我们用变量 lambda_ 来存每个时刻的λ值,代码如下:

with model:
    idx = np.arange(n_count_data)  # idf 表示天数
    # lambda_ 表示每天的 λ的值
    # 当小于τ 时为lambda_1 ,大于为lambda_2
    lambda_ = pm.math.switch(tau >= idx, lambda_1, lambda_2)
type(lambda_)

这里是无法将 lambda_ 的具体的值显示出来的。因为 lambda_1、lambda_2、tau 是随机的,所以 lambda_ 也会是随机的。它们只有在模型编译时,才会出现具体的值。目前我们只是定义了它们的分布方式,还未进行具体计算。
让我们总结一下思路,我们观察了我们得到的用户收发短信的数据,并且假设了这些数据服从于 Poisson 分布。而对于 Poisson 分布,最关键的便是λ (即变量 lambda_ )的求解。为了更加准确的求取 lambda_ ,根据图像,我们将 lambda_ 分成了两个阶段,分别为 lambda_1,lambda_2 这两个值。再加上参数变化的时刻 tau。整个模型需要求解的便是 (lambda_1,lambda_2,tau) 这三个变量。
接下来我们就来将定义模型与实际统计的数据相结合。

with model:
    # 将统计数据 与 参数为 lambda_ 的 Poisson 分布相结合。
    observation = pm.Poisson("obs", lambda_, observed=count_data)
type(observation)

我们假设的观察数据是通过 Poisson 分布产生,因此我们需要把这些参数和 poisson 分布结合,得到观测数据的产生模型。然后将真实的观测数据放入模型中进行训练,进而得到那几个参数的具体后验。
目标数据已经传入了 model,需要求解的参数也已经传入了 model。接下来,其实我们只需要按下“学习”的按钮,让计算机自行学习,就可以得到参数 (τ,λ1,λ2)的值了。
接下来,我们就来编写按下这个“按钮”的代码。但是这里会使用到一种叫做 马尔科夫链蒙特卡洛(MCMC) 的复杂理论。这个复杂理论和代码将在后面的实验进行阐述。为了展示结果,这里,我们只需要运行下面代码即可。无需自己手动敲。

# 下面代码将在之后的实验中,进行阐述
with model:
    step = pm.Metropolis()
    trace = pm.sample(10000, tune=5000, step=step)

通过上面的学习,我们从λ1、λ2和τ各自所对应的后验分布函数中,得到了数千个随机样本。样本如下,这些变量都是通过学习到的各自的分布函数所产生。因为这些变量的具体后验分布公式很能表示,因此返回的是由后验分布产生的随机样本。

lambda_1_samples = trace['lambda_1']
lambda_2_samples = trace['lambda_2']
tau_samples = trace['tau']
lambda_1_samples, lambda_2_samples, tau_samples

我们只需要将这些值进行统计即可。例如,计算 lambda_1 的样例中每个数字所出现的频率。通过这些频率,我们就能够画出每个参数的后验分布的样子。下面,则是我们通过直方图,来展示每种参数的后验概率。

figsize(12.5, 10)
# 下面的代码全为图像可视化代码
# 将图像分为三份,现在ax代表的是第一行第一张
ax = plt.subplot(311)
ax.set_autoscaley_on(False)
# 画出lambda_1 的后验分布
plt.hist(lambda_1_samples, histtype='stepfilled', bins=30, alpha=0.85,
         label="posterior of $\lambda_1$ ", color="#A60628", normed=True)
plt.legend(loc="upper left")
plt.title(r""" $\lambda_1,\;\lambda_2,\;\tau$ """)
plt.xlim([15, 30])
plt.xlabel("$\lambda_1$ value")

# 画出lambda_2 的后验分布
ax = plt.subplot(312)
ax.set_autoscaley_on(False)
plt.hist(lambda_2_samples, histtype='stepfilled', bins=30, alpha=0.85,
         label="posterior of $\lambda_2$ ", color="#7A68A6", normed=True)
plt.legend(loc="upper left")
plt.xlim([15, 30])
plt.xlabel("$\lambda_2$ value")

# 画出lambda_3的后验分布
plt.subplot(313)
w = 1.0 / tau_samples.shape[0] * np.ones_like(tau_samples)
plt.hist(tau_samples, bins=n_count_data, alpha=1,
         label=r"posterior of $\tau$ ",
         color="#467821", weights=w, rwidth=2.)
plt.xticks(np.arange(n_count_data))

plt.legend(loc="upper left")
plt.ylim([0, .75])
plt.xlim([35, len(count_data)-20])
plt.xlabel(r"$\tau$ (day)")
plt.ylabel("probability")

说明
回想一下,贝叶斯方法返回一个分布。因此,现在我们可以用分布来描述未知的λ和τ。我们也可以从上面的分布中,找到参数的合理值:λ1大概为 18 和λ2大概为23。这两个\lambdaλ 的后验分布明显不同,这表明用户接受短信的行为确实发生了变化。
我们还可以注意到λ的后验分布并不像是指数分布。事实上,后验分布并不是我们可以从原始模型中辨别的任何分布。正因如此,我们利用贝叶斯推断出来的不是一个分布的函数值,而是一批分布中的样本点。如果我们改用数学方式处理这个问题,它就会变得棘手和混乱。
再来看看τ的一个分布。由于它是一个离散的变量,所以它的后验看起来和其他的两个参数有点不同,它不存在概率区间。我们可以看到在第3天,有50%的把握可以说用户的行为是有所改变的。并且,从上面结果可以看出,仅仅有三到四天可以认为是潜在的转折点。
后验样本的作用
在本课程的后面章节,我们会着重阐述这个问题。现在我们用另外一个实例对它进行简单的阐述。
我们需要用我们刚才得到的后验样本来回答下面问题:
在第t(0≤t≤73)天中,期望收发所少条短信呢?
由于Poisson分布的期望值等于它的参数λ。因此问题相当于:在时间 t中,参数λ的期望值是多少。

image.png

将上面公式,写成代码,如下:

N = tau_samples.shape[0]
expected_texts_per_day = np.zeros(n_count_data)
for day in range(0, n_count_data):
    ix = day < tau_samples
    # 求第 t 天的期望,即所有可能的 lambda 的平均值
    # 当t

最后,我们将这些期望展示到原图上,观察它与实际收发信息的关系。

figsize(12.5, 5)
plt.plot(range(n_count_data), expected_texts_per_day, lw=4, color="#E24A33",
         label="expected number of text-messages received")
plt.xlim(0, n_count_data)
plt.xlabel("Day")
plt.ylabel("Expected # text-messages")
plt.title("Expected number of text-messages received")
plt.ylim(0, 60)
plt.bar(np.arange(len(count_data)), count_data, color="#348ABD", alpha=0.65,
        label="observed texts per day")

plt.legend(loc="upper left")

上图的结果很明显的说明了转折点的重要影响。我们的分析结果非常符合之前的估计:用户行为确实发生了改变,而且这是一个突然的变化,而非循序渐进的变化。我们可以推测这种情况的产生原因是:短信费用降低,天气提醒短信的订阅或者一段新的感情等。
两个λ值是否真的一样
在短信接收例子中,我们只管地观测了λ1和 λ2的先验信息。并认为他们是不同的。这很公平,毕竟先验的位置基本离得非常远。但是这种观察的主管因素过强,下面,我们将会介绍一种较为正式的方法,来判断两个 λ 值是否相等。
一种方法是计算出 P(λ1<λ2∣data)。即在获得观察数据的前提下,λ1的真实值比λ2小的概率。如果这个概率接近 50% ,那就相当于是投硬币的结果,我们则不能确定这两个λ 值是不同的。如果,这个概率接近 100% ,那么我们就可以很自信的说,这两个值必定不同。
利用上我们得到的后验样本,这种计算是非常简单的。我们只需计算λ1的后验样本中比λ2的后验样本小的次数的比例即可。

print((lambda_1_samples < lambda_2_samples).mean())

结果很显然,现在我们几乎 100% 的把握可以说这两个值是不等的。
当然,我们还可以问的更加详细一点。比如,两个值之间相差至少 1、2、5、10 的概率有多大?

for d in [1, 2, 5, 10]:
    v = (abs(lambda_1_samples-lambda_2_samples) >= d).mean()
    print("两个 lambda 之间相差至少{}的概率为 : %{}".format(d, v*100))

多行为变化推断

数据集的下载

同样,让我们先从蓝桥云课的网站上下载这些数据集:

!wget -nc "https://labfile.oss.aliyuncs.com/courses/1520/lab2-1.csv"

接下来,从这个数据集合读入到模型中:

import scipy.stats as stats
from IPython.core.pylabtools import figsize
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline

count_data = np.loadtxt("lab2-1.csv")
n_count_data = len(count_data)
n_count_data, count_data

模型的建立

image.png

挑战:将上面几个参数加入我们定义的模型中

import pymc3 as pm
import theano.tensor as tt
#定义一个变量模型,后面的所有随机变量都会写入其中
model = pm.Model()
with model:#利用with定义一个上下文管理器,以 model 作为上下文。
           #在这个上下文中定义的变量都会被添加到这个模型中去
        
    # α 变量为样本中计算平均值的逆(即倒数的意思)
    alpha = 1.0/count_data.mean()  
    
    #三个 λ的值都服从指数密度函数分布,函数参数为α
    lambda_1 = pm.Exponential("lambda_1", alpha)
    lambda_2 = pm.Exponential("lambda_2", alpha)
    lambda_3 = pm.Exponential("lambda_3", alpha)
                              
    #τ,即λ发生改变的时间,为 0 -70 中的任意一天(总共71天)
    #因为τ是代表的天数,是离散的,这里通过 DiscreteUniform 设置它为离散型变量
    #即产生随机数
    tau_1 = pm.DiscreteUniform("tau_1", lower=0, upper=n_count_data - 1)
    tau_2 = pm.DiscreteUniform("tau_2", lower=0, upper=n_count_data - 1)
model

挑战:完成分段函数 lambda_ 的赋值。

with model:
    idx = np.arange(n_count_data) # idf 表示天数
    #lambda_ 表示每天的 λ的值
    #使用where 条件语句去达到 3 分段函数赋值的效果
    lambda_ =  pm.math.where (idx

接下来,就是将这我们定义的参数和实际数据相结合,代码和上一个试验相同:

with model:
    # 将统计数据 与 参数为 lambda_ 的 Poisson 分布相结合。
    observation = pm.Poisson("obs", lambda_, observed=count_data)
type(observation)

最后就是摁下“学习”的按钮,让模型进行训练与学习:

with model:
    step = pm.Metropolis()
    trace = pm.sample(1000, tune=500, step=step)

通过 trace 函数得到这些参数的后验分布函数下的几千个随机变量:

lambda_1_samples = trace['lambda_1']
lambda_2_samples = trace['lambda_2']
lambda_3_samples = trace['lambda_3']
tau1_samples = trace['tau_1']
tau2_samples = trace['tau_2']
print("lambda1:", lambda_1_samples)
print("lambda2:", lambda_2_samples)
print("lambda3:", lambda_3_samples)
print("tau_1:", tau1_samples)
print("tau_2:", tau2_samples)

数据可视化

挑战:分别画出以上 5 个参数的分布图像

figsize(12.5, 10)
#下面的代码全为图像可视化代码
#将图像分为三份,现在ax代表的是第一行第一张
ax = plt.subplot(511)
ax.set_autoscaley_on(False)
#画出lambda_1 的后验分布
plt.hist(lambda_1_samples, histtype='stepfilled', bins=30, alpha=0.85,
         label="posterior of $\lambda_1$", color="#A60628", normed=True)
plt.legend(loc="upper left")
plt.title(r"""Posterior distributions of the variables
    $\lambda_1,\;\lambda_2,\;\tau$""")
plt.xlim([15, 30])
plt.xlabel("$\lambda_1$ value")

#画出lambda_2 的后验分布
ax = plt.subplot(512)
ax.set_autoscaley_on(False)
plt.hist(lambda_2_samples, histtype='stepfilled', bins=30, alpha=0.85,
         label="posterior of $\lambda_2$", color="#7A68A6", normed=True)
plt.legend(loc="upper left")
plt.xlim([50, 65])
plt.xlabel("$\lambda_2$ value")

#画出lambda_3 的后验分布
ax = plt.subplot(513)
ax.set_autoscaley_on(False)
plt.hist(lambda_3_samples, histtype='stepfilled', bins=30, alpha=0.85,
         label="posterior of $\lambda_3$ ", color="#7A68A6", normed=True)
plt.legend(loc="upper left")
plt.xlim([15, 30])
plt.xlabel("$\lambda_2$ value")

#画出 tau_1 的后验分布
plt.subplot(514)
w = 1.0 / tau1_samples.shape[0] * np.ones_like(tau1_samples)
plt.hist(tau1_samples, bins=n_count_data, alpha=1,
         label=r" posterior of $\tau_1$ ",
         color="#467821", weights=w, rwidth=2.)
plt.xticks(np.arange(n_count_data))

plt.legend(loc="upper left")
plt.ylim([0, .75])
plt.xlim([20, 35])
plt.xlabel(r"$\tau$ (day)")
plt.ylabel("probability");

##画出 tau_2 的后验分布
plt.subplot(515)
w = 1.0 / tau2_samples.shape[0] * np.ones_like(tau2_samples)
plt.hist(tau2_samples, bins=n_count_data, alpha=1,
         label=r"posterior of $\tau_2$ ",
         color="#467821", weights=w, rwidth=2.)
plt.xticks(np.arange(n_count_data))

plt.legend(loc="upper left")
plt.ylim([0, .75])
plt.xlim([35, len(count_data)-20])
plt.xlabel(r"$\tau$ (day)")
plt.ylabel("probability");

你可能感兴趣的:(101贝叶斯方法数据分析实战--概率分布及 PyMC 初探)