【问题标题】:Markov Chain montecarlo integration and infinite while loop马尔可夫链蒙特卡罗积分和无限while循环
【发布时间】:2020-05-14 23:28:31
【问题描述】:

我正在实现一个带有 Metropolis 和 barkes alpha 的马尔可夫链 Montecarlo,用于数值积分。我创建了一个名为MCMCIntegrator() 的类。我已经为它加载了一些属性,其中之一是我们试图集成的函数(一个 lambda)的 pdf,称为 g

import numpy as np
import scipy.stats as st


class MCMCIntegrator:

    def __init__(self):

        self.g = lambda x: st.gamma.pdf(x, 0, 1, scale=1 / 1.23452676)*np.abs(np.cos(1.123454156))
        self.size = 10000
        self.std = 0.6
        self.real_int = 0.06496359

这个类还有其他方法,size是类必须生成的样本大小,std是Normal Kernel的标准差,几秒钟后你就会看到。 real_int 是我们正在积分的函数从 1 到 2 的积分值。我用 R 脚本生成了它。现在,解决问题。

 def _chain(self, method=None):

        """
            Markov chain heat-up with burn-in

        :param method: Metrpolis or barker alpha
        :return: np.array containing the sample
        """
        old = 0
        sample = np.zeros(int(self.size * 1.5))
        i = 0

        if method:
            def alpha(a, b): return min(1, self.g(b) / self.g(a))

        else:
            def alpha(a, b): return self.g(b) / (self.g(a) + self.g(b))

        while i != len(sample):
            new = st.norm(loc=old, scale=self.std).rvs()
            new = abs(new)
            al = alpha(old, new)
            u = st.uniform.rvs()

            if al > u:
                sample[i] = new
                old = new
                i += 1

        return np.array(sample)

这个方法下面是一个integrate()方法,计算[1, 2]区间内数字的比例:

    def integrate(self, method=None):
        """
            Integration step

        """

        sample = self._chain(method=method)
        
        # discarding 30% of the sample for the burn-in
        ind = int(len(sample)*0.3)
        sample = sample[ind:]
        setattr(self, "sample", sample)

        sample = [1 if 1 < v < 2 else 0 for v in sample]
        return np.mean(sample)

这是主要功能:

def main():

    print("-- RESULTS --".center(20), end='\n')
    mcmc = MCMCIntegrator()
    print(f"\t{mcmc.integrate()}", end='\n')
    print(f"\t{np.abs(mcmc.integrate() - mcmc.real_int) / mcmc.real_int}")


if __name__ == "__main__":
    main()

我陷入了无限循环,我不知道为什么会这样。

【问题讨论】:

  • 代码无法如图所示执行。 _chain 中的 new 变量未定义。除此之外还有许多其他风格推荐......
  • ...将g 转换为类函数...标记 lambda 有点违背 lambda 的目的。您正在有条件地定义函数alpha,这是一种错误的形式。只需创建一个函数并将其发送输入以定义如何操作。稍后,您将 alpha 重新定义为变量,覆盖命名函数....
  • 我已经看到了变量的问题,我已经改变了它,就像我现在的代码一样,仍然存在同样的问题。我很高兴听到您更改代码的建议

标签: python numpy while-loop montecarlo markov-chains


【解决方案1】:

一些事情......你被链方法挂断了,因为 alpha 计算返回 NaN,因为 g() 返回 NaN。看看我插入到您的代码中的打印语句并运行它...

提示:

  1. chain一样让g()成为一个类函数。

  2. 在某些测试值上测试 g(),显然有问题

  3. 不要有条件地定义像alpha 这样的函数。 Wayyy 令人困惑且容易出错/难以排除故障。只需传递 alpha 所需的内容,您也可以将其设为类函数 alpha(a, b, method=None)
  4. 看看你在 `_chain' 函数中更新 i 的位置......你意识到你冒着漫长的循环过程的风险,因为你只是有条件地更新 i!
  5. 使用numpy 阵列,您已准备好应对灾难。您的实际数据之后可能有一堆尾随零,因为您正在覆盖大的零列表。您在这里不需要numpy 数组,只需使用 python 空列表并向其附加新值,无论是零还是一......基于任何内容。

在您进行故障排除(或对您的功能进行单元测试)时添加几个打印语句。试试我在下面添加到你的函数...这是我用来弄清楚发生了什么

def _chain(self, method=None, verbose=True):

    """
        Markov chain heat-up with burn-in

    :param method: Metrpolis or barker alpha
    :return: np.array containing the sample
    """
    old = 0
    sample = np.zeros(int(self.size * 1.5))
    i = 0

    if method:
        def alpha(a, b): return min(1, self.g(b) / self.g(a))

    else:
        def alpha(a, b): 
            if verbose: print(f'g(a): {self.g(a)}, g(b): {self.g(b)}')
            return self.g(b) / (self.g(a) + self.g(b))

    while i != len(sample):
        new = st.norm(loc=old, scale=self.std).rvs()
        new = abs(new)
        al = alpha(old, new)
        u = st.uniform.rvs()
        if verbose: print(f'old: {old:.3f} new: {new:.3f} alpha: {al:.3f} u: {u:.3f}')
        if al > u:
            sample[i] = new
            old = new
            i += 1              # do you really want to conditionally update i?
        sys.exit(-1)            # to breakout of infinite loop...


    return np.array(sample)

【讨论】:

  • 你不知道它对我有多大帮助,我真的很感激谢谢。
  • 感谢您的支持!我很高兴……祝你好运!
  • 进行了更改,程序更加流畅
猜你喜欢
  • 1970-01-01
  • 2014-09-26
  • 1970-01-01
  • 2021-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-15
相关资源
最近更新 更多