聊聊EM算法~

      EM算法(Expection Maximuzation)的中文名稱叫做期望最大化,我的理解EM算法就是一種引入隱含變量的座標向上法,它與其他優化方法的目的相同,就是求解一個數學模型的最優參數,不同之處在於EM算法交互迭代的對象是隱含變量與模型參數,一般隱含變量表現爲數據的類別。期望說白了就是數據的權重平均,在EM算法中,可以理解爲數據的類別,那麼既然確定好了數據的類別,下一步就是想辦法求取新數據構成分佈的參數,一般採用最大似然法求取最優參數。剩下的就是最普通的迭代過程,先初始化參數,計算數據的概率分佈,再對數據進行重新分類,然後重新計算參數,週而復始。幸運的是,EM算法的收斂性能夠得到保證。

      曾經讀過一篇特別好的博客,通過舉例的方式對EM算法解釋的很形象,現摘抄如下:


     “假設我們需要調查我們學校的男生和女生的身高分佈。你怎麼做啊?你說那麼多人不可能一個一個去問吧,肯定是抽樣了。假設你在校園裏隨便地活捉了100個男生和100個女生。他們共200個人(也就是200個身高的樣本數據,爲了方便表示,下面,我說“人”的意思就是對應的身高)都在教室裏面了。那下一步怎麼辦啊?你開始喊:“男的左邊,女的右邊,其他的站中間!”。然後你就先統計抽樣得到的100個男生的身高。假設他們的身高是服從高斯分佈的。但是這個分佈的均值u和方差2我們不知道,這兩個參數就是我們要估計的。記θ=[u, ∂]T

     再回到例子本身,如果沒有“男的左邊,女的右邊,其他的站中間!”這個步驟,或者說我抽到這200個人中,某些男生和某些女生一見鍾情,已經好上了,糾纏起來了。咱們也不想那麼殘忍,硬把他們拉扯開。那現在這200個人已經混到一起了,這時候,你從這200個人(的身高)裏面隨便給我指一個人(的身高),我都無法確定這個人(的身高)是男生(的身高)還是女生(的身高)。也就是說你不知道抽取的那200個人裏面的每一個人到底是從男生的那個身高分佈裏面抽取的,還是女生的那個身高分佈抽取的。用數學的語言就是,抽取得到的每個樣本都不知道是從哪個分佈抽取的。

        這個時候,對於每一個樣本或者你抽取到的人,就有兩個東西需要猜測或者估計的了,一是這個人是男的還是女的?二是男生和女生對應的身高的高斯分佈的參數是多少?

        EM的意思是“Expectation Maximization”,在我們上面這個問題裏面,我們是先隨便猜一下男生(身高)的正態分佈的參數:如均值和方差是多少。例如男生的均值是17,方差是0.1米(當然了,剛開始肯定沒那麼準),然後計算出每個人更可能屬於第一個還是第二個正態分佈中的(例如,這個人的身高是18,那很明顯,他最大可能屬於男生的那個分佈),這個是屬於Expectation一步。有了每個人的歸屬,或者說我們已經大概地按上面的方法將這200個人分爲男生和女生兩部分,我們就可以根據之前說的最大似然那樣,通過這些被大概分爲男生的n個人來重新估計第一個分佈的參數,女生的那個分佈同樣方法重新估計。這個是Maximization。然後,當我們更新了這兩個分佈的時候,每一個屬於這兩個分佈的概率又變了,那麼我們就再需要調整E步……如此往復,直到參數基本不再發生變化爲止。”


 這是我讀過最好的EM算法例子,我對這個例子進行了仿真,代碼如下所示:

% 函數功能:根據身高數據計算男性女性平均身高
% 1.對初始值很敏感,如果先驗初始值不準確,最後必定收斂到不準確值
% 2.對初始數據分佈比較敏感
% 3.初始值不能相同,否則將會陷入無限循環
function EM_algorithm()
    clear all;
    close all;
    clc;
    
    person_num = 600;

    % 男生數據
    u1 = 1.76;
    sigma1 = 0.1;
    x1 = normrnd(u1, sigma1, person_num / 2, 1); 
    y1 = gauss_function(u1, sigma1, x1);
