Python中高斯积分的数值评估?

计算科学 Python scipy 正交
2021-12-19 11:07:02

目标

我正在尝试编写代码来计算下面的归一化高斯,

(1)1σ2πexp((xμ)22σ2)dx

在哪里μ[10,10]

问题

不幸的是,积分算法不收敛并抛出警告:

FinalStat.py:68:IntegrationWarning:积分可能是发散的,或缓慢收敛的。

高斯应该归一化为(1),这似乎是 Quadpack 后端的问题。我想对此进行修复以使积分正常化为其正确值?

代码

from scipy.integrate import quad
import scipy.integrate as integrate
import numpy as np
import numpy
import random
import math

xvalues = []
yvalues = []
def generate():
    #=================================================================== #
    #                                                                    #
    #                 Generates Linear Data                              #
    #                a,b are random varibles                             #
    # ================================================================== #
    for i in range(0,10):
        a = random.randint(-10, 10)
        b = random.randint(-10, 10)
        xvalues.append(i)
        y = a * (b + i)
        yvalues.append(y)


def weighted_mean(yvalues):
    #=============================================#
    #          Computes the Weighted Mean         #
    #=============================================#
    y_i = np.array(yvalues)
    x_i = np.array(xvalues)
    evaulated_mean = sum(x_i*y_i) / len(y_i)
    return evaulated_mean

def weighted_variance(yvalues):
    #============================================#
    #       Computes the Weighted Variance       #
    #============================================#

    s =  []

    yvalues_mean = weighted_mean(yvalues)

    for y in yvalues:
        z = (y - yvalues_mean)**2
        s.append(z)
    #===================================#
    #s_i = value of the data set        #
    #v_i = Number of Data Points in Pop #
    #===================================#
    s_i = np.array(s)
    v_i = np.array(s)
    t = (sum(s_i*v_i)/len(v_i)) 
    print("The Variance", t)
    return t



def gaussian(sigma,mu, x):
    #===================================================#
    #Define and Compute Gaussian Function with the FWDM #
    #===================================================#   
    FWHM = 2*(numpy.sqrt(2*numpy.log(2)))*sigma
    k = 1 / (sigma * math.sqrt(2*math.pi))
    s = -1.0 / (2 * sigma * sigma)
    def f(x):
        return k * math.exp(s * (x - mu)*(x - mu))

    print("The corresponding FHWM", FWHM)
    print("The Integral is", quad(f, -np.inf, np.inf))
    return FWHM


generate()
print( "The Mean is =>" , weighted_mean(yvalues))
#weighted_variance(yvalues)
print("our Normal Distrubtion Equals" , gaussian(weighted_variance(yvalues), weighted_mean(yvalues), random.randint(-10,10)))

输出

The Mean is => -53.7
The Variance 18538654.5401
The corresponding FHWM 43655195.3189315
FinalStat.py:68: IntegrationWarning: The integral is probably divergent, or slowly convergent.print("The Integral is", quad(f, -np.inf, np.inf))
The Integral is (-4.3038967971581716e-08, 6.997796078221529e-13)
our Normal Distrubtion Equals 43655195.3189315
2个回答

无需正交;您的积分可以解析计算。为此,您必须进行变量转换y=(xμ)/2σ

kexp((xμ)22σ2)dx=k2σexp(y2)dy=2πkσ
(在您的情况下,random.seed(0)结果是-1.8286668122220665e-25解释了您遇到的数字困难。)

在代码的示例输出中,σ是巨大的,即高斯非常广泛。s您定义为相应指数参数的前置因子的变量只有11015,这危险地接近典型的双精度限制(添加10161具有典型的双精度,例如,仍然是1. scipy's quad相应地处理巨大和微小的数字将使得难以检测例如数字为零。

为了使数值积分稳定,适当缩放积分变量很重要:这里,σ是您的问题的典型长度尺度,并且希望用于积分的典型数值尺度为1(或者0.1, 要么10,或任何合理的数值大小)。积分变量的可能替换可能是u=(xμ)/σ(和dx=σdu)。然后积分将变为:

kexp((xμ)22σ2)dx=σkexp(u22)du.

def f2(u):
    return k*numpy.exp(-0.5*u**2)*sigma

使用原始积分f(x),我也发现quad失败并产生不正确的积分4108(使用相同的σ如问题中的示例输出所示,而不是另一个随机值),采用f2(u),quad产量1.

假设被积函数的变换不应该像上面那样简单(这基本上会导致具有“归一化”系数的高斯)。也可以定义u=x/σ,即不吸收由于μ在转换中(在这里有效,因为μ[10;10], 如果μ本身很大,确实最好使用前面的转换来避免数值不稳定)并使用以下被积函数:

def f3(u):
   return k*numpy.exp(-0.5*(u*sigma-mu)**2/sigma**2)*sigma 

其中,尽管由于μ在被积函数中,准确地产生1scipy's quad. 选择例如μ=1012后一种方法将失败,quad再次产生接近于0.

变量的变化u=xαdu=dxα通常可用于求积(和其他数值问题)以将积分核转换为数值上更易于处理的量级。