Beklenti-Maksimizasyonu Anlamak İçin Sayısal Örnek


117

Uygulayabilmek ve kullanabilmek için EM algoritmasını iyi anlamaya çalışıyorum. Tam günümü EM'nin radardan gelen konum bilgisini kullanarak uçağı izlemek için kullandığı teori ve makaleyi okuyarak geçirdim. Açıkçası, altında yatan fikri tam olarak anladığımı sanmıyorum. Birisi beni daha basit bir problem için EM'nin birkaç yinelemesini (3-4) gösteren sayısal bir örneğe işaret edebilir mi (Gauss dağılımının parametrelerini tahmin etmek veya sinüzoidal bir serinin sekansını tahmin etmek veya bir sıraya uydurmak gibi).

Biri beni bir kod parçasına (sentetik verilerle) gösterebilse bile, kodu atmaya çalışabilirim.


1
k-aracı çok em, ancak sabit varyansa sahip ve nispeten basittir.
EngrStudent

2
@ arjsgh21, uçak hakkında bahsi geçen yazıyı gönderir misiniz? Kulağa çok ilginç geliyor. Teşekkür ederim
Wakan Tanka

1
"EM Demystified: Bir Beklenti-Maksimize Etme Öğreticisi" Em algoritması hakkında çok net bir matematiksel anlayış sağladığını iddia eden çevrimiçi bir eğitim var.
Shamisen Uzman

Yanıtlar:


98

Bu EM'yi pratik ve (bence) çok sezgisel 'Coin-Toss' örneği ile öğrenmek için bir reçetedir:

  1. Do ve Batzoglou'nun bu kısa EM eğitim notunu okuyun. Bu, bozuk para atma örneğinin açıklandığı şemadır:

    görüntü tanımını buraya girin

  2. Özellikle Beklenti adımındaki olasılıkların nereden geldiğiyle ilgili olarak kafanızda soru işaretleri olabilir. Lütfen bu matematik yığın değişimi sayfasındaki açıklamalara bir göz atın .

  3. Python'da yazmış olduğum koda bakın ve madde 1'deki EM eğitim kağıdındaki yazı tura sorununun çözümünü simüle eden:

    import numpy as np
    import math
    import matplotlib.pyplot as plt
    
    ## E-M Coin Toss Example as given in the EM tutorial paper by Do and Batzoglou* ##
    
    def get_binomial_log_likelihood(obs,probs):
        """ Return the (log)likelihood of obs, given the probs"""
        # Binomial Distribution Log PDF
        # ln (pdf)      = Binomial Coeff * product of probabilities
        # ln[f(x|n, p)] =   comb(N,k)    * num_heads*ln(pH) + (N-num_heads) * ln(1-pH)
    
        N = sum(obs);#number of trials  
        k = obs[0] # number of heads
        binomial_coeff = math.factorial(N) / (math.factorial(N-k) * math.factorial(k))
        prod_probs = obs[0]*math.log(probs[0]) + obs[1]*math.log(1-probs[0])
        log_lik = binomial_coeff + prod_probs
    
        return log_lik
    
    # 1st:  Coin B, {HTTTHHTHTH}, 5H,5T
    # 2nd:  Coin A, {HHHHTHHHHH}, 9H,1T
    # 3rd:  Coin A, {HTHHHHHTHH}, 8H,2T
    # 4th:  Coin B, {HTHTTTHHTT}, 4H,6T
    # 5th:  Coin A, {THHHTHHHTH}, 7H,3T
    # so, from MLE: pA(heads) = 0.80 and pB(heads)=0.45
    
    # represent the experiments
    head_counts = np.array([5,9,8,4,7])
    tail_counts = 10-head_counts
    experiments = zip(head_counts,tail_counts)
    
    # initialise the pA(heads) and pB(heads)
    pA_heads = np.zeros(100); pA_heads[0] = 0.60
    pB_heads = np.zeros(100); pB_heads[0] = 0.50
    
    # E-M begins!
    delta = 0.001  
    j = 0 # iteration counter
    improvement = float('inf')
    while (improvement>delta):
        expectation_A = np.zeros((len(experiments),2), dtype=float) 
        expectation_B = np.zeros((len(experiments),2), dtype=float)
        for i in range(0,len(experiments)):
            e = experiments[i] # i'th experiment
              # loglikelihood of e given coin A:
            ll_A = get_binomial_log_likelihood(e,np.array([pA_heads[j],1-pA_heads[j]])) 
              # loglikelihood of e given coin B
            ll_B = get_binomial_log_likelihood(e,np.array([pB_heads[j],1-pB_heads[j]])) 
    
              # corresponding weight of A proportional to likelihood of A 
            weightA = math.exp(ll_A) / ( math.exp(ll_A) + math.exp(ll_B) ) 
    
              # corresponding weight of B proportional to likelihood of B
            weightB = math.exp(ll_B) / ( math.exp(ll_A) + math.exp(ll_B) ) 
    
            expectation_A[i] = np.dot(weightA, e) 
            expectation_B[i] = np.dot(weightB, e)
    
        pA_heads[j+1] = sum(expectation_A)[0] / sum(sum(expectation_A)); 
        pB_heads[j+1] = sum(expectation_B)[0] / sum(sum(expectation_B)); 
    
        improvement = ( max( abs(np.array([pA_heads[j+1],pB_heads[j+1]]) - 
                        np.array([pA_heads[j],pB_heads[j]]) )) )
        j = j+1
    
    plt.figure();
    plt.plot(range(0,j),pA_heads[0:j], 'r--')
    plt.plot(range(0,j),pB_heads[0:j])
    plt.show()
    

