Bu yanıt orijinal biçiminden önemli ölçüde değiştirildi. Orijinal yanıtımın kusurları aşağıda tartışılacaktır, ancak büyük düzenlemeyi yapmadan önce bu yanıtın nasıl göründüğünü görmek istiyorsanız, aşağıdaki not defterine bir göz atın: https://nbviewer.jupyter.org/github /dmarx/data_generation_demo/blob/54be78fb5b68218971d2568f1680b4f783c0a79a/demo.ipynb
TL; DR: ) 'e yaklaşmak için bir KDE (veya seçtiğiniz prosedür) kullanın , ardından den örnek çizmek için MCMC kullanın , burada modeliniz tarafından verilir. Bu örneklerden, oluşturduğunuz örneklere ikinci bir KDE yerleştirerek ve KDE'yi maksimum posteriori (MAP) tahmininiz olarak maksimize eden gözlemi seçerek "optimal" tahmin edebilirsiniz.P(X)P(X|Y)∝P(Y|X)P(X)P(Y|X)X
Maksimum olasılık tahmini
... neden burada çalışmıyor?
Orijinal yanıtımda önerdiğim teknik, maksimum olasılık tahmini yapmak için MCMC kullanmaktı. Genel olarak, MLE, koşullu olasılıklara "en uygun" çözümleri bulmak için iyi bir yaklaşımdır, ancak burada bir sorunumuz var: çünkü ayrımcı bir model (bu durumda rastgele bir orman) kullanıyoruz, olasılıklarımız karar sınırlarına göre hesaplanıyor . Aslında böyle bir model için "optimal" bir çözüm hakkında konuşmak mantıklı değil çünkü sınıf sınırından yeterince uzaklaştığımızda, model sadece her şey için olanları tahmin edecektir. Yeterli sınıfımız varsa, bazıları tamamen "çevrelenmiş" olabilir, bu durumda bu bir sorun olmayacaktır, ancak verilerimizin sınırındaki sınıflar, zorunlu olarak mümkün olmayan değerlerle "maksimize edilecektir".
Göstermek için, burada bulabileceğiniz bazı kolaylık kodunu kullanacağım, bu da GenerativeSampler
orijinal yanıtımdan kodu saran sınıfı, bu daha iyi çözüm için bazı ek kodları ve birlikte oynadığım bazı ek özellikleri (bazıları hangi , bazıları olmayan) muhtemelen buraya girmeyeceğim.
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()
Bu görselleştirmede, x'ler gerçek verilerdir ve ilgilendiğimiz sınıf yeşildir. Çizgiye bağlı noktalar, çizdiğimiz örneklerdir ve renkleri, sağdaki renk çubuğu etiketi tarafından verilen "inceltilmiş" sekans konumları ile örneklendikleri sıraya karşılık gelir.
Gördüğünüz gibi, örnekleyici verilerden oldukça hızlı bir şekilde saptı ve daha sonra temelde gerçek gözlemlere karşılık gelen özellik alanının değerlerinden oldukça uzak duruyor. Açıkçası bu bir sorundur.
Hile yapmanın bir yolu, teklif işlevimizi yalnızca özelliklerin verilerde gerçekten gözlemlediğimiz değerleri almasına izin verecek şekilde değiştirmektir. Bunu deneyelim ve bunun sonucumuzun davranışını nasıl değiştirdiğini görelim.
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()
Bu kesinlikle önemli bir gelişme ve dağıtım şeklimiz kabaca aradığımız şeye karşılık geliyor, ancak hala uygulanabilir değerlerine karşılık gelmeyen çok fazla gözlem ürettiğimiz açıktır, bu yüzden gerçekten yapmamalıyız bu dağılıma da güven.X
Burada bariz çözüm şekilde örnekleme sürecimizi verilerin gerçekte alması muhtemel özellik uzayının bölgelerine tutturmaktır. Öyleyse, bunun yerine model tarafından verilen olasılığın ortak olasılığından, ve tüm veri kümesine uyan bir KDE tarafından verilen için sayısal bir tahminden örnek alalım . Şimdi ... ... den numune alıyoruz ...P(X)P(Y|X)P(X)P(Y|X)P(X)
Bayes Kuralını Girin
Beni buradaki matematikle daha az el sallamak için tattıktan sonra, bununla adil bir miktar oynadım (dolayısıyla GenerativeSampler
şeyi inşa etmeme izin verdim) ve yukarıda ortaya koyduğum sorunlarla karşılaştım. Bu farkındalığı yaptığımda gerçekten, gerçekten aptal hissettim, ama belli ki Bayes kuralının uygulanması için çağrıda bulunduğunuz şey ve daha önce işten çıkarıldığım için özür dilerim.
Bayes kuralına aşina değilseniz, şöyle görünür:
P(B|A)=P(A|B)P(B)P(A)
Birçok uygulamada payda, payın 1 ile bütünleşmesini sağlamak için bir ölçeklendirme terimi olarak hareket eden bir sabittir, bu nedenle kural genellikle bu şekilde yeniden ifade edilir:
P(B|A)∝P(A|B)P(B)
Veya açık İngilizce olarak: "posterior, önceki olasılığa orantılıdır".
Tanıdık görünmek? Şimdi nasıl:
P(X|Y)∝P(Y|X)P(X)
Evet, MLE için verilerin gözlemlenen dağılımına sabitlenmiş bir tahmin oluşturarak tam olarak daha önce çalıştık. Bayes'i bu şekilde yönetmeyi hiç düşünmemiştim, ama bana bu yeni perspektifi keşfetme fırsatı verdiğiniz için çok teşekkür ederim.
Küçük bir parçayı geri izlemek için MCMC, payda kuralını göz ardı edebileceğimiz bayes kuralının uygulamalarından biridir. Kabul oranını hesapladığımızda, hem payda hem de paydada aynı değeri alır, iptal eder ve normalleştirilmemiş olasılık dağılımlarından örnekler çekmemize izin verir.P(Y)
Bu nedenle, veriler için bir önceliği eklememiz gereken bu anlayışı yaptıktan sonra, standart bir KDE yerleştirerek bunu yapalım ve bunun sonucumuzu nasıl değiştirdiğini görelim.
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()
Çok daha iyi! Şimdi, "maksimum" posteriori tahmini olarak adlandırılan "optimum" değerinizi tahmin edebiliriz. Bu, ikinci bir KDE'ye uyduğumuzu söylemenin süslü bir yoludur - ancak bu sefer numunelerimize - ve maksimize eden değeri bulabiliriz KDE, yani moduna karşılık gelen değer .P ( X | Y )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()
Ve işte burada: Büyük siyah 'X' bizim MAP tahminimizdir (bu konturlar posteriorun KDE'sidir).