gpt4 book ai didi

python - 对数正态分布的均值和标准差与分析值不匹配

转载 作者:行者123 更新时间:2023-12-02 07:14:10 28 4
gpt4 key购买 nike

作为研究的一部分,我从对数正态分布测量平局的均值和标准差。给定基础正态分布的值,应该可以分析性地预测这些数量(如https://en.wikipedia.org/wiki/Log-normal_distribution所示)。

但是,如下图所示,情况似乎并非如此。第一个图显示了对数正态数据相对于高斯σ的均值,而第二个图显示了对数正态数据相对于高斯的σ。显然,“计算”线与“分析”线非常不同。

我将高斯分布的均值与mu = -0.5*sigma**2与sigma相关联,因为这确保了对数正态场的均值应为1。请注意,这是由我从事的物理学领域引起的:例如,如果设置mu=0.0,分析值仍然会发生。

通过将代码复制并粘贴到问题的底部,应该可以复制下面的图。任何有关可能导致此问题的建议将不胜感激!

对数正态与高斯西格玛的均值:
Mean of lognormal vs sigma of gaussian

对数正态的Sigma与高斯的Sigma:
Sigma of lognormal vs sigma of gaussian

注意,要生成上面的图,我使用了N=10000,但是为了提高速度在下面的代码中添加了N=1000

import numpy as np
import matplotlib.pyplot as plt

mean_calc = []
sigma_calc = []
mean_analytic = []
sigma_analytic = []
ss = np.linspace(1.0,10.0,46)
N = 1000

for s in ss:
mu = -0.5*s*s
ln = np.random.lognormal(mean=mu, sigma=s, size=(N,N))
mean_calc += [np.average(ln)]
sigma_calc += [np.std(ln)]
mean_analytic += [np.exp(mu+0.5*s*s)]
sigma_analytic += [np.sqrt((np.exp(s**2)-1)*(np.exp(2*mu + s*s)))]

plt.loglog(ss,mean_calc,label='calculated')
plt.loglog(ss,mean_analytic,label='analytic')
plt.legend();plt.grid()
plt.xlabel(r'$\sigma_G$')
plt.ylabel(r'$\mu_{LN}$')
plt.show()

plt.loglog(ss,sigma_calc,label='calculated')
plt.loglog(ss,sigma_analytic,label='analytic')
plt.legend();plt.grid()
plt.xlabel(r'$\sigma_G$')
plt.ylabel(r'$\sigma_{LN}$')
plt.show()

最佳答案

TL; DR

对数正态分布呈正偏态,尾部分布较重。当对从高度偏斜分布中抽取的样本执行浮点算术运算(例如求和,均值或标准差)时,采样向量将包含在几个数量级(数十年)内具有差异的值。这使得计算不准确。

问题来自这两行:

mean_calc += [np.average(ln)]
sigma_calc += [np.std(ln)]


因为 ln包含非常低和非常高的值,其数量级远高于浮点精度。

使用以下谓词可以很容易地检测到该问题,以警告用户其计算错误:

 (max(ln) + min(ln)) <= max(ln)


在严格正实数中这显然是错误的,但在使用有限精度算术时必须考虑。

修改您的MCVE

如果我们将您的 MCVE稍微修改为:

from scipy import stats

for s in ss:
mu = -0.5*s*s
ln = stats.lognorm(s, scale=np.exp(mu)).rvs(N*N)
f = stats.lognorm.fit(ln, floc=0)
mean_calc += [f[2]*np.exp(0.5*s*s)]
sigma_calc += [np.sqrt((np.exp(f[0]**2)-1)*(np.exp(2*mu + s*s)))]
mean_analytic += [np.exp(mu+0.5*s*s)]
sigma_analytic += [np.sqrt((np.exp(s**2)-1)*(np.exp(2*mu + s*s)))]


即使对于较高的sigma值,它也可以给出合理正确的均值和标准差估计。

enter image description here
enter image description here

关键是 fit使用MLE算法估计参数。这与您直接执行样本均值的原始方法完全不同。

fit方法返回带有 (sigma, loc=0, scale=exp(mu))的元组,该元组是文档中指定的 scipy.stats.lognorm对象的参数。

我认为您应该研究如何估算均值和标准差。差异可能来自算法的这一部分。

可能有多种原因,至少要考虑以下因素:


估算师偏爱:您的估算师正确无误吗?均值是无偏估计量(请参阅下一部分),但可能没有效率。
伪随机发生器的异常值可能不如理论分布那么强烈:MLE可能不如您的估计器敏感新的MCVE波纹管不支持此假设,但Float Arithmetic Error可以解释为什么您的估计器被低估了;
浮点运算错误新的MCVE波纹管突出显示它是问题的一部分。


科学报价

即使没有偏见,幼稚的均值估计器(简单地采用均值)似乎也无法有效地估计大sigma的均值(请参见Qi Tang, Comparison of Different Methods for Estimating Log-normal Means,第11页):


天真的估计量易于计算且无偏见。然而,
当方差较大且样本较多时,此估算器可能效率很低
尺寸很小。


本文回顾了几种估计对数正态分布均值的方法,并以MLE作为比较的参考。这就解释了为什么您的方法会随着sigma的增加而发生漂移,而MLE会更好地粘附,因为对于大的N而言,这没有时间效率。

统计考虑

回忆比:


Lognormalheavy且正尾偏正的长尾分布。一个结果是:随着形状参数sigma的增加,不对称和偏斜度也增加,离群值的强度也增加。
样本数量的影响:随着从分布中抽取的样本数量的增加,对异常值的期望也随之增加(程度也随之增加)。


enter image description here
enter image description here

建立一个新的MCVE

让我们构建一个新的MCVE使其更加清晰。下面的代码从形状参数变化( N100之间的 10000范围)并且将scale参数设置为的对数正态分布中绘制了不同大小( sigma0.1之间的 10范围)的样本。酉。

import warnings
import numpy as np
from scipy import stats

# Make computation reproducible among batches:
np.random.seed(123456789)

# Parameters ranges:
sigmas = np.arange(0.1, 10.1, 0.1)
sizes = np.logspace(2, 5, 21, base=10).astype(int)

# Placeholders:
rv = np.empty((sigmas.size,), dtype=object)
xmean = np.full((3, sigmas.size, sizes.size), np.nan)
xstd = np.full((3, sigmas.size, sizes.size), np.nan)
xextent = np.full((2, sigmas.size, sizes.size), np.nan)
eps = np.finfo(np.float64).eps

# Iterate Shape Parameter:
for (i, s) in enumerate(sigmas):
# Create Random Variable:
rv[i] = stats.lognorm(s, loc=0, scale=1)
# Iterate Sample Size:
for (j, N) in enumerate(sizes):
# Draw Samples:
xs = rv[i].rvs(N)
# Sample Extent:
xextent[:,i,j] = [np.min(xs), np.max(xs)]
# Check (max(x) + min(x)) <= max(x)
if (xextent[0,i,j] + xextent[1,i,j]) - xextent[1,i,j] < eps:
warnings.warn("Potential Float Arithmetic Errors: logN(mu=%.2f, sigma=%2f).sample(%d)" % (0, s, N))
# Generate different Estimators:
# Fit Parameters using MLE:
fit = stats.lognorm.fit(xs, floc=0)
xmean[0,i,j] = fit[2]
xstd[0,i,j] = fit[0]
# Naive (Bad Estimators because of Float Arithmetic Error):
xmean[1,i,j] = np.mean(xs)*np.exp(-0.5*s**2)
xstd[1,i,j] = np.sqrt(np.log(np.std(xs)**2*np.exp(-s**2)+1))
# Log-transform:
xmean[2,i,j] = np.exp(np.mean(np.log(xs)))
xstd[2,i,j] = np.std(np.log(xs))


观察: sigma > 4时,新的MCVE开始发出警告。

MLE作为参考

使用MLE估计形状和比例参数的效果很好:

enter image description here
enter image description here

上面的两个图显示:


估计误差与形状参数一起增长;
估计误差随着样本量的增加而减小( CTL);


请注意,MLE也非常适合shape参数:

enter image description here

浮点运算

绘制绘制样本的范围与形状参数和样本大小的关系是值得的:

enter image description here

或最小和最大数字之间的小数位数形成样本:

enter image description here

在我的设置中:

np.finfo(np.float64).precision  # 15
np.finfo(np.float64).eps # 2.220446049250313e-16


这意味着我们最多可以使用15个有效数字,如果两个数字之间的大小超出,那么最大的数字将吸收较小的数字。

一个基本的例子:如果我们只能保留四个有效数字, 1 + 1e6的结果是什么?
确切结果为 1,000,001.0,但必须四舍五入为 1.000e6。这意味着:由于舍入精度,运算的结果等于最大数。它是有限精度算法的固有特性。

上面的前两个图结合统计考虑因素,可以支持您观察到增加 N不会改善MCVE中较大的 sigma值的估计。

上图和下图显示的是 sigma > 3时,我们没有足够的有效数字(小于5)来执行有效的计算。

更进一步,我们可以说估计量将被低估,因为最大的数将吸收最小的量,然后被低估的总和将除以 N,使估计量默认为有偏差。

当形状参数变得足够大时,由于 Arithmetic Float Errors,计算将受到严重偏差。

这意味着使用诸如:

np.mean(xs)
np.std(xs)


在计算时,由于 xs中存储的值之间的重大差异,估计值将具有巨大的算术浮点误差。下图重现了您的问题:

enter image description here
enter image description here

如前所述,估计是默认值(不会过多),因为采样向量中的高值(少数异常值)会吸收小值(大部分采样值)。

对数转换

如果应用 logarithmic transformation,则可以大大减少这种现象:

xmean[2,i,j] = np.exp(np.mean(np.log(xs)))
xstd[2,i,j] = np.std(np.log(xs))


然后,对均值 is correct的天真的估计就不会受到算术浮点误差的影响,因为所有样本值都将在几十年之内,而不是相对大小高于浮点算术精度。

实际上,对于每个 Nsigma,采用对数变换得出的均值和标准差估计值均与MLE相同:

np.allclose(xmean[0,:,:], xmean[2,:,:])  # True
np.allclose(xstd[0,:,:], xstd[2,:,:]) # True


参考

如果要在进行科学计算时寻找此类问题的完整和详细的说明,我建议您 read the excellent book:N. J. Higham,《数值算法的准确性和稳定性》,Siam,第二版,2002年。

奖金

这里是图形生成代码的示例:

import matplotlib.pyplot as plt

fig, axe = plt.subplots()
idx = slice(None, None, 5)
axe.loglog(sigmas, xmean[0,:,idx])
axe.axhline(1, linestyle=':', color='k')
axe.set_title(r"MLE: $x \sim \log\mathcal{N}(\mu=0,\sigma)$")
axe.set_xlabel(r"Standard Deviation, $\sigma$")
axe.set_ylabel(r"Mean Estimation, $\hat{\mu}$")
axe.set_ylim([0.1,10])
lgd = axe.legend([r"$N = %d$" % s for s in sizes[idx]] + ['Exact'], bbox_to_anchor=(1,1), loc='upper left')
axe.grid(which='both')
fig.savefig('Lognorm_MLE_Emean_Sigma.png', dpi=120, bbox_extra_artists=(lgd,), bbox_inches='tight')

关于python - 对数正态分布的均值和标准差与分析值不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53651223/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com