อัลกอริทึม EM ดำเนินการด้วยตนเอง


20

ฉันต้องการใช้อัลกอริทึม EM ด้วยตนเองแล้วเปรียบเทียบกับผลลัพธ์normalmixEMของmixtoolsแพ็คเกจ แน่นอนฉันจะมีความสุขถ้าพวกเขาทั้งสองนำไปสู่ผลลัพธ์เดียวกัน อ้างอิงหลักคือเจฟฟรีย์ McLachlan (2000) จำกัด ผสมรุ่น

ฉันมีความหนาแน่นของสอง Gaussians ในรูปแบบทั่วไปบันทึกความเป็นไปได้ที่ได้รับ (McLachlan หน้า 48):

logLc(Ψ)=i=1gj=1nzij{logπi+logfi(yi;θi)}.
เป็นถ้าสังเกตได้จาก THความหนาแน่นของส่วนประกอบมิฉะนั้น0คือความหนาแน่นของการกระจายปกติ เป็นสัดส่วนผสมดังนั้นความน่าจะเป็นที่สังเกตจากการกระจายแบบเกาส์เป็นครั้งแรกและความน่าจะเป็นที่สังเกตจากการกระจายเสียนที่สองzij1ผม0ผมππ1π2

Eขั้นตอนคือตอนนี้การคำนวณของความคาดหวังที่มีเงื่อนไข:

Q(Ψ;Ψ(0))=EΨ(0){เข้าสู่ระบบL(|Ψ)|Y}.
ซึ่งนำไปสู่หลังจากผลลัพธ์ที่ได้มาไม่กี่ (หน้า 49):

