在简单混合分布的情况下,您可以通过您首先提到的“hack”获得高效的采样器:
这种特殊情况可以通过选择一个分布或另一个分布来预先采样,但我想用一个分布来做,特别是因为我以后可能需要调整整体分布。
这实际上是一个吉布斯抽样的例子,在统计学中非常普遍。它非常灵活,如果你知道你使用的混合物的数量,它可能很难被击败。从整个集合中选择一个单独的分布进行采样,然后从该条件分布中进行采样。冲洗并重复。
这是一个简单的、未优化的 Haskell 实现,用于混合高斯 Gibbs 采样器。这是非常基本的,但你明白了:
import System.Random
import Control.Monad.State
type ModeList = [(Double, Double)] -- A list of mean/stdev pairs, for each mode.
-- Generate a Gaussian (0, 1) variate.
boxMuller :: StdGen -> (Double, StdGen)
boxMuller gen = (sqrt (-2 * log u1) * cos (2 * pi * u2), gen'')
where (u1, gen') = randomR (0, 1) gen
(u2, gen'') = randomR (0, 1) gen'
sampler :: ModeList -> State StdGen Double
sampler modeInfo = do
gen <- get
let n = length modeInfo
(z0, g0) = boxMuller gen
(c, g1) = randomR (0, n - 1) g0 -- Sample from the components.
(cmu, csig) = modeInfo !! c
put g1
return $ cmu + csig * z0 -- Sample from the conditional distribution.
这是一个示例运行:从两个高斯的一维混合中采样 100 次。众数为x = -3
和x = 2.5
,每个混合分量都有自己独立的方差。您可以在此处添加任意数量的模式。
main = do
let gen = mkStdGen 42
modeInfo = [(2.5, 1.0), (-3, 1.5)]
samples = (`evalState` gen) . replicateM 100 $ sampler modeInfo
print samples
这是这 100 个样本的平滑密度图(使用 R 和 ggplot2):
更通用的算法将是拒绝或重要性采样器,并且在更复杂的分布的情况下,您可能想要手动滚动适当的 MCMC 例程。 这是对 Monte Carlo 和 MCMC 的一个很好的介绍。