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

前言:前一篇文章大概说了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算法的第一步就是初始化的过程,然后根据这个参数得出应该产生的结果。

构建观测数据集

针对这个问题,首先采集数据,用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]])

第一步:参数的初始化

参数赋初值

第一个迭代的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练习还是有作用的。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

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

    前言:前一篇文章大概说了EM算法的整个理解以及一些相关的公式神马的,那些数学公式啥的看完真的是忘完了,那就来用代码记忆记忆吧!接下来将会对python版本的EM算法进行一些分析. EM的python实现和解析 引入问题(双硬币问题) 假设有两枚硬币A.B,以相同的概率随机选择一个硬币,进行如下的抛硬币实验:共做5次实验,每次实验独立的抛十次,结果如图中a所示,例如某次实验产生了H.T.T.T.H.H.T.H.T.H,H代表正面朝上. 假设试验数据记录员可能是实习生,业务不一定熟悉,造成a和b两种

  • 增大python字体的方法步骤

    1.点击开始菜单,打开IDLE程序. 2.默认字体大小给出一个直观的展示. 3.点击菜单栏的"Options". 4.然后在下拉菜单中选择"Configure IDLE". 5.默认字体是新宋体,大小是size=4. 6.对字体大小进行调整后,点击"确认". 7.这样,字体大小就进行了对应的调整. 到此这篇关于增大python字体的方法步骤的文章就介绍到这了,更多相关如何增大python字体内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家

  • 如何在vscode中安装python库的方法步骤

    vscode安装python库 1.已经在vscode中装了python并配置好python运行环境. 检查是否正确配置好运行环境,按Windows+R组合键在运行窗口输入cmd,打开命令提示符窗口输入python确定即可 2.找到vscode中python的路径 随便运行一个代码,例如print("hehe")下面的终端显示如下 图中红色地方圈起的便是python的路径,到python3.8为止. 如果你所显示的内容与我不同,可在setting.json中查找并将路径复制下来(在vs

  • JupyterNotebook设置Python环境的方法步骤

    使用Python时,常遇到的一个问题就是Python和库的版本不同.Anaconda的env算是解决这个问题的一个好用的方法.但是,在使用Jupyter Notebook的时候,我却发现加载的仍然是默认的Python Kernel.这篇博客记录了如何在Jupyter Notebook中也能够设置相应的虚拟环境. conda的虚拟环境 在Anaconda中,我们可以使用conda create -n your_env_name python=your_python_version的方法创建虚拟环境

  • 在win10和linux上分别安装Python虚拟环境的方法步骤

    很多初学者会使用windows作为开发机使用, 今天就来看下如何在win10和Linux下分别安装Python虚机环境.虚机环境有非常多的优点,今天我们用的虚拟环境是virtualenv. virtualenv用于创建独立的Python环境,多个Python相互独立,互不影响,它能够: 1. 在没有权限的情况下安装新套件 2. 不同应用可以使用不同的套件版本 3. 套件升级不影响其他应用 win10下安装 1. 打开cmd 安装虚拟环境包 pip install virtualenvwrappe

  • anaconda中更改python版本的方法步骤

    anaconda是一个非常好用的python发行版本,其中包含了大部分常用的库. 最新的anaconda中python版本已经更新到了python3.6,而tensorflow只支持python3.5. 在anaconda官网中已经给了三种解决方案: https://docs.anaconda.com/anaconda/faq#how-do-i-get-anaconda-with-python-3-5 方法一:在现有的anaconda中新建一个python3.5的开发环境,这样同时保留了pyth

  • pycharm中使用anaconda部署python环境的方法步骤

    今天来说一下python中一个管理包很好用的工具anaconda,可以轻松实现python中各种包的管理.相信大家都会有这种体验,在pycharm也是有包自动搜索和下载的功能,这个我在前面的一篇博客中有相关的介绍(详情请查看点击打开链接),但是这种功能对于一些包是可以使用的,但是总是会遇到有些包下载失败或查询不到的时候,这个时候就会让人很苦恼了.这里我们就来说一下anaconda的好处. 下面是我从别的地方贴来的说辞: Anaconda的优点总结起来就八个字:省时省心.分析利器. 省时省心: A

  • 使用pip发布Python程序的方法步骤

    写过 Python 程序的小伙伴们都知道,需要 import 个非 Python 自带的软件包时,都要用到 pip 这个程序.平时我们都是用 pip,如果我们写好了一个程序,想让大家都能用的到,那么是不是也可以通过 pip 发布出去呢? 答案当然是可以了,这篇文章我们就来看看如何用 pip 发布一个 python 程序. 1. 环境准备 要用 pip 发布 python 程序,首先当然是要安装 Python 和 pip 这两个软件了,以 Ubuntu 16.04 为例: $ sudo apt u

  • C#调用python脚本的方法步骤(2种)

    因项目需要,需要使用C#控制台程序执行python脚本,查询各种资料后可以成功调用了,记录一下,以备后面遗忘. 只尝试了两种调用方式,第一种只适用于python脚本中不包含第三方模块的情况,第二种针对的是python脚本中包含第三方模块的情况.不管哪种方式,首先都需要安装IronPython.我是通过vs2017的工具->NuGet包管理器->管理解决方案的NuGet包,搜索IronPython包安装,也可以在官网下载安装包自行安装后添加引用即可. 方式一:适用于python脚本中不包含第三方

  • 利用setuptools打包python程序的方法步骤

    一.准备工程文件 1.创建工程leeoo 2.在工程根目录下创建setup.py文件 3.在工程根目录下创建同名package 二.编辑setup.py 1.编辑setup.py文件 from setuptools import setup, find_packages setup( name='leeoo', # 包的名称 version='1.0', # 版本号 packages=find_packages(), # 动态获取packages description="leeoo packa

随机推荐