如何从剪裁的正态分布中进行采样?
我想从N(0, 1)
提取样本。但我希望值来自[-1, +1]
。我无法应用np.clip
,因为这会增加-1
和+1
的概率。我可以做随机剪裁,但是不能保证它会超出范围。
#standard
s = np.random.normal(0, 1, [10,10])
s = np.clip(s)
#stochastic
for j in range(10)
edge1 = np.where(s[j] >= 1.)[0]
edge2 = np.where(s[j] <= -1)[0]
if edge1.shape[0] > 0:
rand_el1 = np.random.normal(0, 1, size=(1, edge1.shape[0]))
s[j,edge1] = rand_el1
if edge2.shape[0] > 0:
rand_el2 = np.random.normal(0, 1, size=(1, edge2.shape[0]))
s[j,edge2] = rand_el2
答案 0 :(得分:2)
我认为最简单(也许不是最有效)的方法是使用基本的拒绝采样。它只是模拟来自N(0,1)
的值,拒绝那些超出所需边界的值并保留其他值直到它们堆叠到所需的样本数量。
kept = []
while len(kept) < 1000:
s = np.random.normal()
if -1 <= s <= 1:
kept.append(s)
这里我把东西堆放在一个基本列表中;随意使用np.array并根据数组的尺寸替换长度条件。
答案 1 :(得分:2)
scipy库将截断的正态分布实现为scipy.stats.truncnorm
。在您的情况下,您可以使用sample = truncnorm.rvs(-1, 1, size=sample_size)
。
例如,
In [55]: import matplotlib.pyplot as plt
In [56]: from scipy.stats import truncnorm, norm
从截断为[-1,1]的正态分布中取样100000个点:
In [57]: sample = truncnorm.rvs(-1, 1, size=100000)
制作直方图,并绘制理论PDF曲线。 PDF可以使用truncnorm.pdf
计算,也可以使用norm.pdf
的缩放版本计算。
In [58]: _ = plt.hist(sample, bins=51, normed=True, facecolor='g', edgecolor='k', alpha=0.4)
In [59]: x = np.linspace(-1, 1, 101)
In [60]: plt.plot(x, truncnorm.pdf(x, -1, 1), 'k', alpha=0.4, linewidth=5)
Out[60]: [<matplotlib.lines.Line2D at 0x11f78c160>]
In [61]: plt.plot(x, norm.pdf(x)/(norm.cdf(1) - norm.cdf(-1)), 'k--', linewidth=1)
Out[61]: [<matplotlib.lines.Line2D at 0x11f779f60>]
这是情节:
答案 2 :(得分:1)
迭代地进行stochiastic修剪,直到你不再需要它为止。这基本上意味着将您的if
转换为while
。您也可以借此机会将越界条件简化为单一检查,而不是单独检查每一方:
s = np.random.normal(0, 1, (10, 10))
while True:
out_of_bounds = np.abs(s) > 1
count = np.count_nonzero(out_of_bounds)
if count:
s[out_of_bounds] = np.random.normal(0, 1, count)
else:
break