分布の単純な混合の場合、最初に言及した「ハック」を介して効率的なサンプラーを取得できます。
この特定のケースは、事前にサンプリングするためにいずれかのディストリビューションを選択することでハッキングされる可能性がありますが、特に後でディストリビューション全体を微調整する必要がある場合があるため、単一のディストリビューションでそれを実行したいと思います。
これは実際にはギブスサンプリングの場合であり、統計で非常に一般的です。それは非常に柔軟性があり、使用している混合物の数を知っていれば、おそらく打ち負かすのは難しいでしょう。アンサンブル全体から1つの個別の分布を選択してサンプリングし、その条件付き分布からサンプリングします。すすぎ、繰り返します。
これは、ガウス混合ギブスサンプラー用の単純で最適化されていないHaskellの実装です。それはかなり基本的ですが、あなたは考えを理解します:
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.
実行例を次に示します。2つのガウス分布の1次元混合から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ルーチンを手動でロールする必要があります。 これがモンテカルロとMCMCの良い紹介です。