通过Python实现马尔科夫链蒙特卡罗方法的入门级应用


通过把马尔科夫链蒙特卡罗(MCMC)应用于一个具体问题,本文介绍了 Python 中 MCMC 的入门级应用。


GitHub 地址:https://github.com/WillKoehrsen/ai-projects/blob/master/bayesian/bayesian_inference.ipynb


过去几月中,我总是反复遇到同一个数据科学术语:马尔科夫链蒙特卡罗(Markov Chain Monte Carlo/MCMC)。每当我在实验室、博客、文章中听到这个概念,我常常点头赞同,觉得它很酷,但实际上并没有一个清晰的认知。有几次我尝试着学习 MCMC 和贝叶斯推理,我每次从阅读书籍开始,结果却很快放弃。我感到很恼怒,于是决定转向一种学习任何新技能的最佳方法:将它应用于一个具体问题。


使用我的睡眠数据(我一直打算对此一探究竟)和一本实际应用的书(Bayesian Methods for Hackers),我终于通过一个实际问题学习了马尔科夫链蒙特卡罗。像往常一样,比起阅读抽象的概念,将这些技术应用到具体问题中能让学习变得更简单、更愉快。本文介绍了 Python 中的马尔科夫链蒙特卡罗的入门级应用,正是它教会了我使用这个强大的建模分析工具。


我鼓励大家参阅 GitHub,并将其用于自己的数据当中。本文将重点介绍它的应用和结果,所以会产生很多高层次的话题。如果你在阅读后想了解更多,可以阅读文中提供的链接。


简介


我的 Garmin Vivosmart 手表可以根据心率和运动情况追踪我的睡眠和起床状况。它并非 100%准确,不过真实数据从不完美,我们仍然可以借助正确的模型从噪声数据中提取有用的知识!


典型的睡眠数据


本项目的目标是借助睡眠数据创建一个模型,通过把睡眠看作时间函数,而确定睡眠的后验概率。由于时间是连续变量,确定整个后验分布非常棘手。因此我们转而使用一些可实现近似分布的方法,比如马尔可夫链蒙特卡罗(MCMC)。


选择一个概率分布


在开始使用 MCMC 之前,我们需要确定一个合适的函数来对睡眠的后验概率分布进行建模。一个简单的方法是直观检查这些数据。对于我的睡眠的时间函数的观察如下图所示。


睡眠数据


上图中,每个数据点都用点表示,点的强度显示在特定时间的观测数量。我的手表只能记录我入睡的那一分钟,所以为了扩大数据量,我在精确时间的两边增加以分钟为单位的数据点。举例而言,如果我的手表显示我在晚上 10:05 入睡,那么 10:05 之前的每一分钟都被表示为 0(清醒),10:05 之后的每一分钟都被表示为 1(睡着)。这将大约 60 个夜晚的观测数据扩展到了 11340 个数据点。


我们可以发现,我一般在晚上 10 点之后入睡。但是我们想创建一个模型,以概率的形式捕捉从清醒到入睡的过渡过程。我们可以在模型中使用一个简单的阶跃函数,它在一个精确的时间从唤醒(0)过渡成入睡(1),但是这无法表现数据的不确定性。我不可能在每天晚上的同一时间睡觉,因此需要一个能模拟过渡过程的函数对这一渐进过程进行建模,显示变化特性。给定上述数据的情况下,我们的最佳选择是在 0 和 1 的边界之间平滑过渡的 logistic 函数。以下是睡眠概率作为时间函数的 logistic 方程:



其中,β 和 α 是我们在 MCMC 过程中必须学习的模型参数。具有不同参数的 logsitic 函数图像如下所示。



logsitic 函数很适合本案例中的数据,因为入睡的可能性会逐渐转变,此函数能捕捉睡眠模式之中的变化情况。我们希望能够在函数中插入时间 t,获得睡眠概率(其值在 0 和 1 之间)。我们最终得到的不是在晚上 10:00 入睡与否的直接答案,而是一个概率。为了建立这个模型,我们使用这些数据,通过 MCMC 寻找最佳的 α 和 β 参数。


马尔科夫链蒙特卡罗


马尔可夫链蒙特卡罗指从概率分布中抽样以构建最大可能分布的一类方法。我们不能直接构建 logistic 分布,所以,与之相反,我们为函数的参数(α 和 β)生成了上千个值——被称为样本——从而创造分布的近似值。MCMC 背后的思想是,当我们生成更多的样本时,我们的近似值越来越接近实际的真实分布。


