Was ist eine intuitive Erklärung der Expectation Maximization-Technik? [geschlossen]


109

Expectation Maximization (EM) ist eine Art probabilistische Methode zur Klassifizierung von Daten. Bitte korrigieren Sie mich, wenn ich falsch liege, wenn es sich nicht um einen Klassifikator handelt.

Was ist eine intuitive Erklärung dieser EM-Technik? Was ist expectationhier und was ist maximized?


12
Was ist der Erwartungsmaximierungsalgorithmus? , Nature Biotechnology 26 , 897–899 (2008) hat ein schönes Bild, das zeigt, wie der Algorithmus funktioniert.
Chl

@chl Wie haben sie in Teil b des schönen Bildes die Werte der Wahrscheinlichkeitsverteilung auf dem Z erhalten (dh 0,45 x A, 0,55 x B usw.)?
Noob Saibot


3
Der Link zu dem von @chl erwähnten Bild wurde aktualisiert.
n1k31t4

Antworten:


119

Hinweis: Den Code hinter dieser Antwort finden Sie hier .


Angenommen, wir haben einige Daten aus zwei verschiedenen Gruppen, rot und blau:

Geben Sie hier die Bildbeschreibung ein

Hier können wir sehen, welcher Datenpunkt zur roten oder blauen Gruppe gehört. Dies macht es einfach, die Parameter zu finden, die jede Gruppe charakterisieren. Zum Beispiel liegt der Mittelwert der roten Gruppe bei 3, der Mittelwert der blauen Gruppe bei 7 (und wir könnten die genauen Mittelwerte finden, wenn wir wollten).

Dies wird allgemein als Maximum-Likelihood-Schätzung bezeichnet . Bei einigen Daten berechnen wir den Wert eines Parameters (oder von Parametern), der diese Daten am besten erklärt.

Stellen Sie sich nun vor, wir können nicht sehen, welcher Wert aus welcher Gruppe entnommen wurde. Für uns sieht alles lila aus:

Geben Sie hier die Bildbeschreibung ein

Hier haben wir das Wissen, dass es zwei Gruppen von Werten gibt, aber wir wissen nicht, zu welcher Gruppe ein bestimmter Wert gehört.

Können wir noch die Mittelwerte für die rote und die blaue Gruppe abschätzen, die am besten zu diesen Daten passen?

Ja, oft können wir! Die Erwartungsmaximierung gibt uns eine Möglichkeit, dies zu tun. Die sehr allgemeine Idee hinter dem Algorithmus ist folgende:

  1. Beginnen Sie mit einer ersten Schätzung der einzelnen Parameter.
  2. Berechnen Sie die Wahrscheinlichkeit, dass jeder Parameter den Datenpunkt erzeugt.
  3. Berechnen Sie die Gewichte für jeden Datenpunkt und geben Sie an, ob er roter oder blauer ist, basierend auf der Wahrscheinlichkeit, dass er von einem Parameter erzeugt wird. Kombinieren Sie die Gewichte mit den Daten ( Erwartung ).
  4. Berechnen Sie anhand der gewichtsangepassten Daten eine bessere Schätzung für die Parameter ( Maximierung ).
  5. Wiederholen Sie die Schritte 2 bis 4, bis die Parameterschätzung konvergiert (der Prozess erzeugt keine andere Schätzung mehr).

Diese Schritte bedürfen einer weiteren Erläuterung, daher gehe ich auf das oben beschriebene Problem ein.

Beispiel: Schätzung von Mittelwert und Standardabweichung

In diesem Beispiel werde ich Python verwenden, aber der Code sollte ziemlich leicht zu verstehen sein, wenn Sie mit dieser Sprache nicht vertraut sind.

Angenommen, wir haben zwei Gruppen, rot und blau, wobei die Werte wie im obigen Bild verteilt sind. Insbesondere enthält jede Gruppe einen Wert aus einer Normalverteilung mit den folgenden Parametern:

import numpy as np
from scipy import stats

np.random.seed(110) # for reproducible 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))) # for later use...

Hier ist noch einmal ein Bild dieser roten und blauen Gruppen (damit Sie nicht nach oben scrollen müssen):

Geben Sie hier die Bildbeschreibung ein

Wenn wir die Farbe jedes Punktes sehen können (dh zu welcher Gruppe er gehört), ist es sehr einfach, den Mittelwert und die Standardabweichung für jede Gruppe zu schätzen. Wir übergeben nur die roten und blauen Werte an die in NumPy integrierten Funktionen. Beispielsweise:

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