2
@ Zhubarb: Lütfen döngü sonlandırma koşulunu açıklayabilir misiniz (yani, algoritmanın ne zaman birleşeceğini belirlemek için)? "İyileştirme" değişkeni ne hesaplar?
stackoverflowuser2010

arasında 1) değişimi: @ stackoverflowuser2010, iyileşme iki delta bakar pA_heads[j+1]ve pA_heads[j]arasında 2) değişim pB_heads[j+1]ve pB_heads[j]. Ve bu iki değişimin en yüksek değerini alır. Örneğin eğer için Delta_A=0.001ve Delta_B=0.02adımdan, iyileştirme jiçin j+1olacaktır 0.02.
Zhubarb

1
@ Zhubarb: EM'de bilgisayar yakınsaması için standart bir yaklaşım mı, yoksa şu başınıza gelen bir şey mi? Standart bir yaklaşım ise, lütfen bir referans verebilir misiniz?
stackoverflowuser2010

İşte EM yakınsama üzerine bir referanstır. Kodu bir süre önce yazdım, bu yüzden çok iyi hatırlayamıyorum. Kodda gördüğünüz şeyin bu özel durum için yakınsama kriterim olduğuna inanıyorum. Buradaki fikir, A ve B için maksimum iyileştirme değerinden daha az olduğunda yinelemeleri durdurmaktır delta.
Zhubarb

1
Süper, paragrafın hangi paragraflarının yapamayacağını netleştirmek için iyi bir kod gibi bir şey yok
jon_simon

63

Sorunuz iki bölümden oluşuyor gibi geliyor: temel fikir ve somut bir örnek. Temel fikir ile başlayacağım, sonra alttaki bir örneğe link vereceğim.


ABBA

İnsanların uğraştığı en yaygın durum muhtemelen karışım dağılımlarıdır. Örneğimiz için, basit bir Gauss karışım modeline bakalım:

Farklı araç ve birim varyanslı iki farklı tek değişkenli Gauss dağılımına sahipsiniz.

Bir sürü veri noktanız var, ancak hangi noktaların hangi dağıtımdan geldiğinden emin değilsiniz ve iki dağıtımın araçlarından da emin değilsiniz.

Ve şimdi sıkışıp kaldın:

  • Gerçeğin ne anlama geldiğini biliyorsanız, hangi Gaussian'dan hangi veri noktalarının geldiğini anlayabilirsiniz. Örneğin, bir veri noktası çok yüksek bir değere sahipse, büyük olasılıkla daha yüksek ortalamaya sahip dağıtımdan geldi. Ama ne anlama geldiğini bilmiyorsun, bu yüzden işe yaramaz.

  • Her bir noktadan hangi dağılımın geldiğini biliyorsanız, o zaman iki dağılımın ne anlama geldiğini ilgili noktaların örnek yollarını kullanarak tahmin edebilirsiniz. Fakat gerçekte hangi dağıtıma hangi noktaları atayacağınızı bilmiyorsunuz, bu yüzden bu da işe yaramayacak.

