Numpy 自定义Python Monte Carlo积分函数低估了多维积分

Numpy 自定义Python Monte Carlo积分函数低估了多维积分,numpy,probability,numerical-methods,montecarlo,numerical-integration,Numpy,Probability,Numerical Methods,Montecarlo,Numerical Integration,我需要创建一个自定义Monte Carlo积分函数,以适应使用NumPy的自定义多维分布对象。我需要它对每个维度中相同的值进行积分。它适用于单个维度,但低估了多个维度,随着维度的增加,情况会变得更糟。我用这个(方程式5)作为指导。我的体积公式*平均密度不正确吗?我的取样方法不正确吗?我真的不知道错误是什么 import numpy as np from scipy.stats import multivariate_normal # Set up distribution parameters

我需要创建一个自定义Monte Carlo积分函数,以适应使用NumPy的自定义多维分布对象。我需要它对每个维度中相同的值进行积分。它适用于单个维度,但低估了多个维度,随着维度的增加,情况会变得更糟。我用这个(方程式5)作为指导。我的体积公式*平均密度不正确吗?我的取样方法不正确吗?我真的不知道错误是什么

import numpy as np
from scipy.stats import multivariate_normal

# Set up distribution parameters.
dim = 3
loc = np.repeat(0., repeats=dim)
scale = np.repeat(1., repeats=dim)

# Initialize a multivariate normal distribution.
mvn = multivariate_normal(mean=loc, cov=scale)

def mc_integrator(distribution, dim, support, size=1000, seed=0):
    """
    Parameters
    ----------
    distribution : function
        A probability density function.
    dim : int
        The number of dimensions of the distribution.
    support : list
        List of the low and high values of the hypercube to integrate over.
    size : int, optional
        Number of samples used for estimation. The default is 1000.
    seed : int, optional
        A random seed for reproducibility. The default is 0.

    Returns
    -------
    float
        The estimate of the integral over the hypercube.
    """
    # Set the random seed.
    np.random.seed(seed)
    # Separate the elements of the support.
    a, b = support[0], support[1]
    # Calculate the volume of the hypercube.
    volume = (b-a)**dim
    # Generate random samples of the appropriate shape.
    samples = np.random.uniform(low=a, high=b, size=(size,dim))
    # Return the estimate of the integral.
    return volume*np.mean(distribution(samples))

# Set the number of samples to use for estimation.
size = 10000
# Set the low and high value over each dimension of the hypercube.
support = [-2, 2]
# Print the estimate of the integral.
print(mc_integrator(mvn.pdf, dim, support, size=size))
# Print the exact value of the integral.
print(mvn.cdf(np.repeat(support[1], dim))-mvn.cdf(np.repeat(support[0], dim)))

Output: 0.8523870204938726
        0.9332787601629401

约翰,整体看起来不错,但在我看来,你对预期结果的估计是错误的。我认为预期结果应该是
(F(2)-F(-2)^3
,其中
F
是均值0和方差1的高斯cdf。对于
F(2)-F(-2)
,我得到
erf(sqrt(2))
约为0.9545,然后
(F(2)-F(-2))^3
为0.8696,这与您的结果非常吻合

我不知道mvn.cdf应该返回什么,但是“cdf”的概念在不止一个维度上有点可疑,所以也许你可以避开它

关于一般的多维积分,你提到使用Halton序列。我认为这也是一个有趣的想法。我计算积分的经验是在1或2维中使用求积规则,在3到数维中使用低差异序列(5?7?我不知道)还有,我的建议是,在诉诸数值近似之前,要非常努力地获得精确的结果


我很想听听你在做什么。

约翰,整体看起来不错,但在我看来,你对预期结果的估计不正确。我认为预期结果应该是
(F(2)-F(-2)^3
,其中
F
是均值0和方差1的高斯cdf。对于
F(2)-F(-2),我得到
erf(sqrt(2))
约为0.9545,然后
(F(2)-F(-2))^3
为0.8696,这与您的结果非常吻合

我不知道mvn.cdf应该返回什么,但是“cdf”的概念在不止一个维度上有点可疑,所以也许你可以避开它

关于一般的多维积分,你提到使用Halton序列。我认为这也是一个有趣的想法。我计算积分的经验是在1或2维中使用求积规则,在3到数维中使用低差异序列(5?7?我不知道)还有,我的建议是,在诉诸数值近似之前,要非常努力地获得精确的结果


我很想听听你在做什么。

10000个样本对于MCI来说是非常低的。对于1000000个样本,它只有0.8694640813906446,所以仍然是低估。它似乎总是低估,MC有时也应该高于真实值。当你增加样本的维度时,低估问题会变得更严重分布,所以它必须与我如何处理多维有关。编辑:一旦我让天真的MC集成工作起来,我将添加使用Halton序列生成样本的选项,这将减少所需的样本数。10000个样本对于MCI来说非常少。1000000个样本只有0.8694640813906446,所以仍然是低估。它似乎总是低估,MC有时也应该高于真实值。随着分布维度的增加,低估问题会变得更严重,因此这一定与我如何处理多个维度有关。编辑:一旦我让天真的MC集成起作用,我将添加使用Halton序列生成样本的选项,这将减少所需的样本数量。感谢Robert,我假设我使用多变量_normal.cdf()的方式与(F[b]-F[a]的工作方式相同^#维度。不幸的是,我不能使用求积规则,因为我必须使用非常高的维度分布,所以运行时间会爆炸。我正在构建函数来使用耦合分布,并计算耦合熵、交叉熵和发散。要找到精确的结果很难,而且要使用数值近似允许我获得任何分布的近似结果。感谢Robert,我假设我使用多变量_normal.cdf()的方式与(F[b]-F[a]的工作方式相同^#维度。不幸的是,我不能使用求积规则,因为我必须使用非常高的维度分布,所以运行时间会爆炸。我正在构建函数来使用耦合分布,并计算耦合熵、交叉熵和发散。要找到精确的结果很难,而且要使用数值近似允许我获得任何分布的近似结果。