EM 알고리즘 수동 구현


20

나는 수동으로 EM 알고리즘을 구현하고 다음의 결과를 비교하려는 normalmixEMmixtools패키지로 제공된다. 물론 둘 다 동일한 결과를 이끌어 내면 기쁠 것입니다. 주요 참고 자료는 Geoffrey McLachlan (2000), 유한 혼합물 모델 입니다.

나는 두 가지 가우시안의 혼합 밀도를 가지고 있으며 일반적으로 로그 가능성은 (McLachlan 48 페이지)에 의해 제공됩니다.

logLc(Ψ)=i=1gj=1nzij{logπi+logfi(yi;θi)}.
하다관찰로부터이 된 경우그렇지 성분 농도. 정규 분포의 밀도이다. zij1i0fiπ는 혼합 비율이므로 은 확률이며, 관측 값은 첫 번째 가우스 분포에서 유래하고 는 관측치이며 두 번째 가우시안 분포에서 관측 된 확률입니다.π1π2

E의 단계는 이제 조건부 기대의 계산이다 :

(Ψ;Ψ(0))=이자형Ψ(0){로그기음(|Ψ)|와이}.
결과에 몇 가지 파생 된 결과가 나옵니다 (49 페이지).

τ나는(와이j;Ψ(케이))=π나는(케이)에프나는(와이j;θ나는(케이)에프(와이j;Ψ(케이)=π나는(케이)에프나는(와이j;θ나는(케이)h=1πh(케이)에프h(와이j;θh(케이))
두 가우시안의 경우 (페이지 82) :

τ나는(와이j;Ψ)=π나는ϕ(와이j;μ나는,Σ나는)h=1πhϕ(와이j;μh,Σh)
M의 단계 해주기 Q (49)의 최대화이다 :

Q(Ψ;Ψ(케이))=나는=1j=1τ나는(와이j;Ψ(케이)){로그π나는+로그에프나는(와이j;θ나는)}.
이로 인해 (두 가우시안 인 경우) (82 페이지)가됩니다.

μ나는(케이+1)=j=1τ나는j(케이)와이jj=1τ나는j(케이)Σ나는(케이+1)=j=1τ나는j(케이)(와이jμ나는(케이+1))(와이jμ나는(케이+1))j=1τ나는j(케이)
그리고 우리는 그것을 알고 있습니다 (p. 50)

π나는(케이+1)=j=1τ나는(와이j;Ψ(케이))(나는=1,,).
이 작을 때까지 E, M 단계를 반복합니다 . (Ψ(케이+1))(Ψ(케이))

R 코드를 작성하려고했습니다 (데이터는 여기 에서 찾을 수 있습니다 ).

# 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

일부 관측치는 0 일 가능성이 있고이 로그는이므로 알고리즘이 작동하지 않습니다 -Inf. 내 실수는 어디에?


문제는 통계적인 문제가 아니라 수치적인 문제입니다. 코드에서 기계 정밀도보다 작은 가능성에 대한 우발성을 추가해야합니다.
JohnRos

왜 수작업으로 확인할 수있는 매우 간단한 예제로 mixtools 함수를 수정하려고 시도하지 마십시오. 먼저 5 ~ 10 개의 값과 2 개의 시계열을 말합니다. 그런 다음 코드가 제대로 작동하면 코드를 일반화하고 각 단계에서 확인하십시오.

답변:


17

소스 코드에 몇 가지 문제가 있습니다.

  1. @Pat이 지적했듯이 log (dnorm ())을 사용하면 안됩니다.이 값은 쉽게 무한대로 갈 수 있습니다. logmvdnorm을 사용해야합니다

  2. sum 을 사용할 때 무한하거나 누락 된 값을 제거해야합니다.

  3. 루핑 변수 k가 잘못되었습니다. loglik [k + 1]을 업데이트해야하지만 loglik [k]를 업데이트해야합니다

  4. 분석법과 mixtools의 초기 값이 다릅니다. 당신이 사용하는 당신의 방법 만 사용하여 (수동 mixtools에서, 즉 표준 편차) mixtools를 들어.σΣσ

  5. 귀하의 데이터는 보통의 혼합물처럼 보이지 않습니다 (끝에 그려진 막대 그래프를 확인하십시오). 그리고 혼합물의 한 성분은 매우 작은 sd를 가지기 때문에 임의의 극단 샘플에 대해 및 를 동일하게 설정하는 선을 임의로 추가했습니다 . 코드가 작동하는지 확인하기 위해 추가합니다.τ 2τ1τ2

또한 소스 코드에 완전한 코드 (예 : loglik []를 초기화하는 방법)를 넣고 쉽게 읽을 수 있도록 코드를 들여 쓰는 것이 좋습니다.

결국 mixtools 패키지 를 소개해 주셔서 감사하며 앞으로 연구에 사용할 계획입니다.

또한 귀하의 참조를 위해 작업 코드를 넣었습니다.

# EM algorithm manually
# dat is the data
setwd("~/Downloads/")
load("datem.Rdata")
x <- dat

# initial values
pi1<-0.5
pi2<-0.5
mu1<--0.01
mu2<-0.01
sigma1<-sqrt(0.01)
sigma2<-sqrt(0.02)
loglik<- rep(NA, 1000)
loglik[1]<-0
loglik[2]<-mysum(pi1*(log(pi1)+log(dnorm(dat,mu1,sigma1))))+mysum(pi2*(log(pi2)+log(dnorm(dat,mu2,sigma2))))

mysum <- function(x) {
  sum(x[is.finite(x)])
}
logdnorm <- function(x, mu, sigma) {
  mysum(sapply(x, function(x) {logdmvnorm(x, mu, sigma)}))  
}
tau1<-0
tau2<-0
#k<-1
k<-2

# loop
while(abs(loglik[k]-loglik[k-1]) >= 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))
  tau1[is.na(tau1)] <- 0.5
  tau2[is.na(tau2)] <- 0.5

  # M step
  pi1<-mysum(tau1)/length(dat)
  pi2<-mysum(tau2)/length(dat)

  mu1<-mysum(tau1*x)/mysum(tau1)
  mu2<-mysum(tau2*x)/mysum(tau2)

  sigma1<-mysum(tau1*(x-mu1)^2)/mysum(tau1)
  sigma2<-mysum(tau2*(x-mu2)^2)/mysum(tau2)

  #  loglik[k]<-sum(tau1*(log(pi1)+log(dnorm(x,mu1,sigma1))))+sum(tau2*(log(pi2)+log(dnorm(x,mu2,sigma2))))
  loglik[k+1]<-mysum(tau1*(log(pi1)+logdnorm(x,mu1,sigma1)))+mysum(tau2*(log(pi2)+logdnorm(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

히스토그램 히스토그램


@ zahnxw 답변 주셔서 감사합니다, 그래서 내 코드가 잘못되었다는 의미입니까? 그래서 베이시 아이디어가 작동하지 않습니까?
통계 학자 Tistician

"또한 소스 코드에 완전한 코드 (예 : loglik []를 초기화하는 방법)를 넣고 쉽게 읽을 수 있도록 코드를 들여 쓰는 것이 좋습니다." 이게 내 코드 야? loglik []은 내가 게시 한 코드에서 선언 한대로 정의 되었습니까?
Stat Tistician

1
@StatTistician 아이디어는 정확하지만 구현에 결함이 있습니다. 예를 들어 언더 플로를 고려하지 않았습니다. 또한 루핑 변수 k가 혼란 스럽기 때문에 먼저 loglik [1] 및 loglik [2]를 설정하고 while 루프를 입력 한 후 loglik [1]을 다시 설정하십시오. 이것은 자연스러운 방법이 아닙니다. loglik [] 초기화에 대한 나의 제안은 code : loklik <- rep(NA, 100), 즉 loglik [1], loglik [2] ... loglik [100]을 미리 할당합니다. 원래 코드에서 loglik의 분리를 찾지 못했기 때문에 질문을 제기합니다. 붙여 넣는 동안 코드가 잘릴 수 있습니까?
zhanxw

내가 아래에 게시 한대로 : 귀하의 도움에 감사드립니다.
Stat Tistician

이제 데이터의 어떤 부분이 어떤 혼합물에 속하는지를 결정하는 방법이 있습니까?
추기경

2

.rar 파일을 열려고 시도하는 동안 오류가 계속 발생하지만 어리석은 짓일 수 있습니다.

에프(와이;θ)특급(0.5(와이μ)2/σ2)μ와이τ

이것이 문제라면 가능한 해결책이 있습니다.

τ

τ로그(에프(와이|θ))

평가하다

로그(에프(와이|θ)τ)

에프(와이|θ)τ0

  • 0로그(0)=0(나는에프)=에이

하지만 타우가 움직여서

  • 로그(00)=로그(1)=0

00=1

또 다른 해결책은 로그 내부의 항목을 확장하는 것입니다. 자연 로그를 사용한다고 가정합니다.

τ로그(에프(와이|θ))

=τ로그(특급(0.5(와이μ)2/σ2)/2πσ2)

=0.5τ로그(2πσ2)0.5τ(와이μ)2σ2

수학적으로 동일하지만 큰 음의 힘을 계산하지 않기 때문에 부동 소수점 오류에 대해 더 탄력적이어야합니다. 이것은 내장 된 표준 평가 기능을 더 이상 사용할 수 없다는 것을 의미합니다. 그러나 이것이 문제가되지 않는다면 아마도 더 나은 대답 일 것입니다. 예를 들어, 상황이 있다고 가정 해 봅시다.

0.5(와이μ)2σ2=0.5402=800

로그(특급(800))=로그(0)=나는에프


흠, 솔직히 말해서 : 나는이 일을하기에 충분하지 않습니다. 내가 관심있는 것은 : 구현 된 mixtools 패키지 버전과 알고리즘으로 동일한 결과를 얻을 수 있습니까? 그러나 내 관점에서 이것은 달을 요구하는 것 같습니다. 그러나 나는 당신이 당신의 대답에 노력을 기울 였다고 생각합니다. 감사!
Stat Tistician
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.