EM算法的python实现的方法步骤


Posted in Python onJanuary 02, 2018

前言:前一篇文章大概说了EM算法的整个理解以及一些相关的公式神马的,那些数学公式啥的看完真的是忘完了,那就来用代码记忆记忆吧!接下来将会对python版本的EM算法进行一些分析。

EM的python实现和解析

引入问题(双硬币问题)

假设有两枚硬币A、B,以相同的概率随机选择一个硬币,进行如下的抛硬币实验:共做5次实验,每次实验独立的抛十次,结果如图中a所示,例如某次实验产生了H、T、T、T、H、H、T、H、T、H,H代表正面朝上。

假设试验数据记录员可能是实习生,业务不一定熟悉,造成a和b两种情况

a表示实习生记录了详细的试验数据,我们可以观测到试验数据中每次选择的是A还是B

b表示实习生忘了记录每次试验选择的是A还是B,我们无法观测实验数据中选择的硬币是哪个

问在两种情况下分别如何估计两个硬币正面出现的概率?

以上的针对于b实习生的问题其实和三硬币问题类似,只是这里把三硬币中第一个抛硬币的选择换成了实习生的选择。

对于已知是A硬币还是B硬币抛出的结果的时候,可以直接采用概率的求法来进行求解。对于含有隐变量的情况,也就是不知道到底是A硬币抛出的结果还是B硬币抛出的结果的时候,就需要采用EM算法进行求解了。如下图:

EM算法的python实现的方法步骤

其中的EM算法的第一步就是初始化的过程,然后根据这个参数得出应该产生的结果。

构建观测数据集

针对这个问题,首先采集数据,用1表示H(正面),0表示T(反面):

#硬币投掷结果
observations = numpy.array([[1,0,0,0,1,1,0,1,0,1],
            [1,1,1,1,0,1,1,1,0,1],
            [1,0,1,1,1,1,1,0,1,1],
            [1,0,1,0,0,0,1,1,0,0],
            [0,1,1,1,0,1,1,1,0,1]])

第一步:参数的初始化

参数赋初值

EM算法的python实现的方法步骤

第一个迭代的E步

抛硬币是一个二项分布,可以用scipy中的binom来计算。对于第一行数据,正反面各有5次,所以:

#二项分布求解公式
contribution_A = scipy.stats.binom.pmf(num_heads,len_observation,theta_A)
contribution_B = scipy.stats.binom.pmf(num_heads,len_observation,theta_B)

将两个概率正规化,得到数据来自硬币A,B的概率:

weight_A = contribution_A / (contribution_A + contribution_B)
weight_B = contribution_B / (contribution_A + contribution_B)

这个值类似于三硬币模型中的μ,只不过多了一个下标,代表是第几行数据(数据集由5行构成)。同理,可以算出剩下的4行数据的μ。

有了μ,就可以估计数据中AB分别产生正反面的次数了。μ代表数据来自硬币A的概率的估计,将它乘上正面的总数,得到正面来自硬币A的总数,同理有反面,同理有B的正反面。

#更新在当前参数下A,B硬币产生的正反面次数
 counts['A']['H'] += weight_A * num_heads
 counts['A']['T'] += weight_A * num_tails
 counts['B']['H'] += weight_B * num_heads
 counts['B']['T'] += weight_B * num_tails

第一个迭代的M步

当前模型参数下,AB分别产生正反面的次数估计出来了,就可以计算新的模型参数了:

new_theta_A = counts['A']['H']/(counts['A']['H'] + counts['A']['T'])
new_theta_B = counts['B']['H']/(counts['B']['H'] + counts['B']['T'])

于是就可以整理一下,给出EM算法单个迭代的代码:

def em_single(priors,observations):

  """
  EM算法的单次迭代
  Arguments
  ------------
  priors:[theta_A,theta_B]
  observation:[m X n matrix]

  Returns
  ---------------
  new_priors:[new_theta_A,new_theta_B]
  :param priors:
  :param observations:
  :return:
  """
  counts = {'A': {'H': 0, 'T': 0}, 'B': {'H': 0, 'T': 0}}
  theta_A = priors[0]
  theta_B = priors[1]
  #E step
  for observation in observations:
    len_observation = len(observation)
    num_heads = observation.sum()
    num_tails = len_observation-num_heads
    #二项分布求解公式
    contribution_A = scipy.stats.binom.pmf(num_heads,len_observation,theta_A)
    contribution_B = scipy.stats.binom.pmf(num_heads,len_observation,theta_B)

    weight_A = contribution_A / (contribution_A + contribution_B)
    weight_B = contribution_B / (contribution_A + contribution_B)
    #更新在当前参数下A,B硬币产生的正反面次数
    counts['A']['H'] += weight_A * num_heads
    counts['A']['T'] += weight_A * num_tails
    counts['B']['H'] += weight_B * num_heads
    counts['B']['T'] += weight_B * num_tails

  # M step
  new_theta_A = counts['A']['H'] / (counts['A']['H'] + counts['A']['T'])
  new_theta_B = counts['B']['H'] / (counts['B']['H'] + counts['B']['T'])
  return [new_theta_A,new_theta_B]

EM算法主循环

给定循环的两个终止条件:模型参数变化小于阈值;循环达到最大次数,就可以写出EM算法的主循环了

