Phản ứng này đã được sửa đổi đáng kể từ hình thức ban đầu của nó. Các sai sót trong phản hồi ban đầu của tôi sẽ được thảo luận bên dưới, nhưng nếu bạn muốn xem đại khái phản hồi này trông như thế nào trước khi tôi thực hiện chỉnh sửa lớn, hãy xem sổ tay sau: https://nbviewer.jupyter.org/github /dmarx/data_generation_demo/blob/54be78fb5b68218971d2568f1680b4f783c0a79a/demo.ipynb
TL; DR: Sử dụng một KDE (hoặc các thủ tục lựa chọn của bạn) để xấp xỉ , sau đó sử dụng MCMC để vẽ mẫu từ P ( X | Y ) α P ( Y | X ) P ( X ) , nơi P ( Y | X ) được đưa ra bởi mô hình của bạn. Từ các mẫu này, bạn có thể ước tính X "tối ưu" bằng cách khớp KDE thứ hai với các mẫu bạn đã tạo và chọn quan sát tối đa hóa KDE làm ước tính tối đa của posteriori (MAP).P( X)P( X| Y) Α P( Y| X) P( X)P( Y| X)X
Ước lượng khả năng tối đa
... và tại sao nó không hoạt động ở đây
Trong phản hồi ban đầu của tôi, kỹ thuật tôi đề xuất là sử dụng MCMC để thực hiện ước tính khả năng tối đa. Nói chung, MLE là một cách tiếp cận tốt để tìm giải pháp "tối ưu" cho xác suất có điều kiện, nhưng chúng tôi có một vấn đề ở đây: bởi vì chúng tôi đang sử dụng mô hình phân biệt (một khu rừng ngẫu nhiên trong trường hợp này) xác suất của chúng tôi được tính toán liên quan đến ranh giới quyết định . Thật không có ý nghĩa gì khi nói về một giải pháp "tối ưu" cho một mô hình như thế này bởi vì một khi chúng ta đã đi đủ xa khỏi ranh giới lớp, mô hình sẽ chỉ dự đoán các giải pháp cho mọi thứ. Nếu chúng ta có đủ các lớp, một số trong số chúng có thể hoàn toàn bị "bao vây" trong trường hợp đó sẽ không phải là vấn đề, nhưng các lớp trên ranh giới dữ liệu của chúng ta sẽ được "tối đa hóa" bởi các giá trị không nhất thiết phải khả thi.
Để chứng minh, tôi sẽ tận dụng một số mã tiện lợi bạn có thể tìm thấy ở đây , nó cung cấp GenerativeSampler
lớp bao bọc mã từ phản hồi ban đầu của tôi, một số mã bổ sung cho giải pháp tốt hơn này và một số tính năng bổ sung mà tôi đang chơi xung quanh (một số tính năng hoạt động , một số cái không) mà tôi có lẽ sẽ không vào được đây.
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()
Trong hình dung này, các x là dữ liệu thực và lớp chúng ta quan tâm là màu xanh lá cây. Các chấm được nối với nhau là các mẫu chúng ta đã vẽ và màu của chúng tương ứng với thứ tự được lấy mẫu, với vị trí chuỗi "mỏng" của chúng được đưa ra bởi nhãn thanh màu bên phải.
Như bạn có thể thấy, bộ lấy mẫu chuyển hướng khỏi dữ liệu khá nhanh và sau đó về cơ bản chỉ nằm cách xa các giá trị của không gian tính năng tương ứng với bất kỳ quan sát thực tế nào. Rõ ràng đây là một vấn đề.
Một cách chúng ta có thể gian lận là thay đổi chức năng đề xuất của mình để chỉ cho phép các tính năng lấy các giá trị mà chúng ta thực sự quan sát được trong dữ liệu. Hãy thử điều đó và xem điều đó thay đổi hành vi của kết quả của chúng tôi như thế nào.
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 vì vậy chúng tôi thực sự không nên tin tưởng phân phối này hoặc.
P( X)P( Y| X)P( X)P( Y| X) P( X) ....
Nhập quy tắc Bayes
Sau khi bạn làm cho tôi bớt căng thẳng với môn toán ở đây, tôi đã chơi với số tiền khá lớn này (do đó tôi xây dựng GenerativeSampler
điều đó), và tôi đã gặp phải những vấn đề tôi đặt ra ở trên. Tôi cảm thấy thực sự, thực sự ngu ngốc khi tôi thực hiện điều này, nhưng rõ ràng những gì bạn đang yêu cầu kêu gọi áp dụng quy tắc Bayes và tôi xin lỗi vì đã bị từ chối trước đó.
Nếu bạn không quen thuộc với quy tắc bay, nó sẽ giống như sau:
P( B | A ) = P( A | B ) P( B )P( A )
Trong nhiều ứng dụng, mẫu số là một hằng số đóng vai trò là một thuật ngữ tỷ lệ để đảm bảo rằng tử số tích hợp thành 1, do đó, quy tắc thường được trình bày lại như vậy:
P( B | A ) α P( A | B ) P( B )
Hoặc bằng tiếng Anh đơn giản: "hậu thế tỷ lệ thuận với thời gian trước khả năng".
Nhìn có quen không? Làm thế nào bây giờ:
P( X| Y) Α P( Y| X) P( X)
Vâng, đây chính xác là những gì chúng tôi đã làm việc trước đó bằng cách xây dựng một ước tính cho MLE được neo vào phân phối dữ liệu quan sát được. Tôi chưa bao giờ nghĩ về Bayes cai trị theo cách này, nhưng nó rất có ý nghĩa vì vậy cảm ơn bạn đã cho tôi cơ hội khám phá quan điểm mới này.
P( Y)
Vì vậy, khi đã hiểu rõ rằng chúng ta cần kết hợp trước cho dữ liệu, hãy thực hiện điều đó bằng cách khớp KDE tiêu chuẩn và xem điều đó thay đổi kết quả của chúng ta như thế nào.
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()
Và ở đó bạn có nó: 'X' màu đen lớn là ước tính MAP của chúng tôi (những đường viền đó là KDE của hậu thế).