Aber was ist, wenn wir die Farben der Punkte nicht sehen können ? Das heißt, anstelle von Rot oder Blau wurde jeder Punkt lila gefärbt.

Um zu versuchen, die Mittelwert- und Standardabweichungsparameter für die roten und blauen Gruppen wiederherzustellen, können wir die Erwartungsmaximierung verwenden.

Unser erster Schritt ( Schritt 1 oben) besteht darin, die Parameterwerte für den Mittelwert und die Standardabweichung jeder Gruppe zu erraten. Wir müssen nicht intelligent raten; Wir können beliebige Zahlen auswählen:

# 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

Diese Parameterschätzungen erzeugen Glockenkurven, die folgendermaßen aussehen:

Geben Sie hier die Bildbeschreibung ein

Das sind schlechte Schätzungen. Beide Mittel (die vertikalen gepunkteten Linien) sehen zum Beispiel für sinnvolle Punktgruppen weit entfernt von jeder Art von "Mitte" aus. Wir wollen diese Schätzungen verbessern.

Der nächste Schritt ( Schritt 2 ) besteht darin, die Wahrscheinlichkeit zu berechnen, mit der jeder Datenpunkt unter den aktuellen Parameterschätzungen erscheint:

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)

Hier haben wir einfach jeden Datenpunkt in die Wahrscheinlichkeitsdichtefunktion für eine Normalverteilung eingefügt, wobei wir unsere aktuellen Schätzungen zum Mittelwert und zur Standardabweichung für Rot und Blau verwenden. Dies sagt uns zum Beispiel, dass nach unseren derzeitigen Schätzungen der Datenpunkt bei 1,761 viel wahrscheinlicher rot (0,189) als blau (0,00003) ist.

Für jeden Datenpunkt können wir diese beiden Wahrscheinlichkeitswerte in Gewichte umwandeln ( Schritt 3 ), sodass sie wie folgt zu 1 summieren:

likelihood_total = likelihood_of_red + likelihood_of_blue

red_weight = likelihood_of_red / likelihood_total
blue_weight = likelihood_of_blue / likelihood_total

Mit unseren aktuellen Schätzungen und unseren neu berechneten Gewichten können wir jetzt neue Schätzungen für den Mittelwert und die Standardabweichung der roten und blauen Gruppe berechnen ( Schritt 4 ).

Wir berechnen zweimal den Mittelwert und die Standardabweichung unter Verwendung aller Datenpunkte, jedoch mit unterschiedlichen Gewichtungen: einmal für die roten Gewichte und einmal für die blauen Gewichte.

Das Schlüsselelement der Intuition ist, dass je größer das Gewicht einer Farbe auf einem Datenpunkt ist, desto stärker beeinflusst der Datenpunkt die nächsten Schätzungen für die Parameter dieser Farbe. Dies hat den Effekt, dass die Parameter in die richtige Richtung "gezogen" werden.

def estimate_mean(data, weight):
    """
    For each data point, multiply the point by the probability it
    was drawn from the colour's distribution (its "weight").

    Divide by the total weight: essentially, we're finding where 
    the weight is centred among our data points.
    """
    return np.sum(data * weight) / np.sum(weight)

def estimate_std(data, weight, mean):
    """
    For each data point, multiply the point's squared difference
    from a mean value by the probability it was drawn from
    that distribution (its "weight").

    Divide by the total weight: essentially, we're finding where 
    the weight is centred among the values for the difference of
    each data point from the mean.

    This is the estimate of the variance, take the positive square
    root to find the standard deviation.
    """
    variance = np.sum(weight * (data - mean)**2) / np.sum(weight)
    return np.sqrt(variance)

# 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)

Wir haben neue Schätzungen für die Parameter. Um sie wieder zu verbessern, können wir zu Schritt 2 zurückkehren und den Vorgang wiederholen. Wir tun dies, bis die Schätzungen konvergieren oder nachdem eine bestimmte Anzahl von Iterationen durchgeführt wurde ( Schritt 5 ).

Für unsere Daten sehen die ersten fünf Iterationen dieses Prozesses folgendermaßen aus (neuere Iterationen sehen stärker aus):

Geben Sie hier die Bildbeschreibung ein

Wir sehen, dass die Mittelwerte bereits bei einigen Werten konvergieren und auch die Formen der Kurven (bestimmt durch die Standardabweichung) stabiler werden.