τผม(YJ;Ψ(k))=πผม(k)ผม(YJ;θผม(k)(YJ;Ψ(k)=πผม(k)ผม(YJ;θผม(k)Σชั่วโมง=1ก.πชั่วโมง(k)ชั่วโมง(YJ;θชั่วโมง(k))
ในกรณีของสอง Gaussians (หน้า 82):

τผม(YJ;Ψ)=πผมφ(YJ;μผม,Σผม)Σชั่วโมง=1ก.πชั่วโมงφ(YJ;μชั่วโมง,Σชั่วโมง)
Mขั้นตอนในขณะนี้คือสูงสุดของ Q (หน้า 49) นี้:

Q(Ψ;Ψ(k))=Σผม=1ก.ΣJ=1nτผม(YJ;Ψ(k)){เข้าสู่ระบบπผม+เข้าสู่ระบบผม(YJ;θผม)}.
สิ่งนี้นำไปสู่ ​​(ในกรณีของสอง Gaussians) (หน้า 82):

μผม(k+1)=ΣJ=1nτผมJ(k)YJΣJ=1nτผมJ(k)Σผม(k+1)=ΣJ=1nτผมJ(k)(YJ-μผม(k+1))(YJ-μผม(k+1))TΣJ=1nτผมJ(k)
และเรารู้ว่า (หน้า 50)

πผม(k+1)=ΣJ=1nτผม(YJ;Ψ(k))n(ผม=1,...,ก.).
L ( Ψ ( k + 1 ) ) - L ( Ψ ( k ) ) เราทำขั้นตอน 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อัลกอริทึมไม่ทำงานเนื่องจากข้อสังเกตบางคนมีโอกาสในการเป็นศูนย์และเข้าสู่ระบบของการมีที่นี้ ความผิดพลาดของฉันอยู่ที่ไหน


ปัญหาไม่ใช่ปัญหาเชิงสถิติ แต่เป็นปัญหาเชิงตัวเลข คุณควรเพิ่มความน่าจะเป็นที่เล็กกว่าความแม่นยำของเครื่องในรหัสของคุณ
JohnRos

ทำไมคุณไม่ลองฟังก์ชั่น mixtools ด้วยตัวอย่างง่ายๆที่สามารถตรวจสอบได้ด้วยมือพูดเพียงห้าหรือสิบค่าและสองครั้งก่อน จากนั้นหากคุณพบว่าทำงานได้ที่นั่นให้วางรหัสทั่วไปและยืนยันในแต่ละขั้น

คำตอบ:


17

คุณมีปัญหาหลายอย่างในซอร์สโค้ด:

  1. ตามที่ @Pat ชี้ให้เห็นคุณไม่ควรใช้ log (dnorm ()) เนื่องจากค่านี้สามารถไปที่อนันต์ได้อย่างง่ายดาย คุณควรใช้logmvdnorm

  2. เมื่อคุณใช้ผลรวมโปรดระวังในการลบค่าอนันต์หรือค่าที่หายไป

  3. คุณวนลูปตัวแปร k ไม่ถูกต้องคุณควรอัพเดต loglik [k + 1] แต่คุณอัพเดต loglik [k]

  4. Σσ

  5. τ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

historgram histogram


@zahnxw ขอบคุณสำหรับคำตอบของคุณนั่นหมายความว่ารหัสของฉันผิดหรือเปล่า? ดังนั้นแนวคิดพื้นฐานไม่ทำงาน?
สถิติ Tistician

"ฉันขอแนะนำให้คุณใส่รหัสที่สมบูรณ์ (เช่นวิธีการเริ่มต้น loglik []) ในซอร์สโค้ดของคุณและเยื้องโค้ดเพื่อให้อ่านง่าย" นี่คือรหัสของฉัน? loglik [] ถูกกำหนดตามที่ฉันประกาศไว้ในรหัสที่ฉันโพสต์?
สถิติ Tistician

1
@StatTistician ความคิดนั้นถูกต้อง แต่การนำไปปฏิบัติมีข้อบกพร่อง ตัวอย่างเช่นคุณไม่ได้พิจารณาการไหลของข้อมูลต่ำ นอกจากนี้เมื่อคุณวนลูปตัวแปร k ทำให้เกิดความสับสนอันดับแรกให้คุณตั้งค่า loglik [1] และ loglik [2] หลังจากป้อนห่วงลูปแล้วคุณตั้งค่า loglik [1] อีกครั้ง นี่ไม่ใช่วิธีธรรมชาติที่ต้องทำ ข้อเสนอแนะของฉันเกี่ยวกับการเริ่มต้น loglik [] หมายถึงรหัส: loklik <- rep(NA, 100)ที่จะจัดสรร loglik ล่วงหน้า [1], loglik [2] ... loglik [100] ฉันตั้งคำถามนั้นเพราะในรหัสต้นฉบับของคุณฉันไม่พบ delcaration ของ loglik อาจเป็นรหัสที่ถูกตัดทอนในระหว่างการวาง?
zhanxw

ในขณะที่ฉันโพสต์ด้านล่าง: ขอบคุณสำหรับความช่วยเหลือของคุณ แต่ฉันทิ้งหัวข้อนี้เพราะมันสูงเกินไปสำหรับฉัน
สถิติ Tistician

ขณะนี้มีวิธีในการกำหนดว่าส่วนใดของข้อมูลที่เป็นของผสมหรือไม่
พระคาร์ดินัล

2

ฉันได้รับข้อผิดพลาดเมื่อพยายามเปิดไฟล์. rar แต่นั่นอาจทำให้ฉันทำอะไรที่งี่เง่า

(Y;θ)ประสบการณ์(-0.5(Y-μ)2/σ2)μYτ

หากนั่นคือปัญหามีวิธีแก้ไขที่เป็นไปได้บางอย่าง:

τ

τเข้าสู่ระบบ((Y|θ))

ประเมินผล

เข้าสู่ระบบ((Y|θ)τ)

(Y|θ)τ0

  • 0เข้าสู่ระบบ(0)=0(-ผมn)=ยังไม่มีข้อความaยังไม่มีข้อความ

แต่ด้วยความเป็นเอกภาพทำให้คุณได้รับ

  • เข้าสู่ระบบ(00)=เข้าสู่ระบบ(1)=0

00=1

อีกวิธีคือการขยายสิ่งภายในลอการิทึม สมมติว่าคุณใช้ลอการิทึมธรรมชาติ:

τเข้าสู่ระบบ((Y|θ))

=τเข้าสู่ระบบ(ประสบการณ์(-0.5(Y-μ)2/σ2)/2πσ2)

=-0.5τเข้าสู่ระบบ(2πσ2)-0.5τ(Y-μ)2σ2

ในทางคณิตศาสตร์เหมือนกัน แต่ควรมีความยืดหยุ่นต่อข้อผิดพลาดของจุดลอยตัวมากขึ้นเนื่องจากคุณหลีกเลี่ยงการคำนวณพลังงานเชิงลบขนาดใหญ่ นี่หมายความว่าคุณไม่สามารถใช้ฟังก์ชันการประเมินแบบปกติได้ในตัว แต่ถ้านั่นไม่ใช่ปัญหานี่อาจเป็นคำตอบที่ดีกว่า ตัวอย่างเช่นสมมติว่าเรามีสถานการณ์ที่

-0.5(Y-μ)2σ2=-0.5* * * *402=-800

เข้าสู่ระบบ(ประสบการณ์(-800))=เข้าสู่ระบบ(0)=-ผมn


mh พูดตามตรง: ฉันไม่ดีพอที่จะทำให้เรื่องนี้ทำงานได้ สิ่งที่ฉันสนใจคือ: ฉันสามารถรับผลลัพธ์เดียวกันกับอัลกอริทึมของฉันเป็นแพคเกจ mixtools เวอร์ชันที่นำไปใช้งานได้หรือไม่ แต่จากมุมมองของฉันนี้ดูเหมือนว่าจะขอดวงจันทร์ แต่ฉันคิดว่าคุณใช้ความพยายามในคำตอบของคุณดังนั้นฉันจะยอมรับมัน! ขอบคุณ!
สถิติ Tistician
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.