Bu yüzden, hiçbir yaklaşım işe yaramadı gibi görünüyor: cevabı bulmadan önce cevabı bilmeniz gerekir ve sıkışıp kalırsınız.

EM'nin yapmasına izin veren, tüm süreci bir kerede çözmek yerine bu iki izlenebilir adım arasında geçiş yapmak.

İki araçla ilgili bir tahminde bulunmanız gerekecek (tahmininizin kesin olarak doğru olması gerekmese de, bir yerden başlamanız gerekir).

Bu araçlarla ilgili tahmininiz doğru olsaydı, yukarıdaki ilk kurşun noktama adım atmak için yeterli bilginiz olurdu ve her veri noktasını iki Gaussiandan birine (olasılıkla) atayabilirsiniz. Tahminimizin yanlış olduğunu bilmemize rağmen, hadi bunu deneyelim. Ve sonra, her bir noktanın atanmış dağılımları göz önüne alındığında, ikinci kurşun noktasını kullanan araçlar için yeni tahminler alabilirsiniz. Bu iki adımda her döngü gerçekleştirdiğinizde, modelin olasılığına daha düşük bir bağ geliştirdiğiniz anlaşılıyor.

Çok güzel bir şey: yukarıdaki kurşun noktalarındaki iki öneri ayrı ayrı çalışacak gibi gözükmese de, modeli geliştirmek için hala birlikte kullanabilirsiniz. Gerçek EM'nin sihirli yeterince tekrardan sonra, alt sınır o ve yerel maksimum arasında herhangi boşluk olmayacak kadar yüksek olacaktır olmasıdır. Sonuç olarak, yerel olarak olasılığını optimize ettiniz.

Yani , modeli henüz geliştirmediniz , artan güncellemelerle bulabileceğiniz en iyi modeli buldunuz.


Wikipedia'dan bu sayfa biraz daha karmaşık bir örnek gösteriyor (iki boyutlu Gausslar ve bilinmeyen kovaryans), ancak temel fikir aynı. Ayrıca R, örneğin uygulanması için iyi yorumlanmış bir kod da içerir .

Kodda, “Beklenti” basamağı (E-basamağı) ilk kurşun noktama karşılık geliyor: her Gauss için mevcut parametreler göz önüne alındığında, her Gaussian'ın her veri noktası için hangi Gaussian'ın sorumluluğunu aldığını bulmak. "Maksimizasyon" adımı (M-adımı), bu ikinci atama noktamdaki gibi, bu atamalar verilen araçları ve kovaryansları günceller.

Animasyonda görebileceğiniz gibi, bu güncellemeler hızlı bir şekilde algoritmanın bir dizi korkunç tahminden çok iyi bir gruba geçmesini sağlar: EM'nin bulduğu iki Gauss dağılımına odaklanmış iki nokta bulutu gibi görünüyor.


13

Burada ortalama ve standart sapmayı tahmin etmek için kullanılan Beklenti Maksimizasyonu (EM) örneği. Kod Python'dadır, ancak dili bilmeseniz bile takip etmesi kolay olmalıdır.

EM için motivasyon

Aşağıda gösterilen kırmızı ve mavi noktalar, her biri belirli bir ortalama ve standart sapmaya sahip iki farklı normal dağılımdan alınmıştır:

görüntü tanımını buraya girin

Kırmızı dağılım için "gerçek" ortalama ve standart sapma parametrelerinin makul tahminlerini hesaplamak için, kırmızı noktalara çok kolay bir şekilde bakabilir ve her birinin konumunu kaydedebilir ve sonra bilinen formülleri kullanabiliriz (ve benzer şekilde mavi grup için). .

Şimdi, iki puan grubunun olduğunu bildiğimiz durumu düşünün, ancak hangi noktanın hangi gruba ait olduğunu göremeyiz. Başka bir deyişle, renkler gizlenir:

görüntü tanımını buraya girin

Noktaları iki gruba nasıl ayıracağınız hiç belli değil. Artık kırmızı dağılımın veya mavi dağılımın parametrelerine ilişkin konumlara bakıp tahminleri hesaplayamıyoruz.

EM'nin sorunu çözmek için kullanılabileceği yer burasıdır.

Parametreleri tahmin etmek için EM kullanma

