herzog, schindler, silveira - 2013 - algoritmo de metropolis-hastings
TRANSCRIPT
UNIVERSIDADE FEDERAL DO RIO GRANDE DO SUL
INSTITUTO DE MATEMÁTICA
DEPARTAMENTO DE ESTATÍSTICA
BACHARELADO EM ESTATÍSTICA
ESTATÍSTICA COMPUTACIONAL – MAT02274
PROFESSOR DR. FLAVIO AUGUSTO ZIEGELMANN
METROPOLIS HASTINGS
EDUARDO SCHINDLER RAIANE PADILHA SILVEIRA
RODRIGO CASTELO BRANCO HERZOG
Porto Alegre, 29 de novembro de 2013.
Sumário
1. Introdução
2. Métodos de Monte Carlo em cadeias de Markov (MCMC)
3. Algoritmo de Metropolis Hastings 3.1 Algorítmo genérico 3.2 Implementações
4. Considerações finais
Anexo I – Código R Anexo II – Outro exemplo de aplicação Anexo III – Help da função metrop
Referências
1. Introdução
O algoritmo de Metropolis-Hastings (MH) foi nomeado a partir do físico,
Nicholas Metropolis, que publicou, em 1953, em conjunto com Arianna W.
Rosenbluth, Marshall N. Rosenbluth, Augusta H. Teller e Edward Teller o artigo
Equation of State Calculation by Fast Computing Machines, onde propuseram um
método geral aplicado ao estudo da interação entre moléculas1, através de uma
modificação da integração de Monte Carlo (Metropolis et ali, 1953). W. Keith Hastings
(1970), em artigo publicado na revista Biometrika, chamado Monte Carlo Sampling
using Markov Chains and their aplication, generalizou a aplicação do algorítmo.
Segundo Hastings:
When I returned to the University of Toronto, after my time at Bell Labs, I focused on Monte Carlo methods and at first on methods of sampling from probability distributions with no particular area of application in mind. [University of Toronto Chemistry professor] John Valleau and his associates consulted me concerning their work. They were using Metropolis's method to estimate the mean energy of a system of particles in a defined potential field. With 6 coordinates per particle, a system of just 100 particles involved a dimension of 600. When I learned how easy it was to generate samples from high dimensional distributions using Markov chains, I realised how important this was for Statistics, and I devoted all my time to this method and its variants which resulted in the 1970 paper2.
1 O modelo apresentado neste paper aplicava-se à distribuição de Boltzman, a qual podia descreve o
estado de determinada substância a partir da temperatura e pressão e tinha a seguinte forma:
2 Em tradução livre: “Quando retornei a universidade de Toronto, após algum tempo nos laboratórios
Bell, foquei nos Métodos de Monte Carlo, e, primeiramente, nos métodos de amostragem de
distribuições de probabilidade sem uma área de aplicação particular em mente. [O professor de química
da University of Toronto] John Valleau e seus colegas consultaram-me a respeito de seu trabalho. Eles
estavam utilizando o método de Metropolis para estimar a energia média de um sistema de
partículoasem determinado campo potêncial. Com 6 coordenadas por particular, um sistema de 100
Este algoritmo permite simular distribuições quando não é possível utilizar a
simulação direta, a transformação inversa, ou o método de aceitação-rejeição. Sua
eficiência está diretamente ligada ao fato de não levar em conta a probabilidade das
configurações em si, mas sim a razão entre elas. Outra característica importante é o fato
de gerar amostras dependentes.
2. Métodos de Monte Carlo em cadeias de Markov (MCMC)
Antes de apresentarmos os conceitos do algoritmo de Metropolis Hastings,
vamos considerar a ideia geral do funcionamento dos métodos de Monte Carlo em
cadeias de Markov (MCMC):
Dada uma distribuição alvo , construímos uma kernel3 de Markov K, com
distribuição estacionária , e, então, gera-se uma cadeia de Markov usando este
kernel de modo que a distribuição limite de é e as integrais possam ser
aproximadas usando o Teorema Ergódico (teorema do limite central). Então, a
dificuldade estaria em construir um kernel K que seja associado a alguma determinada
densidade . Existem métodos para derivar K, e eles são teoricamente válidos para
qualquer densidade .
3. Algoritimo de Metropolis-Hastings
O algoritmo de Metropolis-Hastings é um exemplo da aplicação dos métodos de
Monte Carlo em Cadeias de Markov. Dada uma densidade alvo , ela é associada com
uma densidade condicional que, na prática, seja fácil de simular. A distribuição
partículas envolvia a dimensão de 600. Quando compreendi o quão simples era gerar amostras de
distribuições de grandes dimensões utilizando cadeias de Markov, percebi o quão importante isso era
para a estatística, e dediquei todo meu tempo a este método e às suas variantes, o que resultou no
artigo de 1970.” (citação disponível em http://probability.ca/hastings/)
3 O Kernel de transição T (θk+1/ θk) representa a probabilidade do movimento de θk da cadeia para o
próximo estado θk+1, descrevendo, deste modo, a forma na qual o novo estado da cadeia é obtido a
partir do estado atual. A ideia da Cadeia de Markov de que a probabilidade de um estado atual depende
somente do estado imediatamente anterior se aplicam ao algoritmo de Metropolis-Hastings e é o que
torna a sua amostra dependente.
que pode ser quase toda arbitrária, de modo que o único requisito teórico seja que a
razão seja conhecida até uma constante independente de e que
tenha dispersão suficiente para explorar todo o suporte de
3.1 Algoritmo genérico MCMC
O algoritmo de Metropolis-Hastings associado com a densidade alvo e a
densidade condicional produz uma cadeia de Markov através do seguinte
kernel de transação K(3):
Dado ,
Gerar ;
Calcular
Onde ;
é a distribuição candidata;
Probabilidade de aceitação.
3.2 Implementações
Vamos ilustrar o algoritmo aplicando a distribuição Beta com parâmetros 2.7 e
6.3. Portanto, nossa densidade alvo f é Beta(2.7,6.3). Utilizaremos como candidata q, a
distribuição Uniforme (0,1).
Seguindo os passos, temos:
1. Para t=0, consideramos xo tal que f(x0) > 0 tomamos como X0 para
iniciarmos a cadeia.
2. Para t = 1,...,T-1 (e i=2, ...,T), repetimos os seguintes passos:
a) Gerar y da distribuição q(y|x(t)), no caso Uniforme (0,1), com x(t)
b) Gerar NPA
c) Calcular , com f f.d.p. Beta(2.7,6.3) e q Uniforme (0,1).
Se aceitar y e xt+1 = y ;
Caso contrário, xt+1 = xt;
Guardar xt+1 em x[i]= x t+1
Incrementar t e voltar a 2.
Para se inicializar a cadeia, o valor X0 proposto é qualquer, desde que esteja no
suporte da função alvo. Como a candidata deverá ter o suporte igual ao daquela, então
uma forma de inicializar a cadeia é gerar um valor da candidata.
Para as execuções posteriores, é interessante notar que caso o algoritmo opte por
rejeitar o valor proposto, este valor não é descartado, e sim, mantido para a execução
subsequente da cadeia. O que torna a sequência dependente do valor anterior.
Outra observação importante é que, na prática há a necessidade de esperar que a
cadeia atinja o seu estado de equilíbrio. Isso significa que deve-se retirar um certo
número inicial de realizações da cadeia, período chamado de aquecimento (ou burn-in
sample).
A figura 1 ilustra um trecho da cadeia de Markov gerada na implementação do
algoritmo acima utilizando o software R4 (o código encontra-se no anexo I).
Figura 1 – Cadeia de Markov gerada pelo algoritmo.
4 A função metrop() do pacote mcmc permite a aplicação do algoritmo.
A figura 2 mostra a comparação entre a geração direta, através de função do R-
project, e a distribuição gerada pelo algoritmo de Metropolis-Hastings.
Figura 2 - Comparação
Podemos observar que o algoritmo gerou uma distribuição bastante próxima da
distribuição alvo.
Considerações Finais
O algoritmo de Metropolis Hastings tem sido apontado como um dos algoritmos
mais importantes do século XX. Sua aplicação generalizou-se com o desenvolvimento
dos computadores, premitindo a geração de grandes amostras em tempos muito
reduzidos.
A facilidade do algoritmo para lidar com distribuições multidimensionais é outro
ponto forte. As cadeias de Markov já apresentavam este benefício, entretanto, com
Metropolis-Hastings, foi possível sua aplicação a qualquer tipo de distribuição. Sendo
assim, quando todos os outros métodos falharem, ainda é possível recorrer a este
algoritmo.
ANEXO I – Código R do Exemplo
#----- Gerar Beta através do MH ------
a=2.7; b=6.3; #valores iniciais
nsim = 5000
X=rep(runif(1),nsim) # inicializar a cadeia
for (i in 2:nsim){
Y= runif(1)
alpha=min(dbeta(Y,a,b)/dbeta(X[i-1],a,b),1)
X[i]=X[i-1] + (Y-X[i-1])*(runif(1)<alpha)
}
plot(4500:4800,X[4500:4800],ty="l",lwd=2,xlab="Iterações",ylab="X")
title(main="Gerar Beta : MCMC - Metropolis Hastings")
#-------- Histogramas ----------
par(mfrow=c(1,2),mar=c(2,2,1,1))
hist(X[1000:nsim],breaks=50,col="blue",main="Metropolis-Hastings",fre=FALSE)
curve(dbeta(x,a,b),col="sienna",lwd=2,add=TRUE)
hist(rbeta(4000,a,b),breaks=50,col="blue",main="Geração direta",fre=FALSE)
curve(dbeta(x,a,b),col="sienna",lwd=2,add=TRUE
ANEXO II – Outro exemplo de aplicação.
Código fonte retirado da página http://recologia.com.br/2013/08/um-exemplo-do-
algoritimo-de-metropolis-hastings-aplicado-a-distribuicao-binomial/
#Adaptado de uma função do livro Bayesian Data Analysis: A Tutorial with R and BUGS #Semente para replicar os resultado do post. set.seed(51) #Gerando uma amostra de dados probabilidade <-0.70 meusdados <-rbinom (n=14, size =1, prob =probabilidade ) #Definindo a função de likelihood binomial. likelihood <- function( theta , data ) { z <- sum( data == 1 ) N <- length( data ) pDataGivenTheta <- theta ^z * (1-theta )^(N-z ) pDataGivenTheta [ theta > 1 | theta < 0 ] <- 0 return ( pDataGivenTheta ) } plot(seq(0.01, 0.99, 0.01),likelihood (seq(0.01, 0.99, 0.01),meusdados ), frame=F, xlab ="Probabilidade",ylab ="Likelihood",type ="l" ) #Função para definir o prior p(D), prior <- function( theta ) { prior <- dbeta(theta, 1, 1) #exemplo de um prior bimodal #prior < dbeta( pmin(2*theta,2*(1-theta)),2,2 ) prior [ theta > 1 | theta < 0 ] <- 0 return ( prior ) } plot(seq(0.01, 0.99, 0.01),prior (seq(0.01, 0.99, 0.01)), frame=F, xlab ="Probabilidade",ylab ="Likelihood",type ="l" ) #Função auxiliar para ajudar a calcular a probabilidade relativa targetRelProb <- function( theta , data ) { targetRelProb <- likelihood ( theta , data ) * prior ( theta ) return ( targetRelProb ) } # Tamanho da cadeia Ncadeia = 100000 #Inicializando um vetor para salvar os resultados do MCMC cadeia = rep( 0 , Ncadeia ) # Iniciando o MCMC com um valor arbritario cadeia [1] = runif (1, min=0, max=1) # Especificando um valor de burnning, ou seja o quanto do inicio da cadeia vamos jogar fora # Aqui vamo jogar fora 10% burnIn = ceiling( .1 * Ncadeia ) # Vamos contar quantas vezes aceitamos ou não os valores propostos nAceito = 0 nRejeitado = 0 # Agora iniciando o "Random Walk" for ( t in 1:(Ncadeia -1) ) {
#Valor Atual valoratual = cadeia [t] #Propomos uma quantidade para alterar esse valor valorproposto = rnorm ( 1 , mean = 0 , sd = 0.1 ) #Computamos a chance de aceitar a mudança #Essa chance é igual a Likelihood*prior com o novo valor de theta #dividido pele Likeliood*prior antigo chanceaceitar = min( 1, targetRelProb ( valoratual + valorproposto, meusdados ) / targetRelProb ( valoratual , meusdados ) ) #Agora aqui a gente ve na sorte se aceitamos ou não o novo valor. #Veja que temos uma chance de fazer a mudança ou manter o ultimo valor #Se a gente sortei um número qualquer de 0 a 1 e compara se ele é #menor que a chance de aceitar, dessa forma mudamos numa probabilidade #da chance de mudar if ( runif (1) < chanceaceitar ) { #Se aceitarmos mudamos ele na cadeia cadeia [ t+1 ] <- valoratual + valorproposto #So vamos começar a contar depois do burnIn que escolhemos #Afinal, com o começo arbitrario, esperamos aceitar bastante #a não ser que escolhemos um valor proximo do final no começo if ( t > burnIn ) { nAceito <- nAceito + 1 } } else { # Quando não aceitamos o valor proposto mantemos o anterior cadeia [ t+1 ] <- valoratual # E incrementamos aqui apos o BurnIn, como acima if ( t > burnIn ) { nRejeitado <- nRejeitado + 1 } } } #Agora vamos olhar como ficou a cadeia final, ou seja, tirando os valores iniciais cadeiafinal <- cadeia [ (burnIn +1) : length(cadeia ) ] #Alguns Gráficos #----------------------------------------------------------------------- HDIofMCMC = function( sampleVec , credMass =0.95 ) { sortedPts = sort( sampleVec ) ciIdxInc = floor ( credMass * length( sortedPts ) ) nCIs = length( sortedPts ) - ciIdxInc ciWidth = rep( 0 , nCIs ) for ( i in 1:nCIs ) { ciWidth [ i ] = sortedPts [ i + ciIdxInc ] - sortedPts [ i ] } HDImin = sortedPts [ which.min( ciWidth ) ] HDImax = sortedPts [ which.min( ciWidth ) + ciIdxInc ] HDIlim = c( HDImin , HDImax ) return ( HDIlim ) } #------------------------------------------------------------------------ intconf <-HDIofMCMC(cadeiafinal ) hist(cadeiafinal,ylab ="Frequência na cadeia final",xlab ="Probabilidades",xlim =c(0, 1)) lines(c(intconf [1],intconf [2]), c(500, 500),lwd =4,lty =3, col="red") abline(v=mean(cadeiafinal ),lwd =4, col="red") abline(v=probabilidade,lwd =2, col="blue") legend("topleft",lty =c(3, 1, 1),lwd =c(4, 4, 2),bty ="n",cex =0.8, col=c("red", "red", "blue"), legend=c("Intervalo de confiança", "Média das estimativas", "Probabilidade usada nas estimativas")) plot(density(cadeiafinal ),ylab ="Frequência",xlab ="Probabilidades",xlim =c(0, 1), frame=F)
lines(c(intconf [1],intconf [2]), c(0.25, 0.25),lwd =3,lty =2, col="red") abline(v=mean(cadeiafinal ),lwd =1, col="red") abline(v=probabilidade,lwd =1, col="blue") legend("topleft",lty =c(3, 1, 1),lwd =c(2, 1, 1),bty ="n",cex =0.8, col=c("red", "red", "blue"), legend=c("Intervalo de confiança", "Média das estimativas", "Probabilidade usada nas estimativas")) layout(matrix (c(1, 2, 3, 4), ncol=2)) hist(cadeia [1:100],ylab ="Frequência na cadeia",xlab ="Probabilidades",main ="100 primeiros valores",xlim =c(0, 1)) plot(0, 0,xlim =c(0, 100),ylim =c(0, 1),type ="n", frame=F,main ="Cadeia", xlab ="Posição na cadeia",ylab ="Probabilidade") points(cadeia [1:100],type ="l" ) hist(cadeia [10000:10500],ylab ="Frequência na cadeia",xlab ="Probabilidades",main ="Do 10000 ao 10500",xlim =c(0, 1)) plot(0, 0,xlim =c(0, 500),ylim =c(0, 1),type ="n", frame=F,main ="Cadeia", xlab ="Posição na cadeia",ylab ="Probabilidade",xaxt ="n") axis(1,at =seq(0, 500, by=50), labels=seq(10000, 10500, by=50)) points(cadeia [10000:10500],type ="l" ) # Evidencia para o modelo, p(D). media <-mean(cadeiafinal ) desvio <-sd(cadeiafinal ) a = media * ( (media *(1-media )/desvio ^2) - 1 ) b = (1-media ) * ( (media *(1-media )/desvio ^2) - 1 ) wtdEvid = dbeta( cadeiafinal , a , b ) / ( likelihood ( cadeiafinal , meusdados ) * prior ( cadeiafinal ) ) pData = 1 / mean( wtdEvid ) format (pData,scientific = F)
Anexo III – Help da função metrop
metrop package:mcmc R Documentation
Metropolis Algorithm
Description:
Markov chain Monte Carlo for continuous random vector using a
Metropolis algorithm.
Usage:
metrop(obj, initial, nbatch, blen = 1, nspac = 1, scale = 1,
outfun, debug = FALSE, ...)
Arguments:
obj: an R function that evaluates the log unno rmalized
probability density of the desired equilibrium dist ribution of the
Markov chain. First argument is the state vector o f the Markov
chain. Other arguments arbitrary and taken from th e ‘...’
arguments of this function. Should return ‘- Inf’ for points
of the state space having probability zero under th e desired
equilibrium distribution. Alternatively, an object of class
‘"metropolis"’ from a previous run can be supplied, in which
case any missing arguments (including the log unnor malized
density function) are taken from this object (up un til
version 0.7-2 this was incorrect with respect to th e ‘debug’
argument, now it applies to it too).
initial: a real vector, the initial state of the Ma rkov chain.
nbatch: the number of batches.
blen: the length of batches.
nspac: the spacing of iterations that contribute to batches.
scale: controls the proposal step size. If scalar or vector, the
proposal is ‘x + scale * z’ where ‘x’ is the curren t state
and ‘z’ is a standard normal random vector. If mat rix, the
proposal is ‘x + scale %*% z’.
outfun: controls the output. If a function, then t he batch means of
‘outfun(state, ...)’ are returned. If a numeric or logical vector,
then the batch means of ‘state[outfun]’ (if this ma kes sense). If
missing, the the batch means of ‘state’ are returne d.
debug: if ‘TRUE’ extra output useful for testing.
...: additional arguments for ‘obj’ or ‘outfun’.
Details:
Runs a “random-walk” Metropolis algorithm, ter minology introduced
by Tierney (1994), with multivariate normal proposa l producing a
Markov chain with equilibrium distribution having a specified
unnormalized density. Distribution must be continu ous. Support of
the distribution is the support of the density spec ified by argument
‘obj’. The initial state must satisfy ‘obj(state, . ..) > - Inf’.
Description of a complete MCMC analysis (Bayesian l ogistic regression)
using this function can be found in the vignette ‘demo’ (<URL:
../doc/demo.pdf>).
Suppose the function coded by the log unnormal ized function
(either ‘obj’ or ‘obj$lud’) is actually a log unnor malized density,
that is, if w denotes that function, then exp(w) in tegrates to some
value strictly between zero and infinity. Then the ‘metrop’ function
always simulates a reversible, Harris ergodic Marko v chain having the
equilibrium distribution with this log unnormalized density. The chain
is not guaranteed to be geometrically ergodic. In fact it cannot be
geometrically ergodic if the tails of the log unnor malized density are
suficiently heavy. The ‘morph.metrop’ function dea ls with this
situation.
Value:
an object of class ‘"mcmc"’, subclass ‘"metrop olis"’, which is a
list containing at least the following components:
accept: fraction of Metropolis proposals accepted.
batch: ‘nbatch’ by ‘p’ matrix, the batch means, whe re ‘p’ is the
dimension of the result of ‘outfun’ if ‘outfun’ is a function,
otherwise the dimension of ‘state[outfun]’ if that makes sense,
and the dimension of ‘state’ when ‘outfun’ is missi ng.
initial: value of argument ‘initial’.
final: final state of Markov chain.
initial.seed: value of ‘.Random.seed’ before the ru n.
final.seed: value of ‘.Random.seed’ after the run.
time: running time of Markov chain from ‘system.tim e()’.
lud: the function used to calculate log unnor malized density,
either ‘obj’ or ‘obj$lud’ from a previous run.
nbatch: the argument ‘nbatch’ or ‘obj$nbatch’.
blen: the argument ‘blen’ or ‘obj$blen’.
nspac: the argument ‘nspac’ or ‘obj$nspac’.
outfun: the argument ‘outfun’ or ‘obj$outfun’.
Description of additional output when ‘debug = TRUE’ can be found
in the vignette ‘debug’ (<URL: ../doc/debug.pd f>).
Warning:
If ‘outfun’ is missing or not a function, then the log
unnormalized density can be defined without a ... argument and
that works fine. One can define it starting ‘l udfun <-
function(state)’ and that works or ‘ludfun <- function(state,
foo,
bar)’, where ‘foo’ and ‘bar’ are supplied as a dditional arguments
to ‘metrop’.
If ‘outfun’ is a function, then both it and th e log unnormalized
density function can be defined without ... ar guments _if they
have exactly the same arguments list_ and that works fine.
Otherwise it doesn't work. Start the definiti ons ‘ludfun <-
function(state, foo)’ and ‘outfun <- function( state, bar)’ and
you
get an error about unused arguments. Instead start the
definitions ‘ludfun <- function(state, foo, .. .)’ and ‘outfun <-
function(state, bar, ...)’, supply ‘foo’ and ‘ bar’ as additional
arguments to ‘metrop’, and that works fine.
In short, the log unnormalized density functio n and ‘outfun’ need
to have ... in their arguments list to be safe . Sometimes it
works when ... is left out and sometimes it do esn't.
Of course, one can avoid this whole issue by a lways defining the
log unnormalized density function and ‘outfun’ to have only one
argument ‘state’ and use global variables (obj ects in the R
global
environment) to specify any other information these functions
need
to use. That too follows the R way. But some people consider
that bad programming practice.
References:
Tierney, L. (1994) Markov chains for exploring posterior
distributions (with discussion). _Annals of St atistics_ *22*
1701-1762.
See Also:
‘morph.metrop’
Examples:
h <- function(x) if (all(x >= 0) && sum(x) <= 1) return(1) else
return(-Inf)
out <- metrop(h, rep(0, 5), 1000)
out$accept
# acceptance rate too low
out <- metrop(out, scale = 0.1)
out$accept
# acceptance rate o. k. (about 25 percent)
plot(out$batch[ , 1])
# but run length too short (few excursions fro m end to end of
range)
out <- metrop(out, nbatch = 1e4)
out$accept
plot(out$batch[ , 1])
hist(out$batch[ , 1])
Referências
Hastings, W.K. (1970). Monte Carlo sampling methods using Markov chains and their
applications. Biometrika, 57:97-109.
Metropolis, N., Rosenbluth, A., Rosenbluth, M., Teller, A., Teller, E.. (1953). Equations of
State Calculations by Fast Computing Machines. J. Chem. Phys. 21: 1087-1091