马尔科夫链蒙特卡罗方法分为两部分。蒙特卡罗指的是使用重复随机样本获得数值解的一般性技术。蒙特卡罗可以被视为进行了若干次实验,其中每次都对模型中的变量进行改变并观察其响应。通过选择随机数,我们可以探索大部分参数空间,即变量可能值的范围。下图显示了我们的问题使用正常先验后的参数空间。



显然,我们无法一一尝试图像中的每一个点。但是通过对较高概率区域(红色区域)进行随机抽样,我们可以为问题建立最可能的模型。


马尔科夫链


马尔科夫链是一个随机过程,其中次态仅依赖于当前状态(在此语境中,一个状态指的是参数的一次赋值)。马尔科夫链没有记忆性,因为只有当前状态对下一状态起作用,而与到达当前状态的方式无关。如果这种说法还是有些难以理解,我们可以用日常现象中的天气来举例。如果我们想预测明日天气,我们可以仅通过今日天气来得到一个合理的估计。如果今天下雪了,我们可以查看下雪次日天气分布的历史数据,估算明天天气的概率。马尔科夫链的概念在于,我们无需了解整个历史过程就能预测下一状态,这个近似在许多现实情况中就能很好地工作。


综合马尔科夫链和蒙特卡罗的思想,马尔科夫链蒙特卡罗是一种基于当前值重复绘制某一分布参数随机值的方法。每个值的样本都是随机的,但是值的选择受限于当前状态和假定的参数先验分布。MCMC 可以被认为是一种随机游走,在这个过程中逐渐收敛到真实分布。


为了绘制 α 和 β 的随机值,我们需要假设这些值的先验分布。由于我们对参数没有任何提前的假设,我们可以使用正态分布。正态分布也称高斯分布,它由均值和方差定义,分别显示数据的位置以及扩散情况。下图是具有不同均值和方差的几种正态分布:



我们所使用的 MCMC 算法被称为 Metropolis Hastings。为了将我们观察的数据与模型联系起来,每绘制一组随机值,算法会根据数据对其进行评估。如果随机值与数据不一致(这里稍微进行了一些简化),这些值将被拒绝,模型保持当前状态。反之,如果随机值与数据一致,这些值将会分配给参数并成为当前状态。该过程将持续进行指定的步骤数目,模型的准确率也随着步骤数量的增加而改善。


综合而言,马尔科夫链蒙特卡罗在我们的问题当中基本步骤如下:


  1. 为 logistic 函数选择一组初始参数 α 和 β。

  2. 根据当前状态,把新的随机值分配给 α 和 β。

  3. 检查新的随机值是否与观察结果一致。如果不一致,拒绝这些随机值并返回前一个状态。如果一致,则接受这些值,将其作为新的当前状态。

  4. 对指定的迭代次数重复执行步骤 2 和 3。


该算法将返回它为 α 和 β 生成的所有值。然后,我们可以使用这些值的平均值作为 logistc 函数中 α 和 β 的最终可能值。MCMC 无法返回「真实」值,它给出的是分布的近似值。给定数据的情况下,最终输出的睡眠概率模型将是具有 α 和 β 均值的 logistic 函数。


Python 实现


上述细节在我脑海中徘徊已久,最后终于在 Python 中进行了实现!亲眼看到第一手的结果比读取别人的描述有帮助得多。要在 Python 中实现 MCMC,我们需要使用 PyMC3 贝叶斯推理库。它将大部分细节进行了抽象,从而让我们能不迷失在理论中,并建立我们的模型。


下面的代码创建的模型带有参数 α 和 β、概率 p 和观察结果 observed。step 变量指的是特定的算法,sleep_trace 则保存了模型生成的所有参数值。


  1. with pm.Model() as sleep_model:

  2.    # Create the alpha and beta parameters

  3.    # Assume a normal distribution

  4.    alpha = pm.Normal('alpha', mu=0.0, tau=0.05, testval=0.0)

  5.    beta = pm.Normal('beta', mu=0.0, tau=0.05, testval=0.0)

  6.    # The sleep probability is modeled as a logistic function

  7.    p = pm.Deterministic('p', 1. / (1. + tt.exp(beta * time + alpha)))

  8.    # Create the bernoulli parameter which uses observed data to inform the algorithm

  9.    observed = pm.Bernoulli('obs', p, observed=sleep_obs)

  10.    # Using Metropolis Hastings Sampling

  11.    step = pm.Metropolis()

  12.    # Draw the specified number of samples

  13.    sleep_trace = pm.sample(N_SAMPLES, step=step);


