Encontre P (X | Y) ideal, pois tenho um modelo com bom desempenho quando treinado em P (Y | X)

11

Dados de entrada:

-> características da camiseta (cor, logotipo, etc)X

-> margem de lucroY

Treinei uma floresta aleatória nos e Y acima e obtive uma precisão razoável nos dados de teste. Então eu tenhoXY

.P(Y|X)

Agora, eu gostaria de encontrar isto é, distribuição de probabilidade dos recursos X , já que estou esperando essa margem de lucro.P(X|Y)X

Como faço isso com uma floresta aleatória (ou qualquer outro modelo discriminativo)?

Uma sugestão para mim poderia ser começar com um modelo generativo em vez de um modelo discriminativo. Mas, meu entendimento é que o modelo generativo geralmente exige muitos dados para treinar, a menos que isso faça algumas suposições muito restritivas, como independência condicional dos no caso de Naive Bayes?X

XYXYP(Y|X)XY

Além disso, pelo que ouvi, uma pergunta semelhante foi feita para a descoberta de medicamentos e algoritmos foram projetados para criar novos medicamentos candidatos com alto grau de sucesso. Alguém pode me apontar para pesquisar literatura nesse domínio?

Atualizar:

Eu me deparei com isso e isso que fala sobre GANs sendo usados ​​para descoberta de drogas. Redes adversas generativas parecem ser uma boa opção para minha declaração de problemas, então eu tenho lido sobre elas. Mas uma coisa que entendi é que a GAN gera amostras de maneira não supervisionada. Eles tentam produzir amostras que são como capturar primeiro a distribuição subjacente de X e depois amostrar a partir dessa distribuição. Mas estou interessado em X | Y. X e Y são definidos acima. Devo explorar algo diferente de GANs? Alguma dica, por favor?

Questão a seguir:

Imagine que eu tenho um GAN treinado que aprendeu a fazer camisetas (amostra Xs de saída). Como posso obter as 5 melhores camisas para o Y dado?

claudius
fonte
Isso está intimamente relacionado ao Problema da Mochila ou a suas variantes estocásticas. Seria possível reajustá-lo como tal sob algumas suposições razoáveis ​​sobre o seu domínio de entrada?
Mjul 01/01/19
@mjul. Sry não pegou você. Por favor elabore. A proposta de uma abordagem diferente para resolver o problema é sempre bem-vinda!
Claudius
1
O Problema da Mochila é um problema de otimização combinatória, em que o objetivo é identificar o conjunto de recursos mais rentável (para suas camisetas), supondo que você saiba o valor e o custo de cada recurso. Ele assume que os valores são exatos, não estocásticos. No entanto, sob suposições razoáveis ​​de independência, você poderá repor seu problema como o Problema da Mochila ou como uma das variantes estocásticas que também foram estudadas ao longo dos anos. No entanto, sem mais informações, não está claro imediatamente que isso é possível no seu caso.
Mjul

Respostas:

10

Esta resposta foi significativamente modificada de sua forma original. As falhas da minha resposta original serão discutidas abaixo, mas se você quiser ver mais ou menos como era essa resposta antes de fazer a grande edição, dê uma olhada no seguinte caderno: 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

Estimativa de máxima verossimilhança

... e por que não funciona aqui

Na minha resposta original, a técnica que sugeri foi usar o MCMC para realizar a estimativa da máxima probabilidade. Geralmente, o MLE é uma boa abordagem para encontrar as soluções "ótimas" para probabilidades condicionais, mas temos um problema aqui: porque estamos usando um modelo discriminativo (uma floresta aleatória neste caso), nossas probabilidades estão sendo calculadas em relação aos limites de decisão . Na verdade, não faz sentido falar sobre uma solução "ideal" para um modelo como esse, porque, quando nos afastamos o suficiente dos limites da classe, o modelo apenas prevê aqueles para tudo. Se tivermos classes suficientes, algumas delas podem estar completamente "cercadas"; nesse caso, isso não será um problema, mas as classes nos limites de nossos dados serão "maximizadas" por valores que não são necessariamente viáveis.

Para demonstrar, vou aproveitar alguns códigos de conveniência que você pode encontrar aqui , que fornece a GenerativeSamplerclasse que agrupa o código da minha resposta original, algum código adicional para esta melhor solução e alguns recursos adicionais com os quais eu estava brincando (alguns que funcionam , alguns que não) que eu provavelmente não entrarei aqui.

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

insira a descrição da imagem aqui

Nesta visualização, os x são os dados reais e a classe em que estamos interessados ​​é verde. Os pontos conectados à linha são as amostras que desenhamos e sua cor corresponde à ordem em que foram amostradas, com sua posição de sequência "reduzida" dada pelo rótulo da barra de cores à direita.

Como você pode ver, o amostrador divergiu dos dados com bastante rapidez e, basicamente, fica muito distante dos valores do espaço de recurso que correspondem a quaisquer observações reais. Claramente, isso é um problema.

