Thuật toán EM thực hiện thủ công


20

Tôi muốn thực hiện thuật toán EM bằng tay và sau đó so sánh nó với kết quả normalmixEMcủa mixtoolsgói. Tất nhiên, tôi sẽ rất vui nếu cả hai đều dẫn đến cùng một kết quả. Tài liệu tham khảo chính là Geoffrey McLachlan (2000), Mô hình hỗn hợp hữu hạn .

Tôi có mật độ hỗn hợp của hai Gaussian, ở dạng tổng quát, khả năng đăng nhập được đưa ra bởi (McLachlan trang 48):

logLc(Ψ)=i=1gj=1nzij{logπi+logfi(yi;θi)}.
Các là , nếu quan sát là từ i thứ mật độ thành phần, nếu không 0 . Các f_i là mật độ của phân phối chuẩn. Các \ pi là tỷ lệ hỗn hợp, vì vậy \ pi_1 là xác suất, mà một quan sát là từ sự phân bố Gaussian đầu tiên và \ pi_2 là xác suất, mà một quan sát là từ sự phân bố Gaussian thứ hai.zij1i0fiππ1π2

Bước E bây giờ, tính toán kỳ vọng có điều kiện:

Q(Ψ;Ψ(0))=EΨ(0){logLc(|Ψ)|y}.
dẫn đến, sau một vài dẫn xuất cho kết quả (trang 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))
trong trường hợp hai Gaussian (trang 82):

τi(yj;Ψ)=πiϕ(yj;μi,Σi)h=1gπhϕ(yj;μh,Σh)
Bước M bây giờ là tối đa hóa Q (trang 49):

Q(Ψ;Ψ(k))=i=1gj=1nτi(yj;Ψ(k)){logπi+logfi(yj;θi)}.
Điều này dẫn đến (trong trường hợp có hai Gaussian) (trang 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)
và chúng tôi biết rằng (trang 50)

πi(k+1)=j=1nτi(yj;Ψ(k))n(i=1,,g).
Chúng tôi lặp lại các bước E, M cho đến khi nhỏ. L(Ψ(k+1))L(Ψ(k))

Tôi đã cố gắng viết một mã R (dữ liệu có thể được tìm thấy ở đây ).

# 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

Thuật toán không hoạt động, vì một số quan sát có khả năng bằng 0 và nhật ký của điều này là -Inf. Lỗi của tôi ở đâu?


Vấn đề không phải là một thống kê, mà là một số. Bạn nên thêm các trường hợp dự phòng cho khả năng nhỏ hơn độ chính xác của máy trong mã của bạn.
JohnRos

tại sao bạn không thử thực hiện chức năng mixtools bằng một ví dụ rất đơn giản có thể được xác minh bằng tay, trước tiên chỉ nói năm hoặc mười giá trị và hai lần hiển thị. sau đó, nếu bạn thấy nó hoạt động ở đó, hãy khái quát mã của bạn và xác minh ở mỗi bước.

Câu trả lời:


17

Bạn có một số vấn đề trong mã nguồn:

  1. Như @Pat đã chỉ ra, bạn không nên sử dụng log (dnorm ()) vì giá trị này có thể dễ dàng đi đến vô cùng. Bạn nên sử dụng logmvdnorm

  2. Khi bạn sử dụng tổng , hãy lưu ý để xóa các giá trị vô hạn hoặc bị thiếu

  3. Bạn lặp biến k là sai, bạn nên cập nhật loglik [k + 1] nhưng bạn cập nhật loglik [k]

  4. Các giá trị ban đầu cho phương thức và mixtools của bạn là khác nhau. Bạn đang sử dụng trong phương thức của mình, nhưng sử dụng cho mixtools (nghĩa là độ lệch chuẩn, từ hướng dẫn sử dụng mixtools).Σσ

  5. Dữ liệu của bạn trông không giống như một hỗn hợp thông thường (kiểm tra biểu đồ tôi đã vẽ ở cuối). Và một thành phần của hỗn hợp có sd rất nhỏ, vì vậy tôi đã tùy ý thêm một dòng để đặt và bằng với một số mẫu cực đoan. Tôi thêm chúng chỉ để đảm bảo mã có thể hoạt động.τ1τ2