(请在 notebook 中查阅完整代码)


为了了解运行此代码时发生的情况,我们可以查看模型运行过程中生成的 α 和 β 的所有值。



它们被称为轨迹图。我们可以看到,每个状态都与之前的状态有关(马尔科夫链),但是这些值波动显著(蒙特卡罗采样)。


在 MCMC 中,通常高达 90% 的轨迹会被抛弃。该算法无法立即收敛到真正的分布,且初始值往往并不准确。后期的参数值通常更好,这意味着它们是适用于建立模型的参数。我们使用了 10000 个样本并丢弃了前 50%,但是一个行业的应用可能会使用数十万甚至上百万个样本。


给定足够多的迭代次数,MCMC 将收敛于真实值。但是,对收敛进行评估可能比较困难。对此我将不在本文讨论(一个方法是测量轨迹的自相关),但是,如果我们想要结果最准确,这是一个重要的考虑因素。PyMC3 建立了评估模型好坏的函数,其中包括轨迹图和自相关图。


  1. pm.traceplot(sleep_trace, ['alpha', 'beta'])

  2. pm.autocorrplot(sleep_trace, ['alpha', 'beta'])


轨迹图(左)和自相关图(右)


睡眠模型


最终建立并运行模型之后,是时候使用结果了。我们将最后 5000 个 α 和 β 样本的平均值作为参数最可能的值,这就让我们能够创建一条曲线,建模睡眠后验概率:



该模型能很好地反映数据的结果。此外,它捕捉了我睡眠模式当中的固有变化。该模型给出的不是一个简单的是非答案,而是一个概率。例如,我们可以通过该模型找到在给定时间我睡着的概率,并能找到睡眠概率经过 50% 的时间:


  1. 9:30  PM probability of being asleep: 4.80%.

  2. 10:00 PM probability of being asleep: 27.44%.

  3. 10:30 PM probability of being asleep: 73.91%.

  4. The probability of sleep increases to above 50% at 10:14 PM.


尽管我每天都试图在 10 点上床睡觉,但这显然不是大多数下的实际情况。我们可以发现,我上床的平均时间是晚上 10:14 左右。


在数据给定的情况下,这些值是最有可能的估计值。然而,因为模型本身是近似的,所以存在与这些概率相关的不确定性。为了表示这种不确定性,我们可以使用所有的 α 和 β 样本(而不是它们的平均值)来预测某一给定时间的睡眠概率,然后据此绘制直方图。



这些结果更好地反映了 MCMC 模型真正做了什么。MCMC 找到的不是一个简单的答案,而是可能值的样本。贝叶斯推理在现实世界中起到了重要作用,是因为它从概率的角度表示预测结果。我们可以说,问题会有一个可能性最大的答案,但是更加准确的回应是任何预测都存在一系列的可能值。


唤醒模型


我可以使用描述早晨醒来时间的数据建立一个类似的模型。我定了一个闹钟,努力在早晨 6:00 起床。但是可以看到,我并非每日都是如此。下图展现了我从入睡到醒来过渡过程的最终模型以及观察数据。



通过查询模型,我们可以找出在给定时间我睡着的概率以及最有可能醒来的时间。


  1. Probability of being awake at 5:30 AM: 14.10%.

  2. Probability of being awake at 6:00 AM: 37.94%.

  3. Probability of being awake at 6:30 AM: 69.49%.

  4. The probability of being awake passes 50% at 6:11 AM.


看起来我得处理一下我的闹钟了!


睡眠时长


出于好奇心和练习目的,我最终想创造的是关于我睡眠时长的模型。首先,我们需要找到一个函数来模拟数据的分布。我猜想结果应该会是正态分布的形式,但是我们只有通过检查数据才能得到最终结果。



正态分布确实可行,但这无法捕捉右侧的偏离点(即我睡眠时间非常长的情况)。我们可以用两个独立的正态分布来表示两个模型,但是,我想使用偏正态分布。偏正态分布有三个参数:均值、方差、偏斜度 α。以上三个参数都需要通过 MCMC 来学习。下面的代码建立了上述模型,并进行了 Metropolis Hastings 抽样。


  1. with pm.Model() as duration_model:

  2.    # Three parameters to sample

  3.    alpha_skew = pm.Normal('alpha_skew', mu=0, tau=0.5, testval=3.0)

  4.    mu_ = pm.Normal('mu', mu=0, tau=0.5, testval=7.4)

  5.    tau_ = pm.Normal('tau', mu=0, tau=0.5, testval=1.0)

  6.    # Duration is a deterministic variable

  7.    duration_ = pm.SkewNormal('duration', alpha = alpha_skew, mu = mu_,

  8.                              sd = 1/tau_, observed = duration)

  9.    # Metropolis Hastings for sampling

  10.    step = pm.Metropolis()

  11.    duration_trace = pm.sample(N_SAMPLES, step=step)


