手動で実装されたEMアルゴリズム


20

私は手動でEMアルゴリズムを実装してからの結果と比較したいnormalmixEMmixtoolsパッケージ。もちろん、両方が同じ結果につながる場合、私は幸せです。主な参考文献は、Geoffrey McLachlan(2000)、Finite Mixture Modelsです。

2つのガウス分布の混合密度があり、一般的な形式では、対数尤度は(McLachlanページ48)で与えられます。

logLc(Ψ)=i=1gj=1nzij{logπi+logfi(yi;θi)}.
である観察からあった場合は、番目のそうでなければ、コンポーネント密度。正規分布の密度です。ので、混合物の割合である観察最初ガウス分布からのものであることは、確率であり、観察第ガウス分布からのものであることを、確率です。zij1i00fiππ1π2

Eのステップは、今条件付き期待値の計算です。

Q(Ψ;Ψ(0))=EΨ(0){logLc(|Ψ)|y}.
結果(49ページ)へのいくつかの派生の後、リードします:

τi(yj;Ψ(k))=πi(k)fi(yj;θi(k)f(yj;Ψ(k)=πi(k)fi(yj;θi(k)h=1gπh(k)fh(yj;θh(k))
2つのガウス分布の場合の(82ページ):

τi(yj;Ψ)=πiϕ(yj;μi,Σi)h=1gπhϕ(yj;μh,Σh)
Mのステップは現在、Q(49ページ)の最大化です。

Q(Ψ;Ψ(k))=i=1gj=1nτi(yj;Ψ(k)){logπi+logfi(yj;θi)}.
これは(2つのガウス分布の場合)(82ページ)につながります:

μi(k+1)=j=1nτij(k)yjj=1nτij(k)Σi(k+1)=j=1nτij(k)(yjμi(k+1))(yjμi(k+1))Tj=1nτij(k)
そして、我々はそれを知っています(p。50)

πi(k+1)=j=1nτi(yj;Ψ(k))n(i=1,,g).
が小さくなる まで、E、Mステップを繰り返します。 L(Ψ(k+1))L(Ψ(k))

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

一部の観測値にはゼロの可能性があり、この対数はであるため、アルゴリズムは機能していません-Inf。私の間違いはどこですか?


問題は統計的な問題ではなく、数値的な問題です。コードにマシンの精度よりも小さい可能性の偶発事象を追加する必要があります。
ジョンロス

手動で検証できる非常に単純な例を使用して、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回答ありがとうございます。つまり、私のコードが間違っているということですか?basiのアイデアは機能していませんか?
統計Tistician

「また、ソースコードに完全なコード(loglik []の初期化方法など)を入れ、コードをインデントして読みやすくすることをお勧めします。」さて、これは私のコードですか?loglik []は、投稿したコードで宣言したとおりに定義されていますか?
統計Tistician

1
@StatTisticianの考えは正しいが、実装には欠陥がある。たとえば、アンダーフローは考慮しませんでした。また、変数kのループは混乱を招きます。最初にloglik [1]とloglik [2]を設定し、whileループに入った後、loglik [1]を再度設定します。これは自然な方法ではありません。loglik []の初期化についての私の提案はloklik <- rep(NA, 100)、loglik [1]、loglik [2] ... loglik [100]を事前に割り当てるコードを意味します。元のコードでは、loglikの宣言が見つからなかったため、貼り付け中にコードが切り捨てられた可能性があるため、この質問を提起しますか?
-zhanxw

私が以下に投稿したように:あなたの助けをありがとう。しかし、私にとってはあまりにも高度なので、このトピックを落としています。
統計Tistician

データのどの部分がどの混合に属しているかを判断する方法はありますか?
枢機

2

.rarファイルを開こうとするとエラーが発生し続けますが、それは単に愚かなことをしているだけかもしれません。

コードに明らかなエラーは見られません。ゼロになるのは、浮動小数点の精度が原因である可能性があります。を計算するとき、評価していることにてください。これをコンピューターで実行したときに0に切り捨てられるのに、と大きな違いはありません。混合モデルでは、データの一部が各混合コンポーネントに「割り当て」られず、その結果、非常に遠く離れてしまう可能性があるため、これは二重に顕著です。理論的には、これらのポイントは値が低くなるはずです。f(y;θ)exp(0.5(yμ)2/σ2)μyτ 対数尤度を評価すると、問題に対抗しますが、浮動小数点エラーのおかげで、この段階ではすでに数量が-Infとして評価されているため、すべてが壊れます:)。

それが問題である場合、いくつかの可能な解決策があります。

1つは、を対数内に移動することです。だから評価する代わりにτ

τlog(f(y|θ))

評価する

log(f(y|θ)τ)

数学的には同じですが、とがときに何が起こるかを考えてください。現在、以下が得られます:f(y|θ)τ0

  • 0log(0)=0(Inf)=NaN

しかし、タウが移動すると、あなたは得る

  • log(00)=log(1)=0

Rが評価すると仮定します(matlabを使用する傾向があるため、Rが評価されるかどうかはわかりません)00=1

別の解決策は、対数内の要素を拡張することです。自然対数を使用していると仮定すると:

τlog(f(y|θ))

=τlog(exp(0.5(yμ)2/σ2)/2πσ2)

=0.5τlog(2πσ2)0.5τ(yμ)2σ2

数学的には同じですが、大きな負のべき乗の計算を避けたため、浮動小数点エラーに対する回復力が高くなります。これは、組み込みの標準評価関数を使用できなくなることを意味しますが、それが問題でない場合は、おそらくこれがより良い答えです。たとえば、次のような状況があるとします

0.5(yμ)2σ2=0.5402=800

私がjsutが提案したようにそれを評価すると、-800が得られます。ただし、matlabでログを取ることをexpにすると、ます。log(exp(800))=log(0)=Inf


正直言って、私はこのことを機能させるのに十分ではありません。私が興味を持ったのは、アルゴリズムでmixtoolsパッケージの実装バージョンと同じ結果を得ることができますか。しかし、私の観点から、これは月を求めているようです。しかし、あなたはあなたの答えに努力していると思うので、私はそれを受け入れます!ありがとう!
統計Tistician
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.