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中的__init__ 、__new__、__call__小结
Apr 25 Python
详细解析Python中的变量的数据类型
May 13 Python
Python base64编码解码实例
Jun 21 Python
python实现搜索本地文件信息写入文件的方法
Feb 22 Python
Python绘制堆叠柱状图的实例
Jul 09 Python
Python3.5 win10环境下导入kera/tensorflow报错的解决方法
Dec 19 Python
浅谈Python3实现两个矩形的交并比(IoU)
Jan 18 Python
Matplotlib自定义坐标轴刻度的实现示例
Jun 18 Python
python 牛顿法实现逻辑回归(Logistic Regression)
Oct 15 Python
Python3+SQLAlchemy+Sqlite3实现ORM教程
Feb 16 Python
Python语言规范之Pylint的详细用法
Jun 24 Python
python使用torch随机初始化参数
Mar 22 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
php中的实现trim函数代码
2007/03/19 PHP
php中使用Akismet防止垃圾评论的代码
2011/06/10 PHP
那些年我们错过的魔术方法(Magic Methods)
2014/01/14 PHP
php实现网页缓存的工具类分享
2015/07/14 PHP
PHP策略模式定义与用法示例
2017/07/27 PHP
Javascript 陷阱 window全局对象
2008/11/26 Javascript
JavaScript 学习小结(适合新手参考)
2009/07/30 Javascript
jquery 打开窗口返回值实现代码
2010/03/04 Javascript
javascript for循环从入门到偏门(效率优化+奇特用法)
2012/08/01 Javascript
javascript-简单的日历实现及Date对象语法介绍(附图)
2013/05/30 Javascript
Javascript中常见的校验如域名、手机、邮箱等等
2014/01/02 Javascript
几种经典排序算法的JS实现方法
2016/03/25 Javascript
JS加载iFrame出现空白问题的解决办法
2016/05/13 Javascript
JS+HTML5手机开发之滚动和惯性缓动实现方法分析
2016/06/12 Javascript
巧方法 JavaScript获取超链接的绝对URL地址
2016/06/14 Javascript
详解闭包解决jQuery中AJAX的外部变量问题
2017/02/22 Javascript
jQuery实现可兼容IE6的滚动监听功能
2017/09/20 jQuery
微信小程序第三方框架对比 之 wepy / mpvue / taro
2019/04/10 Javascript
使用Vue.js 和Chart.js制作绚丽多彩的图表
2019/06/15 Javascript
jQuery实现评论模块
2020/08/19 jQuery
python实现杨氏矩阵查找
2019/03/02 Python
python实现最大优先队列
2019/08/29 Python
Python生成个性签名图片获取GUI过程解析
2019/12/16 Python
挪威户外活动服装和装备购物网站:Bergfreunde挪威
2016/10/20 全球购物
List、Map、Set三个接口,存取元素时,各有什么特点?
2015/09/27 面试题
初中生物教学反思
2014/01/10 职场文书
刘胡兰的英雄事迹材料
2014/02/11 职场文书
创先争优个人承诺书
2014/08/30 职场文书
2014应届本科生自我评价
2014/09/13 职场文书
电子银行业务授权委托书
2014/10/10 职场文书
党的群众路线教育实践活动调研报告
2014/11/03 职场文书
2015年教师党员公开承诺书
2015/01/22 职场文书
房屋认购协议书
2015/01/29 职场文书
Python实现打乒乓小游戏
2021/09/25 Python
MySQL索引 高效获取数据的数据结构
2022/05/02 MySQL
SpringCloud超详细讲解Feign声明式服务调用
2022/06/21 Java/Android