Wenn wir 20 Iterationen fortsetzen, erhalten wir Folgendes:

Geben Sie hier die Bildbeschreibung ein

Der EM-Prozess hat sich den folgenden Werten angenähert, die den tatsächlichen Werten sehr nahe kommen (wo wir die Farben sehen können - keine versteckten Variablen):

          | EM guess | Actual |  Delta
----------+----------+--------+-------
Red mean  |    2.910 |  2.802 |  0.108
Red std   |    0.854 |  0.871 | -0.017
Blue mean |    6.838 |  6.932 | -0.094
Blue std  |    2.227 |  2.195 |  0.032

Im obigen Code haben Sie möglicherweise bemerkt, dass die neue Schätzung für die Standardabweichung unter Verwendung der Schätzung der vorherigen Iteration für den Mittelwert berechnet wurde. Letztendlich spielt es keine Rolle, ob wir zuerst einen neuen Wert für den Mittelwert berechnen, da wir nur die (gewichtete) Varianz der Werte um einen zentralen Punkt herum finden. Die Schätzungen für die Parameter werden weiterhin konvergieren.


Was ist, wenn wir nicht einmal wissen, von wie vielen Normalverteilungen dies stammt? Hier haben Sie ein Beispiel für k = 2 Verteilungen genommen. Können wir auch k und die k-Parametersätze schätzen?
Stackit

1
@stackit: Ich bin mir nicht sicher, ob es in diesem Fall einen einfachen allgemeinen Weg gibt, den wahrscheinlichsten Wert von k als Teil des EM-Prozesses zu berechnen. Das Hauptproblem ist, dass wir EM mit Schätzungen für jeden der Parameter beginnen müssen, die wir finden möchten, und dass wir k kennen / schätzen müssen, bevor wir beginnen. Hier kann jedoch über EM der Anteil der zu einer Gruppe gehörenden Punkte geschätzt werden. Wenn wir k überschätzen, würde der Anteil aller bis auf zwei Gruppen möglicherweise auf nahe Null fallen. Ich habe nicht damit experimentiert, daher weiß ich nicht, wie gut es in der Praxis funktionieren würde.
Alex Riley

1
@AlexRiley Können Sie etwas mehr über die Formeln zur Berechnung der neuen Schätzungen für Mittelwert und Standardabweichung sagen?
Zitrone

2
@ AlexRiley Danke für die Erklärung. Warum werden die neuen Standardabweichungsschätzungen unter Verwendung der alten Schätzung des Mittelwerts berechnet? Was ist, wenn die neuen Schätzungen des Mittelwerts zuerst gefunden werden?
GoodDeeds

1
@Lemon GoodDeeds Kaushal - Entschuldigung für meine späte Antwort auf Ihre Fragen. Ich habe versucht, die Antwort zu bearbeiten, um die von Ihnen angesprochenen Punkte anzusprechen. Ich habe auch den gesamten in dieser Antwort verwendeten Code in einem Notizbuch hier zugänglich gemacht (das auch ausführlichere Erklärungen einiger Punkte enthält, die ich angesprochen habe).
Alex Riley

36

EM ist ein Algorithmus zum Maximieren einer Wahrscheinlichkeitsfunktion, wenn einige der Variablen in Ihrem Modell nicht beobachtet werden (dh wenn Sie latente Variablen haben).

Sie könnten sich fragen, wenn wir nur versuchen, eine Funktion zu maximieren, warum wir nicht einfach die vorhandene Maschinerie zum Maximieren einer Funktion verwenden. Wenn Sie versuchen, dies zu maximieren, indem Sie Derivate nehmen und auf Null setzen, stellen Sie fest, dass die Bedingungen erster Ordnung in vielen Fällen keine Lösung haben. Es gibt ein Henne-Ei-Problem, das Sie zur Lösung Ihrer Modellparameter benötigen, um die Verteilung Ihrer nicht beobachteten Daten zu kennen. Die Verteilung Ihrer nicht beobachteten Daten hängt jedoch von Ihren Modellparametern ab.

EM versucht, dies zu umgehen, indem es iterativ eine Verteilung für die nicht beobachteten Daten errät, dann die Modellparameter schätzt, indem es etwas maximiert, das eine Untergrenze für die tatsächliche Wahrscheinlichkeitsfunktion darstellt, und dies bis zur Konvergenz wiederholt:

