2017-12-11 10 views
0

SciPy(またはNumPy)確率分布に参加して混合確率分布を作成し、そこからサンプリングできる一般的な方法はありますか?サンプリングのための確率分布の混合を作成する

私のようなものを用いた表示のために、このような分布があります、

double gaussian

しかし、私はこの生成されたモデルから採取することはできません。

、その後のようなルックスをプロットした場合
mixture_gaussian = (norm.pdf(x_axis, -3, 1) + norm.pdf(x_axis, 3, 1))/2 

を曲線としてプロットする点の一覧にすぎません。

注:この特定の配布は単なる例にすぎません。私は、いくつかの種類のディストリビューション(正規分布ではない「サブ」ディストリビューションを含む)を生成できるようにしたいと考えています。理想的には、私は、関数が自動的に(つまり、上記のコードのように明示的に/ 2を行うには持っていない正規化するために何らかの方法があるだろう望んでいるだろう。

んscipyのダウンロード/ numpyのは簡単にこれを達成するいくつかの方法を提供?

This answerは、複数のディストリビューションからのそのようなサンプリングを行うことができる方法を提供しますが、特に異なるサブディストリビューションに異なる重み付けをしたい場合は、ある程度の手作業が必要です。可能であれば、よりクリーンで簡単な方法が望まれます。ありがとう!

+2

[This(https://stackoverflow.com/a/42563049/7207392)]を参考にしてください。 –

答えて

1

サンプリングからmi (PDFにいくつかの係数c_1、c_2、... c_nを加えたもの)の分布は、それぞれ独立してサンプリングし、各インデックスについて、確率k_kでk番目のサンプルから値を取り出すことと等価です。

後者の混合ステップはnumpy.random.choiceで効率的に実行できます。ここでは、3つの分布が混在する例を示します。分布はdistributionsに、係数はcoefficientsにリストされています。脂肪の正規分布、一様分布、および狭い正規分布があり、係数は0.5,0.2,0.3である。与えられた係数に従って、random_idxが生成された後に、混合はdata[np.arange(sample_size), random_idx]で行われる。コメント欄でPaulPanzerのポインタ@に続いて

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() 

histogram

1

、私は簡単にscipyのダウンロードの分布から混合モデルを作成するための以下のサブクラスを作成しました。私の質問にはpdfが必要ではないことに注意してください。

class MixtureModel(rv_continuous): 
    def __init__(self, submodels, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     self.submodels = submodels 

    def _pdf(self, x): 
     pdf = self.submodels[0].pdf(x) 
     for submodel in self.submodels[1:]: 
      pdf += submodel.pdf(x) 
     pdf /= len(self.submodels) 
     return pdf 

    def rvs(self, size): 
     submodel_choices = np.random.randint(len(self.submodels), size=size) 
     submodel_samples = [submodel.rvs(size=size) for submodel in self.submodels] 
     rvs = np.choose(submodel_choices, submodel_samples) 
     return rvs 

mixture_gaussian_model = MixtureModel([norm(-3, 1), norm(3, 1)]) 
x_axis = np.arange(-6, 6, 0.001) 
mixture_pdf = mixture_gaussian_model.pdf(x_axis) 
mixture_rvs = mixture_gaussian_model.rvs(10) 
+1

私はあなたが "異なった"重さ "の異なる"分布をしたいと思った。ここで彼らはすべて同じ重量を取得します。 – FTP

+0

@CrazyIvan、それは正しいです。私は最終的に彼らが異なって加重できるようにします。私が書いた瞬間は十分ですが、最終的に私のランダムな選択(そして 'pdf'のスケーリング)をあなたの答えに近いものに変えなければなりません。 –

関連する問題