Znajdź optymalne P (X | Y), biorąc pod uwagę, że mam model, który ma dobrą wydajność po treningu na P (Y | X)

11

Dane wejściowe:

-> cechy koszulki (kolor, logo itp.)X

-> marża zyskuY

Trenowałem losowy las na powyższych i Y i osiągnąłem rozsądną dokładność na danych testowych. Więc mamXY

.P(Y|X)

Chciałbym teraz znaleźć tj. Rozkład prawdopodobieństwa cech X, biorąc pod uwagę, że oczekuję tak dużej marży zysku.P(X|Y)X

Jak to zrobić za pomocą losowego lasu (lub innego dyskryminującego modelu)?

Jedną z sugestii dla mnie może być rozpoczęcie od modelu generatywnego, a nie dyskryminacyjnego. Ale, rozumiem, że model generatywny wymaga zwykle dużej ilości danych do trenowania, chyba że przyjmą pewne bardzo restrykcyjne założenia, takie jak warunkowa niezależność w przypadku Naive Bayes?X

XYXYP(Y|X)XY

Ponadto z tego, co słyszałem, postawiono podobne pytanie dotyczące odkrywania leków i opracowano algorytmy, które wymyślają nowe kandydujące leki, które mają duży sukces. Czy ktoś może skierować mnie do zbadania literatury w tej dziedzinie?

Aktualizacja:

Natknąłem się na to i to, co mówi o GAN wykorzystywanych do odkrywania narkotyków. Generatywne sieci przeciwne wydają się dobrze pasować do mojego opisu problemu, więc czytałem o nich. Ale zrozumiałem, że GAN generuje próbki bez nadzoru. Próbują wytworzyć próbkę, która jest jak najpierw wychwytywanie podstawowego rozkładu X, a następnie pobieranie próbek z tego rozkładu. Ale interesuje mnie X | Y. X i Y są zdefiniowane powyżej. Czy powinienem odkrywać coś innego niż GAN? Jakieś wskazówki proszę?

Dalsze pytanie:

Wyobraź sobie, że mam przeszkolony GAN, który nauczył się robić koszulki (próbka wyjściowa X). Jak mogę zdobyć 5 najlepszych koszulek dla danego Y?

klaudiusz
źródło
Jest to ściśle związane z problemem plecaka lub jego stochastycznymi wariantami. Czy byłoby możliwe przekształcenie go jako takiego przy pewnych rozsądnych założeniach dotyczących Twojej domeny wejściowej?
mjul
@mjul. Sry cię nie złapał. Proszę opracować. Propozycja innego podejścia do rozwiązania problemu jest zawsze mile widziana!
claudius
1
Problem plecaka to kombinatoryczny problem optymalizacji, którego celem jest określenie najbardziej opłacalnego zestawu funkcji (dla koszulek) przy założeniu, że znasz wartość i koszt poszczególnych funkcji. Zakłada, że ​​wartości są dokładne, a nie stochastyczne. Jednak przy rozsądnych założeniach dotyczących niezależności możesz ponownie określić swój problem jako problem plecakowy lub jako jeden ze stochastycznych wariantów, które również były badane przez lata. Jednak bez dalszych informacji nie jest od razu jasne, że jest to możliwe w twoim przypadku.
mjul

Odpowiedzi:

10

Ta odpowiedź została znacznie zmodyfikowana w stosunku do pierwotnej postaci. Wady mojej oryginalnej odpowiedzi zostaną omówione poniżej, ale jeśli chcesz z grubsza zobaczyć, jak ta odpowiedź wyglądała, zanim dokonałem dużej edycji, spójrz na następujący notatnik: 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

Oszacowanie maksymalnego prawdopodobieństwa

... i dlaczego tu nie działa