Yukarıda gösterilen noktaları oluşturmak için kullanılan kod. Noktaların çizildiği normal dağılımların gerçek araçlarını ve standart sapmalarını görebilirsiniz. Değişkenler redve blueher bir noktanın sırasıyla kırmızı ve mavi gruplardaki pozisyonlarını tutun:

import numpy as np
from scipy import stats

np.random.seed(110) # for reproducible random results

# set parameters
red_mean = 3
red_std = 0.8

blue_mean = 7
blue_std = 2

# draw 20 samples from normal distributions with red/blue parameters
red = np.random.normal(red_mean, red_std, size=20)
blue = np.random.normal(blue_mean, blue_std, size=20)

both_colours = np.sort(np.concatenate((red, blue)))

Biz ise olabilir her noktanın renk görmek, denemek ve kütüphane işlevleri kullanarak ortalamaları ve standart sapmaları kurtarmak olacaktır:

>>> np.mean(red)
2.802
>>> np.std(red)
0.871
>>> np.mean(blue)
6.932
>>> np.std(blue)
2.195

Fakat renkler bizden gizlendiğinden, EM işlemine başlayacağız ...

İlk önce, sadece her grubun parametreleri için değerleri tahmin ediyoruz ( adım 1 ). Bu tahminlerin iyi olması gerekmiyor:

# estimates for the mean
red_mean_guess = 1.1
blue_mean_guess = 9

# estimates for the standard deviation
red_std_guess = 2
blue_std_guess = 1.7

görüntü tanımını buraya girin

Oldukça kötü tahminler - araçlar, bir grup grubun herhangi bir "ortasından" uzun bir yol gibi görünüyor.

EM ile devam etmek ve bu tahminleri geliştirmek için, ortalama ve standart sapma için bu tahminler altında görünen her veri noktasının (gizli renginden bağımsız olarak) olasılığını hesaplıyoruz ( adım 2 ).

Değişken both_coloursher veri noktasını tutar. İşlev stats.norm, verilen parametrelerle normal bir dağılım altındaki noktanın olasılığını hesaplar:

likelihood_of_red = stats.norm(red_mean_guess, red_std_guess).pdf(both_colours)
likelihood_of_blue = stats.norm(blue_mean_guess, blue_std_guess).pdf(both_colours)

Bu bize, örneğin mevcut tahminlerimizde 1.761'deki veri noktasının kırmızı (0.189) 'dan mavi (0.00003)' ten çok daha muhtemel olduğunu söylemektedir.

Bu iki olasılık değerini ağırlıklara dönüştürebiliriz ( 3. adım ), böylece 1'i toplarlar:

likelihood_total = likelihood_of_red + likelihood_of_blue

red_weight = likelihood_of_red / likelihood_total
blue_weight = likelihood_of_blue / likelihood_total

Mevcut tahminlerimiz ve yeni hesaplanan ağırlıklarımızla, şimdi parametreler için yeni, muhtemelen daha iyi tahminler hesaplayabiliriz ( adım 4 ). Ortalama için bir fonksiyona ve standart sapma için bir fonksiyona ihtiyacımız var:

def estimate_mean(data, weight):
    return np.sum(data * weight) / np.sum(weight)

def estimate_std(data, weight, mean):
    variance = np.sum(weight * (data - mean)**2) / np.sum(weight)
    return np.sqrt(variance)

Bunlar, normal fonksiyonlara verinin ortalama ve standart sapmasına çok benziyor. Fark, weighther veri noktasına ağırlık atayan bir parametrenin kullanılmasıdır .

Bu ağırlıklandırma EM'nin anahtarıdır. Bir veri noktasındaki bir rengin ağırlığı arttıkça, veri noktası o rengin parametreleri için sonraki tahminleri o kadar fazla etkiler. Sonuç olarak, bu her parametreyi doğru yönde çekme etkisine sahiptir.

Yeni tahminler bu fonksiyonlarla hesaplanır:

# new estimates for standard deviation
blue_std_guess = estimate_std(both_colours, blue_weight, blue_mean_guess)
red_std_guess = estimate_std(both_colours, red_weight, red_mean_guess)

# new estimates for mean
red_mean_guess = estimate_mean(both_colours, red_weight)
blue_mean_guess = estimate_mean(both_colours, blue_weight)

