从Scipy truncnorm.rvs生成的数据与指定的标准差不匹配

7cwmlq89  于 2022-11-10  发布在  其他
关注(0)|答案(2)|浏览(159)

我试图生成符合特定截断正态分布数据,基于herehere答案,我写道:

lower,upper,mu,sigma,N = 5,15,10,5,10000
samples = scipy.stats.truncnorm.rvs((lower-mu)/sigma,(upper-mu)/sigma,loc=mu,scale=sigma,size=N)
samples.std()

我得到的输出是

> 2.673

这显然与期望值5相差甚远。重复它并不会显著改变它,所以这不是样本量的问题。有什么建议吗?

fruv7luv

fruv7luv1#

事实上,截断正态分布降低了随机变量可能实现的变异性(从而降低了标准差),无论如何,我们知道它为什么不是5.0,但我们真的不知道它为什么应该是2.673;除了它更小的事实。
如果我们通过分析计算截断正态分布的精确标准差,并将其与检索到的经验值进行比较,会怎样?在这种情况下,您可以确保所有内容都符合要求。

from scipy import stats
from scipy.integrate import quad
import numpy as np
from matplotlib import pyplot as plt

# re-normalization constant (inverse of prob. of normal dist. on interval [lower, upper])

p = stats.norm.cdf(upper, loc=mu, scale=sigma) - stats.norm.cdf(lower, loc=mu, scale=sigma)

# plot

x_axis = np.linspace(0, 25, 10000)
plt.title('Truncated Normal Density', fontsize=18)
plt.plot(x_axis, scipy.stats.truncnorm.pdf(x_axis, (lower-mu)/sigma, (upper-mu)/sigma, loc=mu, scale=sigma))

plt.show()

示出了截断正态密度,暗指选择的区间[lower, upper]越窄,标准差将越小(甚至当lowerupper变得无限接近时渐近地接近0)。
让我们严格地确定一下,给定我们的(截断正态随机变量X)的期望值和方差的古老方程,我们有

然后,定义辅助函数

def xfx(x, lower=lower, upper=upper, mu=mu, sigma=sigma):
    '''helper function returning x*f(x) for the truncated normal density f'''
    return x*scipy.stats.truncnorm.pdf(x, (lower-mu)/sigma, (upper-mu)/sigma, loc=mu, scale=sigma)

def x_EX_fx(x, lower=lower, upper=upper, mu=mu, sigma=sigma):
    '''helper function returning (x - E[X])**2 * f(x) for the truncated normal density f'''
    EX = quad(func=xfx,a=lower,b=upper)[0]
    return ((x - EX)**2) * scipy.stats.truncnorm.pdf(x, (lower-mu)/sigma, (upper-mu)/sigma, loc=mu, scale=sigma)

让我们可以精确计算出


# E[X], expected value of X

quad(func=xfx,a=lower,b=upper)[0]
> 10.0

# (Var(X))^(1/2), standard deviation of X

np.sqrt(quad(func=x_EX_fx,a=lower,b=upper)[0])
> 2.697

这看起来与您的观察值2.673非常相似。让我们通过运行模拟研究来观察经验标准差是否接近理论值,以查看差异是否仅仅基于有限的样本大小。


# simulation study

np.random.seed(7447)
stdList = [scipy.stats.truncnorm.rvs((lower-mu)/sigma, (upper-mu)/sigma, loc=mu, scale=sigma, size=round(10**N)).std() for N in range(2,8)]

# plot

plt.title("Convergence behaviour of $\hat{σ}_{n}$ to σ", fontsize=18)
plt.plot(range(2,8), stdList)
plt.axhline(2.697800468774485, color='red', lw=0.85)
plt.legend({'emprical' : 'blue', 'theoretical' : 'red'}, fontsize=14)
plt.xlabel("$log_{10}(N)$", fontsize=14)
plt.show()

屈服的

这将确认您的输出是正确的,

hmae6n7t

hmae6n7t2#

这将在[5,15]之间生成一个剪切的正态分布。这是+/- 1 s.d,因此在该样本上测量的s.d.将不等于输入。
如果对输出范围进行限幅,则必然会降低观测到的标准差。
当下限/上限-〉+/-无穷大时,样本标准差-〉5。当下限/上限-〉10时,样本标准差-〉0。

相关问题