%     plot(x1, ones(person_num / 2, 1), 'r*');
    plot(x1,y1, 'r*');
    
    % 女生數據
    u2 = 1.55;
    sigma2 = 0.1;
    x2 = normrnd(u2, sigma2, person_num / 2, 1); 
    y2 = gauss_function(u2, sigma2, x2);
    hold on;
%     plot(x2, 2 * ones(person_num / 2, 1), 'bo');
    plot(x2, y2, 'bo');
    keyboard
    
    % EM算法
    flag        = 1;
    iter        = 1;
    sigma_joint = 0.1;
    u0_man      = 1.5;
    u0_woman    = 1.4;
    persons     = [x1; x2];
    theold      = 0.001;
    while(flag == 1)
        % 確定樣本類別,E步驟
        z = [];
        for i = 1 : length(persons)
            p_man = gauss_function(u0_man, sigma_joint, persons(i));
            p_woman = gauss_function(u0_woman, sigma_joint, persons(i));
            if p_man > p_woman
                z = [z, 1];
            else
                z = [z, -1];
            end
        end
        
        % 提取樣本類別序列
        man_index = find(z == 1);
        woman_index = find(z == -1);
        
        % 最大似然估計,M步驟
%         u0_man = fminsearch(@(k)StdMonochrome(k,G),[1.5, 2]);
%         u0_woman = fminsearch(@(k)StdMonochrome(k,G),[1.5, 2]);

        % 記錄之前的參數值
        u0_man_old = u0_man;
        u0_woman_old = u0_woman;
        
        disp(['u0_man = ', num2str(u0_man_old)]);
        disp(['u0_woman = ',num2str(u0_woman_old)]);
        disp(['number of man = ', num2str(length(man_index))]);
        disp(['number of woman = ',num2str(length(woman_index))]);

        % 針對於高斯分佈這種情況,最大似然估計解的解析式就是均值
        u0_man = mean(persons(man_index), 1);
        u0_woman = mean(persons(woman_index), 1);
        
        if abs(u0_man - u0_man_old) < theold && abs(u0_woman_old - u0_woman) < theold
            flag = 0;
            disp('success');
            disp(['u0_man = ', num2str(u0_man)]);
            disp(['u0_woman = ',num2str(u0_woman)]);
            disp(['iter = ', num2str(iter)]);
        end
        
        iter = iter + 1;
    end
end

% 高斯核函數,經常寫
function[p] = gauss_function(u, sigma, data)
%     p = (1/sqrt(2*pi)).*exp(-(data - u).* (data - u)/2 * sigma^2);
    p = exp(-(data - u).* (data - u)/sigma^2);
end

其中,數據分佈的具體參數有兩個,代碼中我直接用的是參數經過最大似然估計後的解析解。當然,也可以直接調用Matlab中的函數進行最大似然估計,不過這個例子就沒太大必要了。


抽樣數據的真實分佈如下所示:



運行代碼,得到的迭代數據如下所示,算法迭代9步最終收斂:

u0_man = 1.5
u0_woman = 1.4
number of man = 557
number of woman = 43
u0_man = 1.6714
u0_woman = 1.4049
number of man = 464
number of woman = 136
u0_man = 1.7067
u0_woman = 1.4669
number of man = 400
number of woman = 200
u0_man = 1.7295
u0_woman = 1.498
number of man = 355
number of woman = 245
u0_man = 1.7458
u0_woman = 1.5169
number of man = 326
number of woman = 274
u0_man = 1.7567
u0_woman = 1.5282
number of man = 307
number of woman = 293
u0_man = 1.7641
u0_woman = 1.5352
number of man = 296
number of woman = 304
u0_man = 1.7685
u0_woman = 1.5392
number of man = 292
number of woman = 308
u0_man = 1.7701
u0_woman = 1.5407
number of man = 291
number of woman = 309
success
u0_man = 1.7705
u0_woman = 1.541
iter = 9

其結果與真實值(男:1.76米,女:1.55米)較爲接近。但是,經過幾個實驗得知,EM算法對初始值的敏感程度較高,同時,假設有兩類數據,那麼這兩類數據的類間距離應該滿足一定條件,如果我們將分佈調整爲(男:1.56米,女:1.55米),那麼EM算法將無法收斂。大家可以試一試看。

這段時間一直比較忙,忙於寫代碼實現文獻&改進算法,好久沒寫博客了,如有問題,請代價不吝指教!

參考文獻:http://blog.csdn.net/zouxy09

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章