EM süreci daha sonra bu yeni tahminlerle 2. adımdan itibaren tekrarlanır. Belirli bir yineleme sayısı için adımları tekrarlayabiliriz (örneğin, 20) ya da yakınsak parametreleri görene kadar.

Beş tekrardan sonra, ilk kötü tahminlerimizin iyileşmeye başladığını görüyoruz:

görüntü tanımını buraya girin

20 yinelemeden sonra, EM süreci az çok yakınlaşmıştır:

görüntü tanımını buraya girin

Karşılaştırma için, renk bilgilerinin gizlenmediği hesaplanan değerlerle karşılaştırıldığında EM sürecinin sonuçları:

          | EM guess | Actual 
----------+----------+--------
Red mean  |    2.910 |   2.802
Red std   |    0.854 |   0.871
Blue mean |    6.838 |   6.932
Blue std  |    2.227 |   2.195

Not: Bu yanıt yığın taşması benim cevap uyarlanmıştır burada .


10

Zhubarb'ın cevabını takiben, GNU R'da Do ve Batzoglou "bozuk para" EM örneğini uyguladım mle. stats4Paketin işlevini kullandığımı not et - bu EM ve MLE'nin nasıl ilişkili olduğunu daha net anlamama yardımcı oldu.

require("stats4");

## sample data from Do and Batzoglou
ds<-data.frame(heads=c(5,9,8,4,7),n=c(10,10,10,10,10),
    coin=c("B","A","A","B","A"),weight_A=1:5*0)

## "baby likelihood" for a single observation
llf <- function(heads, n, theta) {
  comb <- function(n, x) { #nCr function
    return(factorial(n) / (factorial(x) * factorial(n-x)))
  }
  if (theta<0 || theta >1) { # probabilities should be in [0,1]
    return(-Inf);
  }
  z<-comb(n,heads)* theta^heads * (1-theta)^(n-heads);
  return (log(z))
}

## the "E-M" likelihood function
em <- function(theta_A,theta_B) {
  # expectation step: given current parameters, what is the likelihood
  # an observation is the result of tossing coin A (vs coin B)?
  ds$weight_A <<- by(ds, 1:nrow(ds), function(row) {
    llf_A <- llf(row$heads,row$n, theta_A);
    llf_B <- llf(row$heads,row$n, theta_B);

    return(exp(llf_A)/(exp(llf_A)+exp(llf_B)));
  })

  # maximisation step: given params and weights, calculate likelihood of the sample
  return(- sum(by(ds, 1:nrow(ds), function(row) {
    llf_A <- llf(row$heads,row$n, theta_A);
    llf_B <- llf(row$heads,row$n, theta_B);

    return(row$weight_A*llf_A + (1-row$weight_A)*llf_B);
  })))
}

est<-mle(em,start = list(theta_A=0.6,theta_B=0.5), nobs=NROW(ds))

1
@ user3096626 Lütfen maksimizasyon adımında neden bir A madeni para olasılığını (satır $ weight_A) günlük olasılıkla (llf_A) çarptığınızı açıklayabilir misiniz? Bunu yapmamız için özel bir kural veya sebep var mı? Demek istediğim, kişi olasılıkları ya da mantıksallıkları çoğaltacaktır ama aynı anda birbirine karışmayacaktı. Ben de yeni bir konu
Alina,


5

Zhubarb tarafından verilen cevap harika, fakat ne yazık ki Python'da. Aşağıda, aynı problem üzerinde yürütülen EM algoritmasının bir Java uygulaması bulunmaktadır (Do ve Batzoglou tarafından yazılmıştır, 2008). Parametrelerin nasıl birleştiğini görmek için standart çıktıya bazı printf'ler ekledim.

thetaA = 0.71301, thetaB = 0.58134
thetaA = 0.74529, thetaB = 0.56926
thetaA = 0.76810, thetaB = 0.54954
thetaA = 0.78316, thetaB = 0.53462
thetaA = 0.79106, thetaB = 0.52628
thetaA = 0.79453, thetaB = 0.52239
thetaA = 0.79593, thetaB = 0.52073
thetaA = 0.79647, thetaB = 0.52005
thetaA = 0.79667, thetaB = 0.51977
thetaA = 0.79674, thetaB = 0.51966
thetaA = 0.79677, thetaB = 0.51961
thetaA = 0.79678, thetaB = 0.51960
thetaA = 0.79679, thetaB = 0.51959
Final result:
thetaA = 0.79678, thetaB = 0.51960

