この応答は、元の形式から大幅に変更されています。私の元の応答の欠陥については以下で説明しますが、大幅に編集する前にこの応答がどのようになっていたかをおおまかに確認したい場合は、次のノートブックをご覧ください:https : //nbviewer.jupyter.org/github /dmarx/data_generation_demo/blob/54be78fb5b68218971d2568f1680b4f783c0a79a/demo.ipynb
TL; DR:概算するために使用するKDE(またはお好みの手順)、その後からサンプルを引き出すためにMCMCを使っP (X | Y )α P (Y | X )P (X )、Pは(Y | X )はモデルによって指定されます。これらのサンプルから、生成したサンプルに2番目のKDEをフィッティングし、KDEを最大化する観測値を最大事後(MAP)推定値として選択することにより、「最適な」Xを推定できます。P(X)P(X| Y)∝ P(Y| バツ)P(X)P(Y| バツ)バツ
最尤推定
...そしてそれがここで機能しない理由
私の最初の応答では、MCMCを使用して最尤推定を実行する方法を提案しました。一般的に、MLEは条件付き確率の「最適な」解を見つけるための優れたアプローチですが、ここで問題があります。判別モデル(この場合はランダムフォレスト)を使用しているため、確率は決定の境界に対して計算されています。 。このようなモデルの「最適な」ソリューションについて話すことは実際には意味がありません。クラスの境界から十分に離れると、モデルはすべてのものを予測するだけだからです。十分なクラスがある場合、それらの一部は完全に「囲まれる」可能性がありますが、その場合は問題になりませんが、データの境界にあるクラスは、必ずしも実現可能ではない値によって「最大化」されます。
実例を示すために、ここで見つけることができるいくつかの便利なコードを活用します。これはGenerativeSampler
、元の応答からのコードをラップするクラス、このより優れたソリューションのためのいくつかの追加コード、および私が試してみたいくつかの追加機能(いくつかの機能するもの)を提供します、そうでないものもありますが、おそらくここには入りません。
np.random.seed(123)
sampler = GenerativeSampler(model=RFC, X=X, y=y,
target_class=2,
prior=None,
class_err_prob=0.05, # <-- the score we use for candidates that aren't predicted as the target class
rw_std=.05, # <-- controls the step size of the random walk proposal
verbose=True,
use_empirical=False)
samples, _ = sampler.run_chain(n=5000)
burn = 1000
thin = 20
X_s = pca.transform(samples[burn::thin,:])
# Plot the iris data
col=['r','b','g']
for i in range(3):
plt.scatter(*X_r[y==i,:].T, c=col[i], marker='x')
plt.plot(*X_s.T, 'k')
plt.scatter(*X_s.T, c=np.arange(X_s.shape[0]))
plt.colorbar()
plt.show()
この視覚化では、xは実際のデータであり、関心のあるクラスは緑色です。線で結ばれたドットは私たちが描いたサンプルであり、その色はそれらがサンプリングされた順序に対応し、右側のカラーバーラベルによって「薄められた」シーケンス位置が示されます。
ご覧のように、サンプラーはデータからかなり速く分岐し、基本的に、実際の観測に対応する特徴空間の値からかなり離れたところにいます。これは明らかに問題です。
だますことができる1つの方法は、提案関数を変更して、フィーチャがデータで実際に観察した値のみを取ることを許可することです。それを試して、結果の動作がどのように変わるか見てみましょう。
np.random.seed(123)
sampler = GenerativeSampler(model=RFC, X=X, y=y,
target_class=2,
prior=None,
class_err_prob=0.05,
verbose=True,
use_empirical=True) # <-- magic happening under the hood
samples, _ = sampler.run_chain(n=5000)
X_s = pca.transform(samples[burn::thin,:])
# Constrain attention to just the target class this time
i=2
plt.scatter(*X_r[y==i,:].T, c='k', marker='x')
plt.scatter(*X_s.T, c='g', alpha=0.3)
#plt.colorbar()
plt.show()
sns.kdeplot(X_s, cmap=sns.dark_palette('green', as_cmap=True))
plt.scatter(*X_r[y==i,:].T, c='k', marker='x')
plt.show()
バツ
P(X)P(Y| バツ)P(X)P(Y| バツ)P(X)
ベイズ規則を入力してください
ここで数学の手間が少なくなるように私を探した後、私はこれをかなり試しました(それで私はGenerativeSampler
ものを作ったのです)、そして私は上に示した問題に遭遇しました。私がこのことに気付いたときは本当に、本当に愚かでしたが、ベイズの法則の適用を求める声をあなたが求めていることは明らかであり、私は以前に却下されたことをお詫びします。
ベイズの規則に慣れていない場合は、次のようになります。
P(B | A )= P(A | B )P(B )P(A )
多くのアプリケーションでは、分母は定数であり、分子が1に積分されることを保証するスケーリング項として機能するため、ルールはしばしばこうして言い換えられます。
P(B | A )∝ P(A | B )P(B )
または平易な英語で:「事後は以前の時間の可能性に比例します」。
見覚えがあります?今はどう:
P(X| Y)∝ P(Y| バツ)P(X)
ええ、これは、観測されたデータの分布に基づいてMLEの推定値を作成することで、これまでに正確に作成したものです。私はベイズがこのように支配することについて考えたことはありませんが、理にかなっているので、この新しい視点を発見する機会を与えてくれてありがとう。
P(Y)
したがって、データの事前統合を組み込む必要があるというこの洞察を作成したら、標準のKDEをフィッティングしてそれを行い、結果がどのように変化するかを見てみましょう。
np.random.seed(123)
sampler = GenerativeSampler(model=RFC, X=X, y=y,
target_class=2,
prior='kde', # <-- the new hotness
class_err_prob=0.05,
rw_std=.05, # <-- back to the random walk proposal
verbose=True,
use_empirical=False)
samples, _ = sampler.run_chain(n=5000)
burn = 1000
thin = 20
X_s = pca.transform(samples[burn::thin,:])
# Plot the iris data
col=['r','b','g']
for i in range(3):
plt.scatter(*X_r[y==i,:].T, c=col[i], marker='x')
plt.plot(*X_s.T, 'k--')
plt.scatter(*X_s.T, c=np.arange(X_s.shape[0]), alpha=0.2)
plt.colorbar()
plt.show()
バツP(X| Y)
# MAP estimation
from sklearn.neighbors import KernelDensity
from sklearn.model_selection import GridSearchCV
from scipy.optimize import minimize
grid = GridSearchCV(KernelDensity(), {'bandwidth': np.linspace(0.1, 1.0, 30)}, cv=10, refit=True)
kde = grid.fit(samples[burn::thin,:]).best_estimator_
def map_objective(x):
try:
score = kde.score_samples(x)
except ValueError:
score = kde.score_samples(x.reshape(1,-1))
return -score
x_map = minimize(map_objective, samples[-1,:].reshape(1,-1)).x
print(x_map)
x_map_r = pca.transform(x_map.reshape(1,-1))[0]
col=['r','b','g']
for i in range(3):
plt.scatter(*X_r[y==i,:].T, c=col[i], marker='x')
sns.kdeplot(*X_s.T, cmap=sns.dark_palette('green', as_cmap=True))
plt.scatter(x_map_r[0], x_map_r[1], c='k', marker='x', s=150)
plt.show()
そして、そこにそれがあります:大きな黒い「X」はMAP推定値です(これらの輪郭は後部のKDEです)。