创建概率分布的混合样本
问题内容:
是否存在加入SciPy(或NumPy)概率分布以创建可从中采样的混合概率分布的一般方法?
我有这样的分布显示使用类似:
mixture_gaussian = (norm.pdf(x_axis, -3, 1) + norm.pdf(x_axis, 3, 1)) / 2
如果再绘制则如下所示:
但是,我无法从此生成的模型中采样,因为它只是将绘制为曲线的点的列表。
注意,这种特定的分布只是一个简单的例子。我希望能够生成几种分布(包括不只是正态分布的“子”分布)。理想情况下,我希望该函数能够以某种方式自动归一化(即不必/ 2
像上面的代码中那样显式地进行该操作)。
SciPy / NumPy是否提供某种轻松实现此目的的方法?
这个答案提供了一种可以从多个分布中进行采样的方法,但是对于给定的混合物分布,当然需要一些手工,特别是当想要对不同的“子”分布进行不同的加权时。这是可用的,但我希望该方法可能更简洁,更直接。谢谢!
问题答案:
从分布的混合中采样(在其中添加了一些系数为c_1,c_2,…,c_n的PDF)相当于分别独立采样,然后对于每个索引,以概率c_k从第k个样本中选择值。
后者的混合步骤可以有效地完成numpy.random.choice
。这是混合三个分布的示例。分布在中列出distributions
,系数在中列出coefficients
。有一个胖正态分布,一个均匀分布和一个狭窄的正态分布,系数为0.5、0.2、0.3。根据给定的系数,混合发生在data[np.arange(sample_size), random_idx]
之后random_idx
。
import numpy as np
import matplotlib.pyplot as plt
distributions = [
{"type": np.random.normal, "kwargs": {"loc": -3, "scale": 2}},
{"type": np.random.uniform, "kwargs": {"low": 4, "high": 6}},
{"type": np.random.normal, "kwargs": {"loc": 2, "scale": 1}},
]
coefficients = np.array([0.5, 0.2, 0.3])
coefficients /= coefficients.sum() # in case these did not add up to 1
sample_size = 100000
num_distr = len(distributions)
data = np.zeros((sample_size, num_distr))
for idx, distr in enumerate(distributions):
data[:, idx] = distr["type"](size=(sample_size,), **distr["kwargs"])
random_idx = np.random.choice(np.arange(num_distr), size=(sample_size,), p=coefficients)
sample = data[np.arange(sample_size), random_idx]
plt.hist(sample, bins=100, density=True)
plt.show()