Der EM-Algorithmus

Beginnen Sie mit der Schätzung der Werte Ihrer Modellparameter

E-Schritt: Verwenden Sie für jeden Datenpunkt mit fehlenden Werten Ihre Modellgleichung, um die Verteilung der fehlenden Daten anhand Ihrer aktuellen Schätzung der Modellparameter und der beobachteten Daten zu ermitteln (beachten Sie, dass Sie für jeden fehlenden Wert eine Verteilung suchen Wert, nicht für den erwarteten Wert). Nachdem wir nun eine Verteilung für jeden fehlenden Wert haben, können wir die Erwartung der Wahrscheinlichkeitsfunktion in Bezug auf die nicht beobachteten Variablen berechnen. Wenn unsere Vermutung für den Modellparameter korrekt war, ist diese erwartete Wahrscheinlichkeit die tatsächliche Wahrscheinlichkeit unserer beobachteten Daten. Wenn die Parameter nicht korrekt waren, handelt es sich nur um eine Untergrenze.

M-Schritt: Nachdem wir nun eine erwartete Wahrscheinlichkeitsfunktion ohne nicht beobachtete Variablen haben, maximieren Sie die Funktion wie im vollständig beobachteten Fall, um eine neue Schätzung Ihrer Modellparameter zu erhalten.

Wiederholen bis zur Konvergenz.


5
Ich verstehe deinen E-Schritt nicht. Ein Teil des Problems ist, dass ich beim Lernen dieses Materials keine Leute finden kann, die dieselbe Terminologie verwenden. Was meinst du mit Modellgleichung? Ich weiß nicht, was Sie unter einer Wahrscheinlichkeitsverteilung verstehen?
user678392

27

Hier ist ein einfaches Rezept, um den Algorithmus zur Erwartungsmaximierung zu verstehen:

1- Lesen Sie dieses EM-Tutorial von Do und Batzoglou.

2- Möglicherweise haben Sie Fragezeichen im Kopf. Schauen Sie sich die Erklärungen auf dieser Seite zum Austausch von Mathe-Stapeln an .

3- Sehen Sie sich diesen Code an, den ich in Python geschrieben habe und der das Beispiel im EM-Tutorial von Punkt 1 erklärt:

Warnung: Der Code ist möglicherweise chaotisch / suboptimal, da ich kein Python-Entwickler bin. Aber es macht den Job.

import numpy as np
import math

#### E-M Coin Toss Example as given in the EM tutorial paper by Do and Batzoglou* #### 

def get_mn_log_likelihood(obs,probs):
    """ Return the (log)likelihood of obs, given the probs"""
    # Multinomial Distribution Log PMF
    # ln (pdf)      =             multinomial coeff            *   product of probabilities
    # ln[f(x|n, p)] = [ln(n!) - (ln(x1!)+ln(x2!)+...+ln(xk!))] + [x1*ln(p1)+x2*ln(p2)+...+xk*ln(pk)]     

    multinomial_coeff_denom= 0
    prod_probs = 0
    for x in range(0,len(obs)): # loop through state counts in each observation
        multinomial_coeff_denom = multinomial_coeff_denom + math.log(math.factorial(obs[x]))
        prod_probs = prod_probs + obs[x]*math.log(probs[x])

    multinomial_coeff = math.log(math.factorial(sum(obs))) -  multinomial_coeff_denom
    likelihood = multinomial_coeff + prod_probs
    return likelihood

# 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((5,2), dtype=float) 
    expectation_B = np.zeros((5,2), dtype=float)
    for i in range(0,len(experiments)):
        e = experiments[i] # i'th experiment
        ll_A = get_mn_log_likelihood(e,np.array([pA_heads[j],1-pA_heads[j]])) # loglikelihood of e given coin A
        ll_B = get_mn_log_likelihood(e,np.array([pB_heads[j],1-pB_heads[j]])) # loglikelihood of e given coin B

        weightA = math.exp(ll_A) / ( math.exp(ll_A) + math.exp(ll_B) ) # corresponding weight of A proportional to likelihood of A 
        weightB = math.exp(ll_B) / ( math.exp(ll_A) + math.exp(ll_B) ) # corresponding weight of B proportional to likelihood of 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

Ich finde, dass Ihr Programm sowohl A als auch B auf 0,66 ergibt. Ich implementiere es auch mit scala. Finden Sie auch, dass das Ergebnis 0,66 ist. Können Sie helfen, das zu überprüfen?
Zjffdu