W mojej pierwotnej odpowiedzi techniką, którą zasugerowałem, było użycie MCMC w celu oszacowania maksymalnego prawdopodobieństwa. Ogólnie rzecz biorąc, MLE jest dobrym podejściem do znalezienia „optymalnych” rozwiązań prawdopodobieństw warunkowych, ale mamy tutaj problem: ponieważ stosujemy model dyskryminacyjny (w tym przypadku las losowy), nasze prawdopodobieństwa są obliczane w odniesieniu do granic decyzji . Mówienie o „optymalnym” rozwiązaniu takiego modelu nie ma sensu, ponieważ gdy znajdziemy się wystarczająco daleko od granicy klasy, model po prostu przewidzi takie dla wszystkiego. Jeśli mamy wystarczającą liczbę klas, niektóre z nich mogą być całkowicie „otoczone”, w takim przypadku nie będzie to stanowić problemu, ale klasy na granicy naszych danych zostaną „zmaksymalizowane” przez wartości, które niekoniecznie są wykonalne.

Aby to zademonstrować, wykorzystam kod wygody, który można znaleźć tutaj , który zapewnia GenerativeSamplerklasę, która otacza kod z mojej oryginalnej odpowiedzi, trochę dodatkowego kodu dla tego lepszego rozwiązania oraz kilka dodatkowych funkcji, z którymi się bawiłem (niektóre z nich działają , niektóre które nie), których prawdopodobnie nie będę tutaj wchodził.

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

wprowadź opis zdjęcia tutaj

W tej wizualizacji x to prawdziwe dane, a klasa, którą jesteśmy zainteresowani, jest zielona. Kropki połączone linią to narysowane przez nas próbki, a ich kolor odpowiada kolejności, w jakiej zostały pobrane, a ich „cieńsza” pozycja sekwencji jest podana na etykiecie paska koloru po prawej stronie.

Jak widać, próbnik dość szybko oddzielił się od danych, a następnie po prostu odstaje dość daleko od wartości przestrzeni cech, które odpowiadają rzeczywistym obserwacjom. Oczywiście jest to problem.

Jednym ze sposobów, w jaki możemy oszukiwać, jest zmiana naszej funkcji propozycji, aby umożliwić funkcjom przyjmowanie wartości, które faktycznie zaobserwowaliśmy w danych. Spróbujmy i zobaczmy, jak to zmienia zachowanie naszego wyniku.

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

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

X

P(X)P(Y|X)P(X)P(Y|X)P(X)

Wprowadź regułę Bayesa

Po tym, jak zaśmieciliście mnie, że mam mniej kłopotów z matematyką, bawiłem się z tym dość sporą kwotą (stąd budowałem ten GenerativeSamplerprzedmiot) i napotkałem problemy, które przedstawiłem powyżej. Kiedy zdałem sobie z tego sprawę, czułem się naprawdę, naprawdę głupio, ale oczywiście to, o co prosisz o wezwania do zastosowania reguły Bayesa, przepraszam za wcześniejsze lekceważenie.

Jeśli nie znasz zasady Bayesa, wygląda to tak:

P(B|A)=P(A|B)P(B)P(A)

W wielu aplikacjach mianownik jest stałą, która działa jak składnik skalujący, aby zapewnić, że licznik zintegruje się z 1, więc reguła jest często przekształcana w ten sposób:

P(B|A)P(A|B)P(B)

Lub zwykłym angielskim: „a posterior jest proporcjonalne do prawdopodobieństwa wcześniejszego”.

Wygląda podobnie? A teraz:

P(X|Y)P(Y|X)P(X)

Tak, dokładnie nad tym pracowaliśmy wcześniej, konstruując oszacowanie dla MLE, które jest zakotwiczone w obserwowanym rozkładzie danych. Nigdy nie myślałem o rządzeniu Bayes w ten sposób, ale ma to sens, więc dziękuję za umożliwienie mi odkrycia tej nowej perspektywy.

P(Y)

Po zapoznaniu się z tym wnioskiem, że musimy uwzględnić wcześniejsze dane, zróbmy to, instalując standardowe KDE i zobaczmy, jak to zmienia nasz wynik.

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

wprowadź opis zdjęcia tutaj

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

