用Python粗糙地实现贝叶斯推理之β分布

用Python粗糙地实现贝叶斯推理之β分布

前言

本文给出的代码只是为了好玩,没有什么质量可言,遵循

Make it run , Make it right , Make it fast

先让它跑起来,至于代码美观和效率则不考虑,反正也没人用,自娱自乐

将概率的概率作为先验概率

在贝叶斯推理中,有先验概率,条件概率,后验概率。 具体的定义这里不再详述,之前的文章也有提及。为了便于理解“将概率的概率作为先验概率”,这里从一个示例讲起,选自《小岛宽之. 统计学关我什么事:生活中的极简统计学》

一对夫妇第一胎生了女孩,请问第二胎是女孩的概率?

这对夫妇生女孩的概率为P,假设P=0.4,P=0.5,P=0.6,即这对夫妇生女孩的概率是0.4,0.5,0.6 。 概率的概率 就是这对夫妇生女孩的概率是0.4的概率,这对夫妇生女孩的概率是0.5的概率,这对夫妇生女孩的概率是0.6的概率。 把概率的概率作为先验概率,由于我们不知道这对夫妇到底是哪一种类型,假设每种的概率都相同,当然,先验概率就是可以随便给出的,这里都取1/3。

Alt text

因为第一胎是女孩,所以

Alt text

这里主要介绍下将概率的概率作为先验概率,为下面的内容做个基础准备。

更具体的概率

上面的示例中,这对夫妇生女孩的概率只有三种情况【0.4,0.5,0.6】,但是实际生活中有无穷种可能,从0到1,是连续的。为了方便计算,这里采用从0-100(0,1,2,...,98,99,100),即

这对夫妇生女孩的概率是0%

这对夫妇生女孩的概率是1%

这对夫妇生女孩的概率是2%

...

这对夫妇生女孩的概率是98%

这对夫妇生女孩的概率是99%

这对夫妇生女孩的概率是100%

每种情况的概率相等,也就是从0到100的概率相等,共101种情况,概率是100(百分制),那么每种概率就是100/101,先验概率就是(100/101)

类比刚才只有三种情况的做法,画出矩形表格,这里就不画了,然后出生的结果是女孩,去掉是男孩的部分,剩下的面积要符合总概率等于100的情况,计算出每个概率所对应的概率,就是后验概率。

不忍直视的Python代码

代码写得很烂,先让它跑起来,以后再优化下(如果可能的话,呵呵!)

# -*- coding: UTF-8 -*-
import numpy

'''
自定义变量
init_prior_pr 初始先验概率
prior_pr 先验概率
posterior_pr 后验概率
result 结果集 (0代表True,1代表False)
x_pr X事件概率
y_pr Y事件概率 (X事件概率 + Y事件概率 = 1)
'''

def beta_pr(result):
    # 先设置初始先验概率为空列表
    init_prior_pr = []

    # 假设所有概率都相等,通过循环得到初始先验概率列表
    ii = 100/101
    count = 0    
    while (count < 101):
        init_prior_pr.append(ii)
        count = count + 1

    # 初始化X事件的概率
    x_pr = list(range(0, 101))  # 生成 0-100 数字

    # 根据X事件生成Y事件
    y_pr = []
    count = 0
    while (count < 101):
        tmp = 100 - x_pr[count]
        y_pr.append(tmp)
        count = count + 1

    # 将初始先验概率赋值给一个临时变量
    prpr = init_prior_pr

    # 开始处理导入的结果集
    for res in result:

        # 初始化各个值
        x_sum = 0
        y_sum = 0        

        # 从临时变量中得到先验概率
        prior_pr = prpr

        # 计算各个事件的总概率
        for elem in range(101):
            x_sum = x_sum + prior_pr[elem] * x_pr[elem]
            y_sum = y_sum + prior_pr[elem] * y_pr[elem]

        # 处理事件
        if res == 0:
            # 观察到X事件的后验概率
            posterior_pr = []
            for elem1 in range(101):
                pmt = prior_pr[elem1] * x_pr[elem1] / x_sum
                posterior_pr.append(pmt) # 生成后验概率列表

            # 将后验概率赋值给临时变量,在下一轮循环中当作先验概率
            prpr = posterior_pr

            # 计算X事件的各个概率的概率,最后计算出X事件的期望值
            x_expect = 0
            for elem3 in range(101):
                x_expect = x_expect + x_pr[elem3] * posterior_pr[elem3] # 计算期望值

            x_expect = x_expect
            x_expect = round(x_expect, 0)
            # print (x_expect)

        elif res == 1:
            # 观察到Y事件的后验概率
            posterior_pr = []
            for elem2 in range(101):
                mtp = prior_pr[elem2] * y_pr[elem2] / y_sum
                posterior_pr.append(mtp) # 生成后验概率列表

            # 将后验概率赋值给临时变量,在下一轮循环中当作先验概率
            prpr = posterior_pr

            # 计算X事件的各个概率的概率,最后计算出X事件的期望值
            x_expect = 0
            for elem4 in range(101):
                x_expect = x_expect + x_pr[elem4] * posterior_pr[elem4] # 计算期望值

            x_expect = x_expect
            x_expect = round(x_expect, 0)
            # print (x_expect)

    return(x_expect)

这里给出的结果是期望,也就是每个概率再乘以它们各自的概率,关于什么是期望,请直接参考维基百科关于期望的条目

最后,关于β分布

如果这对夫妻生女孩的概率是从0到100连续的,那么概率的概率也连续的,这两个数值在一个直角坐标系的第一象限形成一个曲线的图像,就是β分布函数。

Alt text

维基百科上关于β分布的定义

Alt text

这个函数的期望:

Alt text

上述公式计算的期望结果和上面的Python代码计算结果是一样的

当这对夫妻第一胎是女孩,那么第二胎还是女孩的概率期望是:

Python代码

... #省略上述代码
sex = [0] # 女孩为0,男孩为1
print (beta_pr(sex))

Alt text

β分布函数 当概率的概率都是相等的时候,那么β分布函数是一条平行于X轴的线段,Y轴的具体数值不管取决于参数B的大小

Alt text

所以这里的先决条件是 α = 1,β =1 当第一胎是女孩,第二胎还是女孩的概率期望

α = 2 (因为第一胎是女孩,所以可以理解为α+1了)

β = 1 (同理,如果是男孩那么β+1)

期望等于 E = α/(α+β)=2/3=0.67(近似值)

继续增加

sex = [0,1,1] (女孩,男孩,男孩)

α = 2,β = 3

计算结果是相同的,这里就不写了

如果想继续了解β分布,推荐阅读知乎上的一篇问答 如何通俗理解 beta 分布?


全文完

本文参考:

《小岛宽之. 统计学关我什么事:生活中的极简统计学》

维基百科

Python 手册

感谢自由的互联网,让我一个毫无基础的人能学到这些知识。