Java kodu aşağıdadır:

import java.util.*;

/*****************************************************************************
This class encapsulates the parameters of the problem. For this problem posed
in the article by (Do and Batzoglou, 2008), the parameters are thetaA and
thetaB, the probability of a coin coming up heads for the two coins A and B.
*****************************************************************************/
class Parameters
{
    double _thetaA = 0.0; // Probability of heads for coin A.
    double _thetaB = 0.0; // Probability of heads for coin B.

    double _delta = 0.00001;

    public Parameters(double thetaA, double thetaB)
    {
        _thetaA = thetaA;
        _thetaB = thetaB;
    }

    /*************************************************************************
    Returns true if this parameter is close enough to another parameter
    (typically the estimated parameter coming from the maximization step).
    *************************************************************************/
    public boolean converged(Parameters other)
    {
        if (Math.abs(_thetaA - other._thetaA) < _delta &&
            Math.abs(_thetaB - other._thetaB) < _delta)
        {
            return true;
        }

        return false;
    }

    public double getThetaA()
    {
        return _thetaA;
    }

    public double getThetaB()
    {
        return _thetaB;
    }

    public String toString()
    {
        return String.format("thetaA = %.5f, thetaB = %.5f", _thetaA, _thetaB);
    }

}


/*****************************************************************************
This class encapsulates an observation, that is the number of heads
and tails in a trial. The observation can be either (1) one of the
observed observations, or (2) an estimated observation resulting from
the expectation step.
*****************************************************************************/
class Observation
{
    double _numHeads = 0;
    double _numTails = 0;

    public Observation(String s)
    {
        for (int i = 0; i < s.length(); i++)
        {
            char c = s.charAt(i);

            if (c == 'H')
            {
                _numHeads++;
            }
            else if (c == 'T')
            {
                _numTails++;
            }
            else
            {
                throw new RuntimeException("Unknown character: " + c);
            }
        }
    }

    public Observation(double numHeads, double numTails)
    {
        _numHeads = numHeads;
        _numTails = numTails;
    }

    public double getNumHeads()
    {
        return _numHeads;
    }

    public double getNumTails()
    {
        return _numTails;
    }

    public String toString()
    {
        return String.format("heads: %.1f, tails: %.1f", _numHeads, _numTails);
    }

}

/*****************************************************************************
This class runs expectation-maximization for the problem posed by the article
from (Do and Batzoglou, 2008).
*****************************************************************************/
public class EM
{
    // Current estimated parameters.
    private Parameters _parameters;

    // Observations from the trials. These observations are set once.
    private final List<Observation> _observations;

    // Estimated observations per coin. These observations are the output
    // of the expectation step.
    private List<Observation> _expectedObservationsForCoinA;
    private List<Observation> _expectedObservationsForCoinB;

    private static java.io.PrintStream o = System.out;

    /*************************************************************************
    Principal constructor.
    @param observations The observations from the trial.
    @param parameters The initial guessed parameters.
    *************************************************************************/
    public EM(List<Observation> observations, Parameters parameters)
    {
        _observations = observations;
        _parameters = parameters;
    }

    /*************************************************************************
    Run EM until parameters converge.
    *************************************************************************/
    public Parameters run()
    {

        while (true)
        {
            expectation();

            Parameters estimatedParameters = maximization();

            o.printf("%s\n", estimatedParameters);

            if (_parameters.converged(estimatedParameters)) {
                break;
            }

            _parameters = estimatedParameters;
        }

        return _parameters;

    }