Uma maneira de enganar é alterar a função da proposta para permitir apenas que os recursos obtenham valores que realmente observamos nos dados. Vamos tentar isso e ver como isso muda o comportamento do nosso resultado.

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

insira a descrição da imagem aqui

insira a descrição da imagem aqui

X

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

Digite a regra de Bayes

Depois que você me perseguiu para ser menos exigente com a matemática aqui, brinquei bastante com isso (daí eu construí a GenerativeSamplercoisa), e encontrei os problemas que expus acima. Eu me senti muito, muito estúpido quando fiz isso, mas obviamente o que você está pedindo pede uma aplicação da regra de Bayes e peço desculpas por ter sido menosprezado antes.

Se você não está familiarizado com a regra de bayes, fica assim:

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

Em muitas aplicações, o denominador é uma constante que atua como um termo de escala para garantir que o numerador se integre a 1; portanto, a regra geralmente é reafirmada da seguinte maneira:

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

Ou em inglês simples: "o posterior é proporcional aos tempos anteriores à probabilidade".

Parece familiar? Que tal agora:

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

Sim, foi exatamente isso que desenvolvemos anteriormente, construindo uma estimativa para o MLE ancorada na distribuição observada dos dados. Eu nunca pensei sobre Bayes governar dessa maneira, mas faz sentido, então obrigado por me dar a oportunidade de descobrir essa nova perspectiva.

P(Y)

Portanto, depois de entendermos que precisamos incorporar um prior para os dados, vamos fazer isso ajustando um KDE padrão e ver como isso muda nosso resultado.

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

insira a descrição da imagem aqui

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

insira a descrição da imagem aqui

E aí está: o grande X preto é a nossa estimativa MAP (esses contornos são o KDE do posterior).

David Marx
fonte
Obrigado pela resposta. Eu tenho uma pergunta. alpha = np.min ([f (novo) / f (antigo), 1]) ..... aqui f (novo) é P (Y = 0 | X = novo), pois estamos usando model.predict_proba que fornece distribuição de Y dado X ...... mas de en.wikipedia.org/wiki/Metropolis –Hastings_algorithm, o que eu entendi é que alfa deve ser mínimo (P (X = novo | y = 0) / P (X = antigo | y = 0), 1). Eu entendi mal alguma coisa?
Claudius
Você também mencionou na nota do TLDR "Use o MCMC para gerar amostras de p (X | Y) pontuando os valores candidatos X em relação à probabilidade condicional de classe fornecida pelo seu modelo". Mas model.predict_proba não fornece probabilidade de classe dada X. Como você pode dizer P (X1 | Y = 0)> P (X2 | Y = 0) apenas porque model.predict_proba (X1) [0,0]> model .predict_proba (X2) [0,0]. Eu li o relacionamento do model.predict_proba como P (Y = 0 | X1)> P (Y = 0 | X2). por favor me avise onde estou errado.
Claudius
Também outra pergunta de acompanhamento ... Qual é a função de distribuição simétrica da proposta aqui? Obrigado David por me ajudar !!
Claudius
A proposta simétrica é uma caminhada aleatória gaussiana. Pretendo atualizá-lo em breve com uma demonstração de uma função "empírica" ​​da proposta. Em relação à matemática do MCMC, não se prenda a isso. Mantendo Y fixo e executando X candidatos contra p (Y | X), o MCMC aproxima o MLE para X em p (Y = 0 | X), ou seja, a função que estou amostrando daqui não é p (Y | X ) (caso contrário, eu estaria gerando uma sequência de rótulos de classe), é L (X; Y). Isso efetivamente me fornece uma distribuição sobre p (X | Y = 0). A função de pontuação na proporção da metrópole é p (Y | X), mas o modo como estou usando produz amostras de p (X | Y).
David Marx
Hey David. Você pode escrever as contas para isso? Estou tendo dificuldade em me convencer com a matemática. Verifiquei seu perfil para descobrir que você é graduado em estatística. Por favor, elabore seus pontos para ajudar meros mortais como eu: P. Especialmente "Mantendo Y fixo e executando X candidatos contra p (Y | X), o MCMC aproxima o MLE para X em p (Y = 0 | X), ou seja, a função que estou amostrando daqui não é p (Y | X) (caso contrário, eu estaria gerando uma sequência de rótulos de classe), é L (X; Y). Isso efetivamente me fornece uma distribuição sobre p (X | Y = 0). "Agradecemos antecipadamente!
Claudius
0

Uma maneira de avançar pode ser:

Crie uma rede neural avançada que, dado que Y (provavelmente você deseja normalizá-la) preveja o X. Portanto, a saída do modelo (a última camada) seria um conjunto de neurônios softmax para cada recurso. Portanto, se o recurso 1 (por exemplo, cor) tiver 4 opções, você aplicará o softmax em quatro neurônios e fará o mesmo em cada recurso.

Então sua função de perda pode ser a soma (ou uma combinação linear, se você preferir) da entropia cruzada para cada recurso.

Escachator
fonte
obrigado pela sua resposta! Mas estou procurando uma resposta que sugira várias abordagens e mencione prós e contras de cada abordagem.
claudius