def em(observations,prior,tol = 1e-6,iterations=10000):
  """
  EM算法
  :param observations :观测数据
  :param prior:模型初值
  :param tol:迭代结束阈值
  :param iterations:最大迭代次数
  :return:局部最优的模型参数
  """
  iteration = 0;
  while iteration < iterations:
    new_prior = em_single(prior,observations)
    delta_change = numpy.abs(prior[0]-new_prior[0])
    if delta_change < tol:
      break
    else:
      prior = new_prior
      iteration +=1
  return [new_prior,iteration]

调用

给定数据集和初值,就可以调用EM算法了:

print em(observations,[0.6,0.5])

得到

[[0.72225028549925996, 0.55543808993848298], 36]

我们可以改变初值,试验初值对EM算法的影响。

print em(observations,[0.5,0.6])

结果:

[[0.55543727869042425, 0.72225099139214621], 37]

看来EM算法还是很健壮的。如果把初值设为相等会怎样?

print em(observations,[0.3,0.3])

输出:[[0.64000000000000001, 0.64000000000000001], 1]

显然,两个值相加不为1的时候就会破坏这个EM函数。

换一下初值:

print em(observations,[0.99999,0.00001])

输出:[[0.72225606292866507, 0.55543145006184214], 33]

EM算法对于参数的改变还是有一定的健壮性的。

以上是根据前人写的博客进行学习的~可以自己动手实现以下,对于python练习还是有作用的。希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python文档生成工具pydoc使用介绍
Jun 02 Python
Python使用logging模块实现打印log到指定文件的方法
Sep 05 Python
python 利用pandas将arff文件转csv文件的方法
Feb 12 Python
Python实现求两个数组交集的方法示例
Feb 23 Python
python实现两张图片拼接为一张图片并保存
Jul 16 Python
Django中reverse反转并且传递参数的方法
Aug 06 Python
python实现的批量分析xml标签中各个类别个数功能示例
Dec 30 Python
python 实现从高分辨图像上抠取图像块
Jan 02 Python
Python函数生成器原理及使用详解
Mar 12 Python
Python unittest基本使用方法代码实例
Jun 29 Python
matplotlib bar()实现百分比堆积柱状图
Feb 24 Python
Python学习之时间包使用教程详解
Mar 21 Python
Python+树莓派+YOLO打造一款人工智能照相机
Jan 02 #Python
matplotlib绘制动画代码示例
Jan 02 #Python
Python+matplotlib+numpy实现在不同平面的二维条形图
Jan 02 #Python
Python 实现淘宝秒杀的示例代码
Jan 02 #Python
python基于twisted框架编写简单聊天室
Jan 02 #Python
python http接口自动化脚本详解
Jan 02 #Python
详解用python实现简单的遗传算法
Jan 02 #Python
You might like
ThinkPHP中的常用查询语言汇总
2014/08/22 PHP
WordPress中访客登陆实现邮件提醒的PHP脚本实例分享
2015/12/14 PHP
详解PHP对象的串行化与反串行化
2016/01/24 PHP
PHP实现可自定义样式的分页类
2016/03/29 PHP
jQuery中文入门指南,翻译加实例,jQuery的起点教程
2007/01/13 Javascript
javascript showModalDialog,open取得父窗口的方法
2010/03/10 Javascript
Chosen 基于jquery的选择框插件使用方法
2012/05/30 Javascript
jquery获得页面元素的坐标值实现思路及代码
2013/04/15 Javascript
基于JQuery 滑动与动画的说明介绍
2013/04/18 Javascript
jQuery获取选中内容及设置元素属性的方法
2014/07/09 Javascript
AngularJS自定义插件实现网站用户引导功能示例
2016/11/07 Javascript
详解JavaScript常量定义
2017/01/03 Javascript
BootStrap的select2既可以查询又可以输入的实现代码
2017/02/17 Javascript
通俗易懂地解释JS中的闭包
2017/10/23 Javascript
Vue中render函数的使用方法
2018/01/31 Javascript
echarts同一页面中四个图表切换的js数据交互方法示例
2018/07/03 Javascript
在vue中给列表中的奇数行添加class的实现方法
2018/09/05 Javascript
微信小程序之事件交互操作实例分析
2018/12/03 Javascript
vue响应式系统之observe、watcher、dep的源码解析
2019/04/09 Javascript
前端深入理解Typescript泛型概念
2020/03/09 Javascript
Vue中el-form标签中的自定义el-select下拉框标签功能
2020/04/20 Javascript
Python基础入门之seed()方法的使用
2015/05/15 Python
Python编程实现线性回归和批量梯度下降法代码实例
2018/01/04 Python
PyQtGraph在pyqt中的应用及安装过程
2019/08/04 Python
简单了解为什么python函数后有多个括号
2019/12/19 Python
对Matlab中共轭、转置和共轭装置的区别说明
2020/05/11 Python
如何真正的了解python装饰器
2020/08/14 Python
PHP如何去执行一个SQL语句
2016/03/05 面试题
外贸业务员求职信
2014/06/16 职场文书
2014财务年度工作总结
2014/11/11 职场文书
大学生心理健康活动总结
2015/05/08 职场文书
《角的度量》教学反思
2016/02/18 职场文书
创业计划书之废品回收
2019/09/26 职场文书
Memcached介绍及php-memcache扩展安装
2021/04/01 PHP
postgreSQL数据库基础知识介绍
2022/04/12 PostgreSQL
Windows Server 2012 R2服务器安装与配置的完整步骤
2022/07/15 Servers