    /*************************************************************************
    Given the observations and current estimated parameters, compute new
    estimated completions (distribution over the classes) and observations.
    *************************************************************************/
    private void expectation()
    {

        _expectedObservationsForCoinA = new ArrayList<Observation>();
        _expectedObservationsForCoinB = new ArrayList<Observation>();

        for (Observation observation : _observations)
        {
            int numHeads = (int)observation.getNumHeads();
            int numTails = (int)observation.getNumTails();

            double probabilityOfObservationForCoinA=
                binomialProbability(10, numHeads, _parameters.getThetaA());

            double probabilityOfObservationForCoinB=
                binomialProbability(10, numHeads, _parameters.getThetaB());

            double normalizer = probabilityOfObservationForCoinA +
                                probabilityOfObservationForCoinB;

            // Compute the completions for coin A and B (i.e. the probability
            // distribution of the two classes, summed to 1.0).

            double completionCoinA = probabilityOfObservationForCoinA /
                                     normalizer;
            double completionCoinB = probabilityOfObservationForCoinB /
                                     normalizer;

            // Compute new expected observations for the two coins.

            Observation expectedObservationForCoinA =
                new Observation(numHeads * completionCoinA,
                                numTails * completionCoinA);

            Observation expectedObservationForCoinB =
                new Observation(numHeads * completionCoinB,
                                numTails * completionCoinB);

            _expectedObservationsForCoinA.add(expectedObservationForCoinA);
            _expectedObservationsForCoinB.add(expectedObservationForCoinB);
        }
    }

    /*************************************************************************
    Given new estimated observations, compute new estimated parameters.
    *************************************************************************/
    private Parameters maximization()
    {

        double sumCoinAHeads = 0.0;
        double sumCoinATails = 0.0;
        double sumCoinBHeads = 0.0;
        double sumCoinBTails = 0.0;

        for (Observation observation : _expectedObservationsForCoinA)
        {
            sumCoinAHeads += observation.getNumHeads();
            sumCoinATails += observation.getNumTails();
        }

        for (Observation observation : _expectedObservationsForCoinB)
        {
            sumCoinBHeads += observation.getNumHeads();
            sumCoinBTails += observation.getNumTails();
        }

        return new Parameters(sumCoinAHeads / (sumCoinAHeads + sumCoinATails),
                              sumCoinBHeads / (sumCoinBHeads + sumCoinBTails));

        //o.printf("parameters: %s\n", _parameters);

    }

    /*************************************************************************
    Since the coin-toss experiment posed in this article is a Bernoulli trial,
    use a binomial probability Pr(X=k; n,p) = (n choose k) * p^k * (1-p)^(n-k).
    *************************************************************************/
    private static double binomialProbability(int n, int k, double p)
    {
        double q = 1.0 - p;
        return nChooseK(n, k) * Math.pow(p, k) * Math.pow(q, n-k);
    }

    private static long nChooseK(int n, int k)
    {
        long numerator = 1;

        for (int i = 0; i < k; i++)
        {
            numerator = numerator * n;
            n--;
        }

        long denominator = factorial(k);

        return (long)(numerator / denominator);
    }

    private static long factorial(int n)
    {
        long result = 1;
        for (; n >0; n--)
        {
            result = result * n;
        }

        return result;
    }

    /*************************************************************************
    Entry point into the program.
    *************************************************************************/
    public static void main(String argv[])
    {
        // Create the observations and initial parameter guess
        // from the (Do and Batzoglou, 2008) article.

        List<Observation> observations = new ArrayList<Observation>();
        observations.add(new Observation("HTTTHHTHTH"));
        observations.add(new Observation("HHHHTHHHHH"));
        observations.add(new Observation("HTHHHHHTHH"));
        observations.add(new Observation("HTHTTTHHTT"));
        observations.add(new Observation("THHHTHHHTH"));

        Parameters initialParameters = new Parameters(0.6, 0.5);

        EM em = new EM(observations, initialParameters);

        Parameters finalParameters = em.run();

        o.printf("Final result:\n%s\n", finalParameters);
    }
}

5
% Implementation of the EM (Expectation-Maximization)algorithm example exposed on:
% Motion Segmentation using EM - a short tutorial, Yair Weiss, %http://www.cs.huji.ac.il/~yweiss/emTutorial.pdf
% Juan Andrade, jandrader@yahoo.com

clear all
clc

%% Setup parameters
m1 = 2;                 % slope line 1
m2 = 6;                 % slope line 2
b1 = 3;                 % vertical crossing line 1
b2 = -2;                % vertical crossing line 2
x = [-1:0.1:5];         % x axis values
sigma1 = 1;             % Standard Deviation of Noise added to line 1
sigma2 = 2;             % Standard Deviation of Noise added to line 2

%% Clean lines
l1 = m1*x+b1;           % line 1
l2 = m2*x+b2;           % line 2

%% Adding noise to lines
p1 = l1 + sigma1*randn(size(l1));
p2 = l2 + sigma2*randn(size(l2));