wprowadź opis zdjęcia tutaj

I oto masz: duży czarny „X” jest naszym oszacowaniem na mapie (te kontury są KDE tylnego).

David Marks
źródło
Dziękuję za twoją odpowiedź. Mam pytanie. alfa = np.min ([f (nowy) / f (stary), 1]) ..... tutaj f (nowy) to P (Y = 0 | X = nowy), ponieważ używamy modelu.predict_proba, co daje rozkład Y, biorąc pod uwagę X ...... ale z en.wikipedia.org/wiki/Metropolis –Hastings_algorytm, co mogłem zrozumieć to alfa powinno wynosić min (P (X = nowy | y = 0) / P (X = stary | y = 0), 1). Czy coś źle zrozumiałem?
claudius
Wspomniałeś także w notatce TLDR „Użyj MCMC do wygenerowania próbek z p (X | Y) poprzez ocenę kandydujących wartości X względem prawdopodobieństwa warunkowego określonego przez twój model”. Ale czy model.predict_proba nie podaje prawdopodobieństwa klasy podanego X. Jak możesz powiedzieć P (X1 | Y = 0)> P (X2 | Y = 0) tylko dlatego, że model.predict_proba (X1) [0,0]> model .predict_proba (X2) [0,0]. Relację czytam z model.predict_proba jako P (Y = 0 | X1)> P (Y = 0 | X2). proszę daj mi znać, gdzie się mylę.
claudius
Także kolejne pytanie ... Czym jest tutaj symetryczna dystrybucja propozycji? Dzięki David za pomoc!
claudius
Propozycja symetryczna to losowy spacer gaussowski. Niedługo planuję zaktualizować tę wersję demonstracyjną funkcji „empirycznej”. Jeśli chodzi o matematykę MCMC, nie przejmuj się zbytnio. Trzymając Y w pozycji stałej i uruchamiając kandydatów X względem p (Y | X), MCMC aproksymuje MLE dla X w p (Y = 0 | X), tzn. Funkcja, z której próbuję stąd, nie jest p (Y | X ) (w przeciwnym razie generowałbym sekwencję etykiet klas), to L (X; Y). To skutecznie daje mi rozkład na p (X | Y = 0). Funkcja oceniania w stosunku do metropolii to p (Y | X), ale sposób, w jaki ją wykorzystuję, pozwala uzyskać próbki z p (X | Y).
David Marx,
Cześć David. Czy możesz zapisać matematykę? Trudno mi przekonać się do matematyki. Sprawdziłem twój profil, aby dowiedzieć się, że jesteś absolwentem statystyki. Proszę rozwinąć swoje punkty, aby pomóc zwykłym śmiertelnikom takim jak ja: P. Zwłaszcza "Trzymając Y ustalone i uruchamiając kandydatów X względem p (Y | X), MCMC aproksymuje MLE dla X w p (Y = 0 | X), tzn. Funkcja, z której próbuję stąd, nie jest p (Y | X) (w przeciwnym razie generowałbym sekwencję etykiet klas), to L (X; Y). To skutecznie daje mi rozkład na p (X | Y = 0). "Z góry dzięki!
claudius
0

Jednym ze sposobów przejścia do przodu może być:

Utwórz sieć neuronową ze sprzężeniem zwrotnym, która, biorąc pod uwagę Y (prawdopodobnie chcesz ją znormalizować), przewiduje X. Tak więc wyjście modelu (ostatniej warstwy) byłoby zestawem neuronów softmax dla każdej cechy. Więc jeśli funkcja 1 (np. Kolor) ma 4 opcje, zastosujesz softmax na czterech neuronach i zrobisz to samo dla każdej funkcji.

Wtedy twoją funkcją straty może być suma (lub kombinacja liniowa, jeśli wolisz) entropii krzyżowej dla każdej cechy.

Escachator
źródło
dzięki za odpowiedź! Ale szukam odpowiedzi, która sugeruje wiele podejść i wymienia zalety i wady każdego podejścia.
claudius