Quiero implementar el algoritmo EM manualmente y luego compararlo con los resultados normalmixEM
del mixtools
paquete. Por supuesto, sería feliz si ambos conducen a los mismos resultados. La referencia principal es Geoffrey McLachlan (2000), Modelos de mezclas finitas .
Tengo una densidad de mezcla de dos gaussianos, en forma general, la probabilidad logarítmica está dada por (McLachlan página 48):
El paso E ahora es el cálculo de la expectativa condicional:
Traté de escribir un código R (los datos se pueden encontrar aquí ).
# EM algorithm manually
# dat is the data
# initial values
pi1 <- 0.5
pi2 <- 0.5
mu1 <- -0.01
mu2 <- 0.01
sigma1 <- 0.01
sigma2 <- 0.02
loglik[1] <- 0
loglik[2] <- sum(pi1*(log(pi1) + log(dnorm(dat,mu1,sigma1)))) +
sum(pi2*(log(pi2) + log(dnorm(dat,mu2,sigma2))))
tau1 <- 0
tau2 <- 0
k <- 1
# loop
while(abs(loglik[k+1]-loglik[k]) >= 0.00001) {
# E step
tau1 <- pi1*dnorm(dat,mean=mu1,sd=sigma1)/(pi1*dnorm(x,mean=mu1,sd=sigma1) +
pi2*dnorm(dat,mean=mu2,sd=sigma2))
tau2 <- pi2*dnorm(dat,mean=mu2,sd=sigma2)/(pi1*dnorm(x,mean=mu1,sd=sigma1) +
pi2*dnorm(dat,mean=mu2,sd=sigma2))
# M step
pi1 <- sum(tau1)/length(dat)
pi2 <- sum(tau2)/length(dat)
mu1 <- sum(tau1*x)/sum(tau1)
mu2 <- sum(tau2*x)/sum(tau2)
sigma1 <- sum(tau1*(x-mu1)^2)/sum(tau1)
sigma2 <- sum(tau2*(x-mu2)^2)/sum(tau2)
loglik[k] <- sum(tau1*(log(pi1) + log(dnorm(x,mu1,sigma1)))) +
sum(tau2*(log(pi2) + log(dnorm(x,mu2,sigma2))))
k <- k+1
}
# compare
library(mixtools)
gm <- normalmixEM(x, k=2, lambda=c(0.5,0.5), mu=c(-0.01,0.01), sigma=c(0.01,0.02))
gm$lambda
gm$mu
gm$sigma
gm$loglik
El algoritmo no funciona, ya que algunas observaciones tienen la probabilidad de cero y el registro de esto sí -Inf
. ¿Dónde está mi error?
fuente
Respuestas:
Tiene varios problemas en el código fuente:
Como señaló @Pat, no debe usar log (dnorm ()) ya que este valor puede llegar fácilmente al infinito. Deberías usar logmvdnorm
Cuando use la suma , tenga en cuenta que elimina los valores infinitos o faltantes
Su variable de bucle k está mal, debe actualizar loglik [k + 1] pero actualiza loglik [k]
Los valores iniciales para su método y mixtools son diferentes. Está usando en su método, pero está usando para mixtools (es decir, desviación estándar, del manual de mixtools).Σ σ
Sus datos no se ven como una mezcla de lo normal (verifique el histograma que tracé al final). Y un componente de la mezcla tiene un SD muy pequeño, así que agregué arbitrariamente una línea para configurar y para que sean iguales para algunas muestras extremas. Los agrego solo para asegurarme de que el código pueda funcionar.τ1 τ2
También le sugiero que ponga códigos completos (p. Ej., Cómo inicializa loglik []) en su código fuente y sangría el código para que sea fácil de leer.
Después de todo, gracias por presentar el paquete mixtools , y planeo usarlos en mi investigación futura.
También pongo mi código de trabajo para su referencia:
Historgram
fuente
loklik <- rep(NA, 100)
que asignará previamente loglik [1], loglik [2] ... loglik [100]. Planteo esa pregunta porque en su código original, no encontré la delcaración de loglik, ¿tal vez el código se trunca durante el pegado?Sigo recibiendo un error al intentar abrir su archivo .rar, pero eso puede ser solo que estoy haciendo algo tonto.
Si ese es el problema, hay algunas soluciones posibles:
evaluar
pero con tau movido obtienes
Otra solución es expandir las cosas dentro del logaritmo. Asumiendo que estás usando logaritmos naturales:
Matemáticamente es lo mismo, pero debería ser más resistente a los errores de coma flotante, ya que ha evitado calcular una gran potencia negativa. Esto significa que ya no puede usar la función de evaluación de normas incorporada, pero si eso no es un problema, esta es probablemente la mejor respuesta. Por ejemplo, digamos que tenemos la situación donde
fuente