EM एल्गोरिथ्म मैन्युअल रूप से लागू किया गया


20

मैं ईएम एल्गोरिथ्म मैन्युअल लागू करने और उसके बाद के परिणामों की तुलना करना चाहते हैं normalmixEMका mixtoolsपैकेज। निश्चित रूप से, मुझे खुशी होगी अगर वे दोनों एक ही परिणाम के लिए नेतृत्व करेंगे। मुख्य संदर्भ जेफ्री मैकलैक्लन (2000), फ़िनाइट मिक्सचर मॉडल है

मेरे पास दो गॉसियों का मिश्रण घनत्व है, सामान्य रूप में, लॉग-लाइबिलिटी (मैक्लाक्लन पेज 48) द्वारा दिया गया है:

logLc(Ψ)=i=1gj=1nzij{logπi+logfi(yi;θi)}.
zij हैं 1 , अगर अवलोकन से था i वें घटक घनत्व, अन्यथा 0fi सामान्य वितरण का घनत्व है। π , मिश्रण अनुपात है तो π1 संभावना है, कि एक अवलोकन पहले गाऊसी वितरण से है और π2 संभावना है, कि एक अवलोकन दूसरा गाऊसी वितरण से है।

कदम अब, सशर्त उम्मीद की गणना है:

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))
दो के मामले में (82 पेज):

τi(yj;Ψ)=πiϕ(yj;μi,Σi)h=1gπhϕ(yj;μh,Σh)
एम कदम अब क्यू (पेज 49) को अधिकतम है:

Q(Ψ;Ψ(k))=i=1gj=1nτi(yj;Ψ(k)){logπi+logfi(yj;θi)}.
इससे (दो गाऊसी लोगों के मामले में) (पृष्ठ 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)
और हम जानते हैं कि (पृष्ठ 50)

πi(k+1)=j=1nτi(yj;Ψ(k))n(i=1,,g).
हम E, M चरणों को तक दोहराते हैं छोटा है। L(Ψ(k+1))L(Ψ(k))

मैंने एक आर कोड लिखने की कोशिश की (डेटा यहां पाया जा सकता है )।

# 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। मेरी गलती कहाँ है?


समस्या एक सांख्यिकीय नहीं है, बल्कि एक संख्यात्मक है। आपको अपने कोड में मशीन की तुलना में छोटे संभावना के लिए आकस्मिकता को जोड़ना चाहिए।
जॉनरोस

क्यों न आप मिक्सटूल फंक्शन को बहुत ही सरल उदाहरण के साथ प्रस्तुत करने की कोशिश करें जिसे हाथ से सत्यापित किया जा सके, सिर्फ पांच या दस मान और दो बार, पहले कहो। फिर, यदि आपको लगता है कि यह वहां काम करता है, तो अपने कोड को सामान्य करें और प्रत्येक चरण पर सत्यापित करें।

जवाबों:


17

आपको स्रोत कोड में कई समस्याएं हैं:

  1. जैसा कि @Pat ने बताया, आपको लॉग (dnorm ()) का उपयोग नहीं करना चाहिए क्योंकि यह मान आसानी से अनंत तक जा सकता है। आपको logmvdnorm का उपयोग करना चाहिए

  2. जब आप राशि का उपयोग करते हैं , तो अनंत या लापता मूल्यों को हटाने के लिए जागरूक रहें

  3. आप चर k गलत कर रहे हैं, आपको loglik [k + 1] को अद्यतन करना चाहिए लेकिन आप loglik [k] को अद्यतन करते हैं।

  4. आपकी विधि और मिक्सटूल के लिए प्रारंभिक मान अलग-अलग हैं। आप अपनी पद्धति में का उपयोग कर रहे हैं , लेकिन मिक्सटूल के लिए (मिक्सटूल मैनुअल से मानक विचलन) का उपयोग कर रहे हैं।σΣσ

  5. आपका डेटा सामान्य के मिश्रण की तरह नहीं दिखता है (चेक हिस्टोग्राम जिसे मैंने अंत में प्लॉट किया था)। और मिश्रण के एक घटक में बहुत छोटा एसडी है, इसलिए मैंने मनमाने ढंग से कुछ चरम नमूनों के बराबर होने के लिए और को सेट करने के लिए एक पंक्ति जोड़ी । मैं उन्हें सिर्फ यह सुनिश्चित करने के लिए जोड़ता हूं कि कोड काम कर सकता है।τ 2τ1τ2

मेरा यह भी सुझाव है कि आप अपने स्रोत कोड में पूर्ण कोड (जैसे कि आप loglik [] कैसे शुरू करते हैं) और कोड को पढ़ने में आसान बनाने के लिए इंडेंट करें।

आखिरकार, मिक्सटूल पैकेज शुरू करने के लिए धन्यवाद , और मैं अपने भविष्य के शोध में उनका उपयोग करने की योजना बना रहा हूं।

मैंने आपके संदर्भ के लिए अपना काम कोड भी डाला:

# 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 हिस्टोग्राम