Wenn ich eine Tabelle verwende, finde ich Ihre 0,66-Ergebnisse nur, wenn meine anfänglichen Vermutungen gleich sind. Ansonsten kann ich die Ausgabe des Tutorials reproduzieren.
Soakley

@zjffdu, wie viele Iterationen führt die EM aus, bevor Sie 0,66 zurückgeben? Wenn Sie mit gleichen Werten initialisieren, bleibt es möglicherweise bei einem lokalen Maximum hängen und Sie werden feststellen, dass die Anzahl der Iterationen extrem niedrig ist (da es keine Verbesserung gibt).
Zhubarb

Sie können auch diese Folie von Andrew Ng und Harvards
Minh Phan

16

Technisch gesehen ist der Begriff "EM" etwas unterbestimmt, aber ich gehe davon aus, dass Sie sich auf die Clusteranalysetechnik der Gaußschen Mischungsmodellierung beziehen, die ein Beispiel für das allgemeine EM-Prinzip ist.

Tatsächlich ist die EM-Clusteranalyse kein Klassifikator . Ich weiß, dass einige Leute Clustering als "unbeaufsichtigte Klassifizierung" betrachten, aber tatsächlich ist die Clusteranalyse etwas ganz anderes.

Der Hauptunterschied und das große Missverständnis, das Menschen bei der Clusteranalyse immer haben, besteht darin, dass es in der Clusteranalyse keine "richtige Lösung" gibt . Es ist eine Methode zur Entdeckung von Wissen , es soll tatsächlich etwas Neues finden ! Dies macht die Bewertung sehr schwierig. Es wird häufig anhand einer bekannten Klassifizierung als Referenz bewertet, aber das ist nicht immer angemessen: Die Klassifizierung, die Sie haben, spiegelt möglicherweise die Daten wider oder nicht.

Lassen Sie mich ein Beispiel geben: Sie haben einen großen Kundendatensatz, einschließlich Geschlechtsdaten. Eine Methode, die diesen Datensatz in "männlich" und "weiblich" aufteilt, ist optimal, wenn Sie ihn mit den vorhandenen Klassen vergleichen. In einer "Vorhersage" -Methode ist dies gut, da Sie für neue Benutzer jetzt deren Geschlecht vorhersagen können. In einer "Wissensentdeckungs" -Methode ist dies tatsächlich schlecht, weil Sie eine neue Struktur in den Daten entdecken wollten . Eine Methode, die z. B. die Daten in ältere Menschen und Kinder aufteilt, würde jedoch in Bezug auf die männliche / weibliche Klasse so schlecht abschneiden, wie es nur geht . Dies wäre jedoch ein hervorragendes Clustering-Ergebnis (wenn das Alter nicht angegeben würde).

Nun zurück zu EM. Im Wesentlichen wird davon ausgegangen, dass Ihre Daten aus mehreren multivariaten Normalverteilungen bestehen (beachten Sie, dass dies eine ist ausgegangen, sehr starke Annahme ist, insbesondere wenn Sie die Anzahl der Cluster festlegen!). Anschließend wird versucht, ein lokales optimales Modell dafür zu finden, indem abwechselnd das Modell und die Objektzuordnung zum Modell verbessert werden .

Um die besten Ergebnisse in einem Klassifizierungskontext zu erzielen, wählen Sie die Anzahl der größeren Cluster als die Anzahl der Klassen ist, oder wenden Sie die Clusterbildung sogar nur auf einzelne Klassen an (um herauszufinden, ob innerhalb der Klasse eine Struktur vorhanden ist!).

Angenommen, Sie möchten einen Klassifikator trainieren, um "Autos", "Fahrräder" und "Lastwagen" zu unterscheiden. Es hat wenig Sinn anzunehmen, dass die Daten aus genau 3 Normalverteilungen bestehen. Sie können jedoch davon ausgehen, dass es mehr als eine Art von Autos (sowie Lastwagen und Fahrräder) gibt. Anstatt einen Klassifikator für diese drei Klassen zu trainieren, gruppieren Sie Autos, Lastwagen und Fahrräder in jeweils 10 Gruppen (oder vielleicht 10 Autos, 3 Lastwagen und 3 Fahrräder, was auch immer) und trainieren dann einen Klassifikator, um diese 30 Klassen zu unterscheiden, und dann Führen Sie das Klassenergebnis wieder mit den ursprünglichen Klassen zusammen. Möglicherweise stellen Sie auch fest, dass es einen Cluster gibt, der besonders schwer zu klassifizieren ist, z. B. Trikes. Es sind etwas Autos und etwas Fahrräder. Oder Lieferwagen, die eher übergroßen Autos als Lastwagen ähneln.