Tôi cũng đề nghị bạn đặt mã hoàn chỉnh (ví dụ: cách bạn khởi tạo loglik []) trong mã nguồn của mình và thụt mã để dễ đọc.

Sau tất cả, cảm ơn vì đã giới thiệu gói mixtools và tôi dự định sử dụng chúng trong nghiên cứu tương lai của mình.

Tôi cũng đặt mã làm việc của mình để bạn tham khảo:

# 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

Lịch sử Biểu đồ


@zahnxw cảm ơn câu trả lời của bạn, vậy có nghĩa là mã của tôi sai? Vì vậy, ý tưởng basi không hoạt động?
Stat Tistician

"Tôi cũng đề nghị bạn nên đặt mã hoàn chỉnh (ví dụ: cách bạn khởi tạo loglik []) trong mã nguồn của mình và thụt mã để dễ đọc." Vâng đây là mã của tôi? loglik [] được định nghĩa khi tôi khai báo nó trong mã tôi đã đăng?
Stat Tistician

1
@StatTistician ý tưởng là chính xác, nhưng việc thực hiện không có sai sót. Ví dụ, bạn đã không xem xét dưới dòng chảy. Ngoài ra, bạn lặp biến k là khó hiểu, trước tiên bạn đặt loglik [1] và loglik [2], sau khi nhập vòng lặp while, bạn lại đặt loglik [1]. Đây không phải là cách tự nhiên để làm. Đề xuất của tôi về việc khởi tạo loglik [] có nghĩa là mã : loklik <- rep(NA, 100), sẽ phân bổ trước loglik [1], loglik [2] ... loglik [100]. Tôi đưa ra câu hỏi đó bởi vì trong mã gốc của bạn, tôi không tìm thấy sự phân chia loglik, có thể mã bị cắt ngắn trong quá trình dán?
zhanxw

Như tôi đã đăng dưới đây: Cảm ơn sự giúp đỡ của bạn, nhưng tôi đang bỏ qua chủ đề này, vì nó quá cao cấp đối với tôi.
Stat Tistician

Bây giờ có cách nào để xác định phần nào của dữ liệu thuộc về hỗn hợp nào không?
Đức Hồng Y

2

Tôi liên tục gặp lỗi khi cố mở tệp .rar của bạn, nhưng đó có thể chỉ là tôi làm điều gì đó ngớ ngẩn.

f(y;θ)điểm kinh nghiệm(-0,5(y-μ)2/σ2)μyτ

Nếu đó là vấn đề, có một số giải pháp có thể:

τ

τđăng nhập(f(y|θ))

đánh giá

đăng nhập(f(y|θ)τ)

f(y|θ)τ0

  • 0đăng nhập(0)= =0(-tôinf)= =NmộtN

nhưng với tau di chuyển bạn nhận được

  • đăng nhập(00)= =đăng nhập(1)= =0

00= =1

Một giải pháp khác là mở rộng ra những thứ bên trong logarit. Giả sử bạn đang sử dụng logarit tự nhiên:

τđăng nhập(f(y|θ))

= =τđăng nhập(điểm kinh nghiệm(-0,5(y-μ)2/σ2)/2πσ2)

= =-0,5τđăng nhập(2πσ2)-0,5τ(y-μ)2σ2

Về mặt toán học là như nhau, nhưng sẽ linh hoạt hơn đối với các lỗi dấu phẩy động vì bạn đã tránh tính toán một công suất âm lớn. Điều này có nghĩa là bạn không thể sử dụng chức năng đánh giá định mức tích hợp nữa, nhưng nếu đó không phải là vấn đề thì đây có lẽ là câu trả lời tốt hơn. Ví dụ: giả sử chúng ta có tình huống

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

log(exp(800))=log(0)=Inf


mh, thành thật mà nói: tôi không đủ tốt để làm cho điều này hoạt động. Điều tôi quan tâm là: Tôi có thể nhận được kết quả tương tự với thuật toán của mình như phiên bản đã triển khai của gói mixtools không. Nhưng theo quan điểm của tôi thì điều này dường như đang đòi hỏi mặt trăng. Nhưng tôi nghĩ bạn đã nỗ lực vào câu trả lời của mình, vì vậy tôi sẽ chấp nhận nó! Cảm ơn!
Stat Tistician
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.