@zahnxw आपके उत्तर के लिए धन्यवाद, तो क्या इसका मतलब है, कि मेरा कोड गलत है? तो बासी विचार काम नहीं कर रहा है?
स्टेटिस्ट टिशियन

"मैं यह भी सुझाव देता हूं कि आप अपने स्रोत कोड में पूर्ण कोड (जैसे कि आप loglik को कैसे शुरू करते हैं]] और कोड को इंडेंट करें ताकि पढ़ने में आसानी हो।" वैसे यह मेरा कोड है? loglik [] परिभाषित किया गया है क्योंकि मैंने इसे मेरे द्वारा पोस्ट किए गए कोड में घोषित किया था?
स्टेट टिशियन

1
@StatTistician का विचार सही है, लेकिन कार्यान्वयन में खामियाँ हैं। उदाहरण के लिए, आपने अंडर-फ्लो पर विचार नहीं किया। इसके अलावा, आप चर k को भ्रमित कर रहे हैं, आप पहले loglik [1] और loglik [2] को सेट करते हैं, जबकि लूप में प्रवेश करने के बाद, आप loglik [1] को फिर से सेट करते हैं। यह प्राकृतिक तरीका नहीं है। Loglik को शुरू करने के बारे में मेरा सुझाव [] का अर्थ है कोड:, loklik <- rep(NA, 100)जो loglik को आवंटित करेगा [1], loglik [2] ... loglik [100]। मैं यह प्रश्न उठाता हूं क्योंकि आपके मूल कोड में, मुझे लॉगलिक का विलोपन नहीं मिला था, शायद कोड चिपकाने के दौरान छंटनी हुई हो?
zhanxw

जैसा कि मैंने नीचे पोस्ट किया है: आपकी मदद के लिए धन्यवाद, लेकिन मैं इस विषय को छोड़ रहा हूं, क्योंकि यह मेरे लिए बहुत उन्नत है।
स्टेट टिशियन

क्या अब यह निर्धारित करने का एक तरीका है कि डेटा का कौन सा हिस्सा किस मिश्रण से संबंधित है?
कार्डिनल

2

आपकी .rar फ़ाइल को खोलने का प्रयास करते समय मुझे एक त्रुटि मिलती रहती है, लेकिन हो सकता है कि मैं कुछ मूर्खतापूर्ण कर रहा हो।

मुझे आपके कोड में कोई स्पष्ट त्रुटियाँ नहीं दिख रही हैं। एक संभावित कारण जो आपको शून्य मिल रहा है वह फ्लोटिंग पॉइंट सटीकता के कारण है। याद रखें, जब आप गणना करते हैं, तो आप मूल्यांकन कर रहे हैं । जब आप इसे कंप्यूटर पर करते हैं, तो इसके लिए और बीच बहुत बड़ा अंतर नहीं होता है । यह मिश्रण मॉडल में दोगुना ध्यान देने योग्य है, क्योंकि आपका कुछ डेटा प्रत्येक मिश्रण घटक को "असाइन" नहीं किया जाएगा और इसलिए यह बहुत दूर तक समाप्त हो सकता है। सिद्धांत रूप में इन बिंदुओं को भी कम मूल्य के साथ समाप्त होना चाहिएexp ( - 0.5 ( y - μ ) 2 / σ 2f(y;θ)exp(0.5(yμ)2/σ2)μyτ जब आप लॉग संभावना का मूल्यांकन करते हैं, तो समस्या का प्रतिकार करते हैं - लेकिन फ़्लोटिंग पॉइंट त्रुटि के लिए धन्यवाद, इस चरण से मात्रा का मूल्यांकन पहले ही किया जा चुका है, इसलिए यह सब टूट जाता है :)।

यदि यह समस्या है, तो कुछ संभावित उपाय हैं:

एक को लघुगणक के अंदर अपने को स्थानांतरित करना है । इसलिए मूल्यांकन करने के बजायτ

τlog(f(y|θ))

मूल्यांकन करना

log(f(y|θ)τ)

गणितीय एक ही है, लेकिन क्या होता है जब के बारे में सोचना और हैं । वर्तमान में आपको मिलता है:f(y|θ)τ0

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

लेकिन ताऊ के साथ आप चले गए

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

मानकर R मूल्यांकन करता है (मुझे नहीं पता कि यह होता है या नहीं जैसा कि मैं matlab का उपयोग करता हूं)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 में अगर हम करते हैं, तो हमें ।log(exp(800))=log(0)=Inf


mh, ईमानदार होना: मैं इस काम को पाने के लिए पर्याप्त नहीं हूं। मुझे इसमें क्या दिलचस्पी थी: क्या मैं अपने एल्गोरिथ्म के साथ मिक्सटूल पैकेज के कार्यान्वित संस्करण के समान परिणाम प्राप्त कर सकता हूं। लेकिन मेरे दृष्टिकोण से यह चंद्रमा के लिए पूछ रहा है। लेकिन मुझे लगता है कि आपने अपने जवाब में प्रयास किया है, इसलिए मैं इसे स्वीकार करूंगा! धन्यवाद!
स्टेट टिशियन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.