Wie ist EM unterbestimmt?
Sam Boosalis

Es gibt mehr als eine Version davon. Technisch kann man Lloyd-Stil k-auch "EM" nennen. Sie müssen angeben, welches Modell Sie verwenden.
Hat aufgehört - Anony-Mousse

2

Da andere Antworten gut sind, werde ich versuchen, eine andere Perspektive zu bieten und den intuitiven Teil der Frage anzugehen.

Der EM-Algorithmus (Expectation-Maximization) ist eine Variante einer Klasse iterativer Algorithmen, die Dualität verwenden

Auszug (Schwerpunkt Mine):

In der Mathematik übersetzt eine Dualität im Allgemeinen Konzepte, Theoreme oder mathematische Strukturen eins zu eins in andere Konzepte, Theoreme oder Strukturen, oft (aber nicht immer) mittels einer Involutionsoperation: wenn das Dual von A ist B, dann ist das Dual von B A. Solche Involutionen haben manchmal feste Punkte , so dass das Dual von A A selbst ist

Normalerweise ein duales B von einem Objekts A in irgendeiner Weise mit A verbunden, wodurch eine gewisse Symmetrie oder Kompatibilität erhalten bleibt . Zum Beispiel AB = const

Beispiele für iterative Algorithmen, die Dualität (im vorherigen Sinne) verwenden, sind:

  1. Euklidischer Algorithmus für Greatest Common Divisor und seine Varianten
  2. Gram-Schmidt-Vektor-Basis-Algorithmus und Varianten
  3. Arithmetisches Mittel - Geometrische mittlere Ungleichung und ihre Varianten
  4. Expectation-Maximization-Algorithmus und seine Varianten (siehe auch hier für eine informationsgeometrische Ansicht )
  5. (.. andere ähnliche Algorithmen ..)

In ähnlicher Weise kann der EM-Algorithmus auch als zwei doppelte Maximierungsschritte angesehen werden :

.. [EM] wird als Maximierung einer gemeinsamen Funktion der Parameter und der Verteilung über die nicht beobachteten Variablen angesehen. Der E-Schritt maximiert diese Funktion in Bezug auf die Verteilung über die nicht beobachteten Variablen; der M-Schritt in Bezug auf die Parameter ..

In einem iterativen Algorithmus unter Verwendung von Dualität gibt es die explizite (oder implizite) Annahme eines Gleichgewichts- (oder festen) Konvergenzpunkts (für EM wird dies unter Verwendung von Jensens Ungleichung bewiesen).

Der Umriss solcher Algorithmen lautet also:

  1. E-ähnlicher Schritt: Finden Sie die beste Lösung x in Bezug auf gegebenes y , das konstant gehalten wird.
  2. M-ähnlicher Schritt (dual): Finden Sie die beste Lösung y in Bezug auf x (wie im vorherigen Schritt berechnet), das konstant gehalten wird.
  3. Kriterium des Abschluss- / Konvergenzschritts: Wiederholen Sie die Schritte 1, 2 mit den aktualisierten Werten von x , y, bis die Konvergenz (oder die angegebene Anzahl von Iterationen erreicht ist).

Beachten Sie, dass ein solcher Algorithmus, wenn er zu einem (globalen) Optimum konvergiert, eine Konfiguration gefunden hat, die in beiden Sinnen am besten ist (dh sowohl in der x- Domäne / den Parametern als auch in der y- Domäne / den Parametern). Der Algorithmus kann jedoch nur ein lokales Optimum und nicht das globale Optimum finden.

Ich würde sagen, dies ist die intuitive Beschreibung des Umrisses des Algorithmus

Für die statistischen Argumente und Anwendungen haben andere Antworten gute Erklärungen gegeben (siehe auch Referenzen in dieser Antwort)


2

Die akzeptierte Antwort bezieht sich auf das Chuong EM Paper , das EM in angemessener Weise erklärt. Es gibt auch ein Youtube-Video , in dem das Papier ausführlicher erklärt wird.

Um es noch einmal zusammenzufassen, hier ist das Szenario:

