Respons ini telah dimodifikasi secara signifikan dari bentuk aslinya. Kelemahan dari tanggapan awal saya akan dibahas di bawah, tetapi jika Anda ingin melihat kira-kira seperti apa tanggapan ini sebelum saya membuat perubahan besar, lihat buku catatan berikut: https://nbviewer.jupyter.org/github /dmarx/data_generation_demo/blob/54be78fb5b68218971d2568f1680b4f783c0a79a/demo.ipynb
P( X)P( X| Y) ∝ P( Y| X) P( X)P( Y| X)X
Estimasi Kemungkinan Maksimum
... dan mengapa itu tidak berhasil di sini
Dalam respons awal saya, teknik yang saya sarankan adalah menggunakan MCMC untuk melakukan estimasi kemungkinan maksimum. Secara umum, MLE adalah pendekatan yang baik untuk menemukan solusi "optimal" untuk probabilitas bersyarat, tetapi kami memiliki masalah di sini: karena kami menggunakan model diskriminatif (hutan acak dalam kasus ini) probabilitas kami dihitung relatif terhadap batas keputusan . Sebenarnya tidak masuk akal untuk berbicara tentang solusi "optimal" untuk model seperti ini karena begitu kita mendapatkan cukup jauh dari batas kelas, model hanya akan memprediksi yang untuk semuanya. Jika kita memiliki cukup kelas beberapa dari mereka mungkin benar-benar "dikelilingi" dalam hal ini ini tidak akan menjadi masalah, tetapi kelas pada batas data kita akan "dimaksimalkan" oleh nilai-nilai yang tidak selalu layak.
Untuk menunjukkan, saya akan memanfaatkan beberapa kode kenyamanan yang dapat Anda temukan di sini , yang menyediakan GenerativeSampler
kelas yang membungkus kode dari respons awal saya, beberapa kode tambahan untuk solusi yang lebih baik ini, dan beberapa fitur tambahan yang saya mainkan (beberapa yang berfungsi , beberapa yang tidak) yang saya mungkin tidak akan masuk ke sini.
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()
Dalam visualisasi ini, x adalah data nyata, dan kelas yang kami minati berwarna hijau. Titik-titik yang terhubung garis adalah sampel yang kami gambar, dan warnanya sesuai dengan urutan sampelnya, dengan posisi urutan "menipis" yang diberikan oleh label bilah warna di sebelah kanan.
Seperti yang Anda lihat, sampler menyimpang dari data cukup cepat dan kemudian pada dasarnya bergaul cukup jauh dari nilai-nilai ruang fitur yang sesuai dengan pengamatan nyata. Jelas ini masalah.
Salah satu cara kita dapat menipu adalah dengan mengubah fungsi proposal kami untuk hanya memungkinkan fitur mengambil nilai yang sebenarnya kami amati dalam data. Mari kita coba dan lihat bagaimana hal itu mengubah perilaku hasil kita.
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()
X
P( X)P( Y| X)P( X)P(Y|X)P(X)
Masukkan Aturan Bayes
Setelah Anda membujuk saya untuk tidak terlalu bersemangat dengan matematika di sini, saya bermain-main dengan jumlah yang lumayan (karenanya saya membangunnya GenerativeSampler
), dan saya menemui masalah yang saya sebutkan di atas. Saya merasa benar-benar bodoh ketika saya membuat realisasi ini, tetapi jelas apa yang Anda minta panggilan untuk penerapan aturan Bayes dan saya minta maaf karena menolak sebelumnya.
Jika Anda tidak terbiasa dengan aturan bayes, sepertinya ini:
P(B|A)=P(A|B)P(B)P(A)
Dalam banyak aplikasi penyebutnya adalah konstanta yang bertindak sebagai istilah penskalaan untuk memastikan bahwa pembilangnya berintegrasi ke 1, sehingga aturannya sering dinyatakan kembali sebagai berikut:
P(B|A)∝P(A|B)P(B)
Atau dalam bahasa Inggris yang sederhana: "posterior sebanding dengan waktu sebelumnya, kemungkinan".
Terlihat familier? Bagaimana kalau sekarang:
P(X|Y)∝P(Y|X)P(X)
Ya, inilah tepatnya yang kami lakukan sebelumnya dengan menyusun perkiraan untuk MLE yang didasarkan pada distribusi data yang diamati. Saya tidak pernah memikirkan Bayes memerintah dengan cara ini, tetapi masuk akal jadi terima kasih telah memberi saya kesempatan untuk menemukan perspektif baru ini.
P(Y)
Jadi, setelah membuat wawasan ini bahwa kita perlu memasukkan prior untuk data, mari kita lakukan itu dengan memasang KDE standar dan lihat bagaimana hal itu mengubah hasil kita.
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()
XP(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()
Dan begitulah: hitam besar 'X' adalah perkiraan MAP kami (kontur itu adalah KDE dari posterior).