%% showing ideal and noise values
figure,plot(x,l1,'r'),hold,plot(x,l2,'b'), plot(x,p1,'r.'),plot(x,p2,'b.'),grid

%% initial guess
m11(1) = -1;            % slope line 1
m22(1) = 1;             % slope line 2
b11(1) = 2;             % vertical crossing line 1
b22(1) = 2;             % vertical crossing line 2

%% EM algorithm loop
iterations = 10;        % number of iterations (a stop based on a threshold may used too)

for i=1:iterations

    %% expectation step (equations 2 and 3)
    res1 = m11(i)*x + b11(i) - p1;
    res2 = m22(i)*x + b22(i) - p2;
    % line 1
    w1 = (exp((-res1.^2)./sigma1))./((exp((-res1.^2)./sigma1)) + (exp((-res2.^2)./sigma2)));

    % line 2
    w2 = (exp((-res2.^2)./sigma2))./((exp((-res1.^2)./sigma1)) + (exp((-res2.^2)./sigma2)));

    %% maximization step  (equation 4)
    % line 1
    A(1,1) = sum(w1.*(x.^2));
    A(1,2) = sum(w1.*x);
    A(2,1) = sum(w1.*x);
    A(2,2) = sum(w1);
    bb = [sum(w1.*x.*p1) ; sum(w1.*p1)];
    temp = A\bb;
    m11(i+1) = temp(1);
    b11(i+1) = temp(2);

    % line 2
    A(1,1) = sum(w2.*(x.^2));
    A(1,2) = sum(w2.*x);
    A(2,1) = sum(w2.*x);
    A(2,2) = sum(w2);
    bb = [sum(w2.*x.*p2) ; sum(w2.*p2)];
    temp = A\bb;
    m22(i+1) = temp(1);
    b22(i+1) = temp(2);

    %% plotting evolution of results
    l1temp = m11(i+1)*x+b11(i+1);
    l2temp = m22(i+1)*x+b22(i+1);
    figure,plot(x,l1temp,'r'),hold,plot(x,l2temp,'b'), plot(x,p1,'r.'),plot(x,p2,'b.'),grid
end

4
Ham koda bir tartışma ya da açıklama ekleyebilir misiniz? Pek çok okuyucunun en azından yazdığınız dili
söylemekte fayda var

1
@Glen_b - bu MatLab. Birilerinin koduna cevabını daha kapsamlı bir şekilde not etmesinin ne kadar kibar olduğunu düşünüyorum.
EngrStudent

4

Sana Maria L Rizzo'nun R kitabından geçmeni öneririm. Bölümlerden biri, sayısal bir örnekle EM algoritmasının kullanımını içermektedir. Daha iyi anlamak için koddan geçtiğimi hatırlıyorum.

Ayrıca, başlangıçta kümelenme açısından görüntülemeye çalışın. İki farklı normal yoğunluktan 10 gözlem yapılan bir kümeleme problemi olan elle çalışın. Bu yardımcı olmalı.R :) yardım alın


2

θA=0.6θB=0.5

# gem install distribution
require 'distribution'

# error bound
EPS = 10**-6

# number of coin tosses
N = 10

# observations
X = [5, 9, 8, 4, 7]

# randomly initialized thetas
theta_a, theta_b = 0.6, 0.5

p [theta_a, theta_b]

loop do
  expectation = X.map do |h|
    like_a = Distribution::Binomial.pdf(h, N, theta_a)
    like_b = Distribution::Binomial.pdf(h, N, theta_b)

    norm_a = like_a / (like_a + like_b)
    norm_b = like_b / (like_a + like_b)

    [norm_a, norm_b, h]
  end

  maximization = expectation.each_with_object([0.0, 0.0, 0.0, 0.0]) do |(norm_a, norm_b, h), r|
    r[0] += norm_a * h; r[1] += norm_a * (N - h)
    r[2] += norm_b * h; r[3] += norm_b * (N - h)
  end

  theta_a_hat = maximization[0] / (maximization[0] + maximization[1])
  theta_b_hat = maximization[2] / (maximization[2] + maximization[3])

  error_a = (theta_a_hat - theta_a).abs / theta_a
  error_b = (theta_b_hat - theta_b).abs / theta_b

  theta_a, theta_b = theta_a_hat, theta_b_hat

  p [theta_a, theta_b]

  break if error_a < EPS && error_b < EPS
end
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.