1st:  {H,T,T,T,H,H,T,H,T,H} 5 Heads, 5 Tails; Did coin A or B generate me?
2nd:  {H,H,H,H,T,H,H,H,H,H} 9 Heads, 1 Tails
3rd:  {H,T,H,H,H,H,H,T,H,H} 8 Heads, 2 Tails
4th:  {H,T,H,T,T,T,H,H,T,T} 4 Heads, 6 Tails
5th:  {T,H,H,H,T,H,H,H,T,H} 7 Heads, 3 Tails

Two possible coins, A & B are used to generate these distributions.
A & B have an unknown parameter: their bias towards heads.

We don't know the biases, but we can simply start with a guess: A=60% heads, B=50% heads.

Im Fall der Frage des ersten Versuchs würden wir intuitiv denken, dass B sie generiert hat, da der Anteil der Köpfe sehr gut mit der Tendenz von B übereinstimmt ... aber dieser Wert war nur eine Vermutung, daher können wir nicht sicher sein.

In diesem Sinne denke ich gerne an die EM-Lösung wie folgt:

  • Bei jedem Flip-Versuch kann über die Münze abgestimmt werden, die ihm am besten gefällt
    • Dies hängt davon ab, wie gut jede Münze zu ihrer Verteilung passt
    • ODER Aus Sicht der Münze besteht eine hohe Erwartung, dass dieser Versuch im Vergleich zur anderen Münze (basierend auf den Log-Wahrscheinlichkeiten ) durchgeführt wird.
  • Abhängig davon, wie sehr jeder Versuch jede Münze mag, kann die Schätzung des Parameters (Bias) dieser Münze aktualisiert werden.
    • Je mehr ein Versuch eine Münze mag, desto mehr kann er die Tendenz der Münze aktualisieren, um ihre eigene zu reflektieren!
    • Im Wesentlichen werden die Verzerrungen der Münze aktualisiert, indem diese gewichteten Aktualisierungen über alle Versuche hinweg kombiniert werden. Dieser Prozess wird als ( Maximierung ) bezeichnet und bezieht sich auf den Versuch, bei einer Reihe von Versuchen die besten Vermutungen für die Verzerrung jeder Münze zu erhalten.

Dies mag eine Vereinfachung sein (oder auf einigen Ebenen sogar grundlegend falsch), aber ich hoffe, dass dies auf einer intuitiven Ebene hilft!


1

EM wird verwendet, um die Wahrscheinlichkeit eines Modells Q mit latenten Variablen Z zu maximieren.

Es ist eine iterative Optimierung.

theta <- initial guess for hidden parameters
while not converged:
    #e-step
    Q(theta'|theta) = E[log L(theta|Z)]
    #m-step
    theta <- argmax_theta' Q(theta'|theta)

e-step: Berechnen Sie bei gegebener aktueller Schätzung von Z die erwartete Loglikelihood-Funktion

m-Schritt: Finde Theta, das dieses Q maximiert

GMM Beispiel:

e-step: Schätzen Sie die Etikettenzuweisungen für jeden Datenpunkt unter Berücksichtigung der aktuellen Schätzung der gmm-Parameter

m-Schritt: Maximieren Sie ein neues Theta angesichts der neuen Etikettenzuordnungen

K-means ist auch ein EM-Algorithmus und es gibt viele erklärende Animationen zu K-means.


1

Unter Verwendung des gleichen Artikels von Do und Batzoglou, der in Zhubarbs Antwort zitiert wurde, implementierte ich EM für dieses Problem in Java . Die Kommentare zu seiner Antwort zeigen, dass der Algorithmus an einem lokalen Optimum hängen bleibt, was auch bei meiner Implementierung auftritt, wenn die Parameter thetaA und thetaB gleich sind.

Unten ist die Standardausgabe meines Codes, die die Konvergenz der Parameter zeigt.

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

Unten ist meine Java-Implementierung von EM zur Lösung des Problems in (Do und Batzoglou, 2008). Der Kern der Implementierung ist die Schleife, in der EM ausgeführt wird, bis die Parameter konvergieren.

private Parameters _parameters;

public Parameters run()
{
    while (true)
    {
        expectation();

        Parameters estimatedParameters = maximization();

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

        _parameters = estimatedParameters;
    }

    return _parameters;
}

Unten ist der gesamte Code.

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,
respectively.
*****************************************************************************/
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
experimental 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);
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.