【问题标题】:Obtain the value of the random variable given the cumulative probability (Python)在给定累积概率的情况下获取随机变量的值(Python)
【发布时间】:2020-12-05 12:10:50
【问题描述】:

这里是一个快速的背景信息。我正在尝试使用蒙特卡罗方法为两个对数正态随机变量的线性组合获得组合 CDF,然后将其反转以进行采样。这是执行相同操作的 Python 代码:

import numpy as np
from scipy import special


# parameters of distribution 1
mu1 = 0.3108
s1=0.3588

# parameters of distribution 2
mu2=1.2271
s2=0.2313

a = 2
b=3

N_sampling = 10000

kk=0

Y=np.zeros(N_sampling)
X1=np.zeros(N_sampling)
X2=np.zeros(N_sampling)

while(kk<N_sampling):
    F = np.random.rand(2)
    X1[kk]=np.exp(mu1+(2**0.5)*s1*special.erfinv(2*F[0]-1))  # sampling X1 (distribution1) by inverting the CDF
    X2[kk]=np.exp(mu2+(2**0.5)*s2*special.erfinv(2*F[1]-1))  # sampling X2 (distribution2) by inverting the CDF  
    
    Y[kk]=a*X1[kk]+b*X2[kk] # obtain the random variable as a linear combination of X1 and X2
    kk=kk+1
    

# Obtain the CDF of Y

freq, bin_borders = np.histogram(Y, bins=50)    
norm_freq = freq/np.sum(freq)
cdf_Y = np.cumsum(norm_freq)


# obtain the value of Y given the value of cdf_Y
cdf_Y_input=0.5
idx=np.searchsorted(cdf_Y,cdf_Y_input)
Y_out = 0.5*(bin_borders[idx-1]+bin_borders[idx])

问题:

scipy 中有直接的函数来执行这个操作吗?

在代码的最后一行,我取平均值,有没有办法通过插值等获得更准确的值?如果是这样,我如何在 Python 中实现它

【问题讨论】:

  • 你为什么要模拟对数正态分布?您可以使用 scipy 对两个累积对数正态进行平均。然后使用此函数反转函数:pypi.org/project/pynverse 进行采样。
  • 你能解释一下如何用 scipy 平均两个累积对数正态吗?
  • (lognorm.cdf(第一组参数) + lognorm.cdf(第二组参数))/2.平均积分是积分的平均值。
  • @LevB 这是错误的,你没有平均CDF,请检查我的答案
  • @Mechanician 目标只是做采样吗?我的意思是要问是否需要 CDF 用于采样以外的其他目的。感谢您提供任何信息。

标签: python statistics probability distribution probability-distribution


【解决方案1】:

如果您想从 2 个对数正态分布的总和中获取样本,则不需要蒙特卡洛方案。

import openturns as ot 
x1 = ot.LogNormal()
x1.setParameter(ot.LogNormalMuSigma()([0.3108, 0.3588, 0.0]))
# in order to convert mu, sigma into mulog and sigmalog

x2 = ot.LogNormal()
x2.setParameter(ot.LogNormalMuSigma()([1.2271, 0.2313, 0.0]))

x1 和 x2 之和本身就是一个分布

sum = x1+x2

您可以访问其平均值 sum.getMean()[0] (= 1.5379) 或其标准差 sum.getStandardDeviation()[0](= 0.42689241033309544)

当然,您可以获得任意大小 N 的样本 对于 N=5:sum.getSample(5)

print(sum.getSample(5))
0 : [ 1.29895 ]
1 : [ 1.32224 ]
2 : [ 1.259   ]
3 : [ 1.16083 ]
4 : [ 1.30129 ]

【讨论】:

    【解决方案2】:

    嗯,有一个众所周知的情况,当您将两个 RV X+Y 相加,知道 PDFX(x),PDFY(y) 并想知道PDFX+Y(z)。您可以在这里使用类似的方法,计算 PDF 并制作 CDF=d PDF(z)/dz

    PDFaX+bY(z) = S dy PDFY(y) PDFX((z-by)/a) / |一个|

    S 表示集成。

    您可以直接为 CDF 编写它

    CDFaX+bY(z) = S dy PDFY(y) CDFX((z-by)/a)

    你可以计算这个积分:

    1. 分析

    2. 数值上,使用SciPy

    3. 前后做傅里叶变换,类似Convolution

    4. 当然,蒙特卡洛积分始终是一种选择

    更新

    这里是最简单的代码让你开始

    import numpy as np
    from math import erf
    
    SQRT2 = np.sqrt(2.0)
    SQRT2PI = np.sqrt(2.0*np.pi)
        
    def PDF(x):
        if x <= 0.0:
            return 0.0
    
        q = np.log(x)
        return np.exp( - 0.5*q*q ) / (x * SQRT2PI)
    
    def CDF(x):
        if x <= 0.0:
            return 0.0
    
        return 0.5 + 0.5*erf(np.log(x)/SQRT2)    
    
    import scipy.integrate as integrate
    import matplotlib.pyplot as plt
    
    a = 0.4
    b = 0.6
    
    N = 101
    
    z = np.linspace(0.0, 5.0, N)
    c = np.zeros(N) # CDF of the sum
    p = np.zeros(N) # PDF of the sum
    t = np.zeros(N) # CDF as integral of PDF
    
    for k in range(1, N):
        zz = z[k]
        ylo = 0.0
        yhi = zz/b
    
        result = integrate.quad(lambda y: PDF(y) * CDF((zz - b*y)/a), ylo, yhi)
        print(result)
        c[k] = result[0]
    
        result = integrate.quad(lambda y: PDF(y) * PDF((zz - b*y)/a)/a, ylo, yhi)
        print(result)
        p[k] = result[0]
    
        t[k] = integrate.trapz(p, z) # trapezoidal integration over PDF
    
    
    plt.plot(z, c, 'b^') # CDF
    plt.plot(z, p, 'r.') # PDF
    plt.plot(z, t, 'g-') # CDF as integral over PDF
    plt.show()
    

    图表

    【讨论】:

    • 谢谢,但是两个对数正态的和没有封闭形式的解析解
    • @Mechanician 好吧,我会先看看通过 SciPy 的直接集成。下限为 0,上限也因 (z-by)/a 项而固定。
    • @Mechanician PDF = d/dx ( CDF) 当然,但您最好将它集成到 CDF 中。我已经更新了代码和绘图
    • @Mechanician 或者您甚至可以沿循环集成 PDF 以检查 CDF 是否正常。代码和图表已更新
    • @Mechanician 我在另一个问题答案中发布了如何从倒置 CDF 进行采样。你可能想看看stackoverflow.com/questions/63449211/…
    猜你喜欢
    • 2021-01-08
    • 2020-12-27
    • 2021-10-22
    • 1970-01-01
    • 2010-11-01
    • 1970-01-01
    • 2019-09-13
    • 1970-01-01
    • 2021-01-10
    相关资源
    最近更新 更多