现在,我们可以使用这三个参数的均值来构建最有可能的分布。以下是根据数据观察得到的最终偏正态分布。



看起来拟合得不错!我们可以通过查询模型,找到我至少可以获得一定睡眠时长的概率,同时也能找到最可能的睡眠时长:


  1. Probability of at least 6.5 hours of sleep = 99.16%.

  2. Probability of at least 8.0 hours of sleep = 44.53%.

  3. Probability of at least 9.0 hours of sleep = 10.94%.

  4. The most likely duration of sleep is 7.67 hours.


我对这个结果并不是完全满意,但是对一个研究生而言,这样的结果已经不错啦。


小结


这个项目的顺利完成再次展示了解决问题的重要性,而且我们最好选择解决真实存在的应用问题(https://towardsdatascience.com/how-to-master-new-skills-656d42d0e09c)。在使用马尔科夫链蒙特卡罗构建贝叶斯推理的端对端实现过程中,我学习了许多基础知识,而且非常享受这个过程。我不仅更加了解我的习惯(以及我需要改进的方面),而且终于弄明白了 MCMC 和贝叶斯推理到底是什么。在数据科学领域,我们要不断地给自己的库存知识增加新的工具,而最有效的学习方法就是找到一个问题并着手开始解决它! 


原文链接:https://towardsdatascience.com/markov-chain-monte-carlo-in-python-44f7e609be98


文章版权归原作者所有,转载仅供学习使用,不用于任何商业用途,如有侵权请留言联系删除,感谢合作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/303946.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

315曝光不良奸商 对企业不能罚酒三杯

3月15日,315晚会又曝光了一批无良奸商,虽然315晚会年年曝光,各地政府也迅速跟进打击,但侵害消费者权益的情况却屡见不鲜。从被曝光企业的道歉信来看,“承认错误只是个别问题全面排查整改配合管理部门执法向消费者表示道…

.NET 产品版权保护方案 (.NET源码加密保护)

一. 前言大家好,我是康世杰,大家可以叫我Jason。我和大家一样,都是搞技术出身,也未当过讲师,所以口材有限,如果讲得不好之处,还希望大家多多海含,谢谢。今天是我们第一次见面&…

java地图 热力图,腾讯地图数据可视化之热力图

前言数据可视化API(Web),是基于腾讯位置服务JavaScript API GL实现的专业地理空间数据可视化渲染引擎。 通过这套API,可以实现轨迹数据、坐标点数据、热力、迁徙、航线等空间数据的可视化展现。使用步骤1、注册成为腾讯位置服务开发者,并进入…

建模分析师与算法工程师的主要区别

大家晚上好,我是新来的实习生小模君,前几天小智老师给我科普了数据挖掘的基础知识,颇有收获,于是就趁小天今天有事休假冒个泡跟大家分享一番。数据挖掘,英文名叫Data mining,一般是指从大型数据库中将隐藏的…

Flurl使用Polly实现重试Policy

❝在使用Flurl作为HttpClient向Server请求时,由于网络或者其它一些原因导致请求会有失败的情况,比如HttpStatusCode.NotFound、HttpStatusCode.ServiceUnavailable、HttpStatusCode.RequestTimeout等;网络上有比较多的HttpClientFactory使用P…

推荐15个 JavaScript 和 CSS 库

Tutorialzine的使命是让开发者与最新的Web开发发展同步。因此,我们每月都会精选一批最优秀的资源推荐给大家,相信这些资源你绝对值得拥有!ClarifyJSClarifyJS可以让你串联一串方法,以任意顺序执行。通常的JavaScript方法是从左到右…

Dapr Meetup 3.22【周六】

点击蓝字关注我们Dapr(Distributed Application Runtime ,分布式应用运行时)是微软新推出的,一个可移植的、由事件驱动的运行时,用于跨云和边缘构建分布式应用程序。2019年10月9日,正式以 MIT 协议开源。…

日本老爷爷坚持17年用Excel作画,我可能用了假的Excel···

本文来源自网络说起办公软件Excel,不少人可能同小编一样,谈及色变。想想公式、表格头都大了,今天要介绍的这个人竟然可以用其作画,简直是大写的“丧心病狂”!这位传奇人物就是堀内辰男,今年已经77岁了&…

腾讯二面挂了,就因为这个...

牛年跳槽季,惨遭开门黑,谨以此文纪念我的首次腾讯面试经历。经我的老师,微软MVP大佬推荐,有幸拿到了腾讯.NET Core高开面试机会,二面却挂在一个最常见的问题上,“你上家公司电商平台的TPS、QPS是多少&#…

51CTO博客 NO.1 大奖赛之后感想---奖品

自从加入51cto技术成就梦想这个大家庭以来,进入这个大家庭可以说是个机会,也可以是个缘分;已经有半年了,明朗炽热般的心,使我深深地喜欢上了这一个大家庭;这个大家庭是一个很不平凡而又富有源源不断学而不尽…

入门 | 我们常听说的置信区间与置信度到底是什么?

机器学习本质上是对条件概率或概率分布的估计,而这样的估计到底有多少是置信度?这里就涉及到统计学里面的置信区间与置信度,本文简要介绍了置信区间这一核心概念,它有助于我们从直观上理解评价估计优劣的度量方法。本文讨论了统计…

.NET 差点不叫“.NET”?微软大牛爆料技术往事

作者 | 伍杏玲出品 | CSDN(ID:CSDNnews)2000 年注定是不平凡的一年:千年虫问题爆发、互联网泡沫破灭……正值世界风云突变之际,比尔盖茨和史蒂夫鲍尔默向全球宣布全力打造“下一代因特网”——.NET 平台。比尔盖茨对.N…

【翻译】WPF 中附加行为的介绍 Introduction to Attached Behaviors in WPF

【翻译】WPF 中附加行为的介绍 Introduction to Attached Behaviors in WPF目录 隐藏 引言 [Introduction]背景 [Background]附加行为 [Attached Behaviors]论证 [Demonstration]结论 [Conclusion]参考 [References]版本历史 [Revision History]许可证 [License]作者&#xff…

地图是怎么知道实时路况的?因为我们每个人都是“百万年薪级”数据贡献者

【导读】地图公司给地图“上色”主要靠数据,数据够则地图生。数据是地图的生命,车速是路况的根本,地图获取数据主要有两种方式:自给自足、仰给于人上班出门,点开地图,前面红色,后面红色&#xf…

MySQL优化从执行计划开始(explain超详细)

前言小伙伴一定遇到过这样反馈:这页面加载数据太慢啦,甚至有的超时了,用户体验极差,需要赶紧优化;反馈等同于投诉啊,多有几次,估计领导要找你谈话啦。于是不得不停下手里头的活,赶紧…

一个老程序员的忠告:不要一辈子靠技术生存

图丨《Ready Player One》文丨源:世界经理人我现在是自己做,但我此前有多年在从事软件开发工作,当回过头来想一想自己,觉得特别想对那些初学JAVA/DOT。NET技术的朋友说点心里话,希望你们能从我们的体会中,多…

怎样安装php52-71,CentOS如何安装PHP5和PHP7

推荐(免费):PHP7安装PHP5下载解压二进制包[roottest-a src]# cd /usr/local/src/[roottest-a src]# wget http://cn2.php.net/distributions/php-5.6.32.tar.bz2[roottest-a src]# tar jxvf php-5.6.32.tar.bz2编译安装PHP./configure --prefix/usr/local/php --wit…

应用程序自动更新组件GeneralUpdate3.2.1发布

GeneralUpdate开源组件更新公告一、组件简介GeneralUpdate是基于.net standard开发的一款(c/s应用)自动升级程序。该组件将更新的核心部分抽离出来方便应用于多种项目当中目前适用于wpf,控制台应用,winfrom。本组件(除…

你不知道C#只带有 get 访问器的属性是只读属性?

问题窥探之前有个哥们在使用Newtonsoft.Json反序列化的时候,发现明明有数据,但是就是序列化不出来数据到实体里面。咋一看,确实没什么问题啊,字符串的数据是存在的。那么问题出在哪里呢。解决思路1、我让他把字符串复制出来&#…

葬身李刚儿子车轮下的漂亮女孩

这么一个青春、靓丽的女孩~~~~~~~~就这样丧生在官二代的铁轮下~~~~~~~~~~~~可惜了~~~~~~~~~~~~哀痛啊,什么世道!转载于:https://blog.51cto.com/jsfido/418494