Berikut adalah contoh dari Maksimalisasi Ekspektasi (EM) yang digunakan untuk memperkirakan mean dan standar deviasi. Kode ini dalam Python, tetapi harus mudah diikuti bahkan jika Anda tidak terbiasa dengan bahasa tersebut.
Motivasi untuk EM
Titik merah dan biru yang ditunjukkan di bawah ini diambil dari dua distribusi normal yang berbeda, masing-masing dengan mean dan standar deviasi tertentu:
Untuk menghitung perkiraan yang masuk akal dari mean "benar" dan parameter standar deviasi untuk distribusi merah, kita dapat dengan mudah melihat titik merah dan mencatat posisi masing-masing, dan kemudian menggunakan rumus yang sudah dikenal (dan juga untuk kelompok biru) .
Sekarang perhatikan kasus di mana kita tahu bahwa ada dua kelompok titik, tetapi kita tidak bisa melihat titik mana yang termasuk kelompok mana. Dengan kata lain, warnanya disembunyikan:
Sama sekali tidak jelas bagaimana membagi poin menjadi dua kelompok. Kami sekarang tidak dapat hanya melihat posisi dan menghitung estimasi untuk parameter distribusi merah atau distribusi biru.
Di sinilah EM dapat digunakan untuk menyelesaikan masalah.
Menggunakan EM untuk memperkirakan parameter
Berikut adalah kode yang digunakan untuk menghasilkan poin yang ditunjukkan di atas. Anda dapat melihat rata-rata aktual dan standar deviasi dari distribusi normal tempat titik diambil. Variabel red
dan blue
memegang posisi masing-masing titik dalam kelompok merah dan biru masing-masing:
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)))
Jika kita dapat melihat warna setiap titik, kita akan mencoba dan memulihkan cara dan standar deviasi menggunakan fungsi pustaka:
>>> np.mean(red)
2.802
>>> np.std(red)
0.871
>>> np.mean(blue)
6.932
>>> np.std(blue)
2.195
Tapi karena warnanya tersembunyi dari kami, kami akan memulai proses EM ...
Pertama, kita hanya menebak nilai untuk parameter masing-masing kelompok ( langkah 1 ). Dugaan ini tidak harus bagus:
# 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
Tebakan yang cukup buruk - artinya terlihat jauh dari "tengah" kelompok poin mana pun.
Untuk melanjutkan EM dan meningkatkan tebakan ini, kami menghitung kemungkinan setiap titik data (terlepas dari warna rahasianya) yang muncul di bawah tebakan ini untuk mean dan standar deviasi ( langkah 2 ).
Variabel both_colours
memegang setiap titik data. Fungsi stats.norm
menghitung probabilitas titik di bawah distribusi normal dengan parameter yang diberikan:
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)
Ini memberi tahu kita, misalnya, bahwa dengan perkiraan kami saat ini, titik data di 1,761 jauh lebih mungkin untuk menjadi merah (0,189) daripada biru (0,00003).
Kami dapat mengubah dua nilai kemungkinan ini menjadi bobot ( langkah 3 ) sehingga jumlahnya menjadi 1 sebagai berikut:
likelihood_total = likelihood_of_red + likelihood_of_blue
red_weight = likelihood_of_red / likelihood_total
blue_weight = likelihood_of_blue / likelihood_total
Dengan perkiraan kami saat ini dan bobot kami yang baru dihitung, kami sekarang dapat menghitung estimasi baru, mungkin lebih baik, untuk parameter ( langkah 4 ). Kita membutuhkan fungsi untuk mean dan fungsi untuk deviasi standar:
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)
Ini terlihat sangat mirip dengan fungsi biasa dengan mean dan standar deviasi data. Perbedaannya adalah penggunaan weight
parameter yang memberikan bobot pada setiap titik data.
Pembobotan ini adalah kunci EM. Semakin besar bobot warna pada suatu titik data, semakin banyak titik data tersebut mempengaruhi taksiran selanjutnya untuk parameter warna itu. Pada akhirnya, ini memiliki efek menarik setiap parameter ke arah yang benar.
Tebakan baru dihitung dengan fungsi-fungsi ini:
# 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)
Proses EM kemudian diulangi dengan tebakan baru ini dari langkah 2 dan seterusnya. Kita dapat mengulangi langkah-langkah untuk sejumlah iterasi (katakanlah 20), atau sampai kita melihat parameter menyatu.
Setelah lima iterasi, kami melihat dugaan buruk awal kami mulai menjadi lebih baik:
Setelah 20 iterasi, proses EM memiliki lebih atau kurang konvergen:
Sebagai perbandingan, berikut adalah hasil dari proses EM dibandingkan dengan nilai yang dihitung di mana informasi warna tidak disembunyikan:
| 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
Catatan: jawaban ini diadaptasi dari jawaban saya di Stack Overflow di sini .