图1:mutilmodel distribution data



高斯分布(Gaussian distribution),是一个在数学、物理及工程等领域都非常重要的连续概率分布函数,它描述了一种围绕某个单值聚集分布的随机变量。生活中,各种各样的心理学测试分数和物理现象比如光子计数都被发现近似地服从高斯分布。同时,高斯分布也是统计学以及许多统计测试中最广泛应用的一类分布。中心极限定理表明,采样的均值近似服从高斯分布;还可以证明,高斯分布的信息熵在所有的已知均值及方差的连续分布中最大,这使得高斯分布成为一种均值以及方差已知的分布的自然选择。然而,直觉上可知高斯分布是一个单模态(只有一个最大值)的分布,不能对多模态的数据分布提供一个较好的近似(如图1所示)。

为了解决这个问题,人们提出了高斯混合模型(GMM),顾名思义,就是数据可以看作是从数个高斯分布中生成出来的。虽然我们可以用不同的分布来随意地构造 XX Mixture Model ,但是 GMM是 最为流行。另外,Mixture Model 本身其实也是可以变得任意复杂的,通过增加 Model 的个数,我们可以任意地逼近任何连续的概率密分布。


每个 GMM 由 K 个 Gaussian 分布组成,每个 Gaussian 称为一个“Component”,这些 Component 线性加成在一起就组成了 GMM 的概率密度函数:




p(x)=∑k=1Kp(k)p(x|k)=∑k=1KπkN(x|μk,Σk)(1)



根据上面的式子,如果我们要从 GMM 的分布中随机地取一个点的话,实际上可以分为两步:首先随机地在这 K个 Component 之中选一个,每个 Component 被选中的概率实际上就是它的系数 πk,选中了 Component 之后,再单独地考虑从这个 Component 的分布中选取一个点就可以了──这里已经回到了普通的 Gaussian 分布,转化为了已知的问题。假设现在有 N 个数据点,我们认为这些数据点由某个GMM模型产生,现在我们要需要确定 πk,μk,σk 这些参数。很自然的,我们想到利用最大似然估计来确定这些参数,GMM的似然函数如下:




log∏i=1Np(xi)=∑i=1Nlogp(xi)=∑i=1Nlog∑k=1KπkN(xi|μk,Σk)(2)



由于在对数函数里面又有加和,我们没法直接用求导解方程的办法直接求得最大值。为了解决这个问题,我们利用EM算法,分布迭代的求得最大值,并获得取得最大值时各个参数的值。具体可分为以下几步:

  1. 初始化参数 πk,μk,Σk,一种流行的做法是先通过K-means算法对数据点进行聚类,根据聚类结果选取参数的初始值。
  2. E step:估计数据由每个 Component 生成的概率(并不是每个 Component 被选中的概率):对于每个数据 xi 来说,它由第 k 个 Component 生成的概率为
    γ(i,k)=πkN(xi|μk,Σk)∑j=1KπjN(xi|μj,Σj)(3) 然而,由于式子里的 πk、μk、Σk 正是需要我们估计的参数,我们采用迭代法,即取上一次迭代所得的值(或者初始值)。
  3. M step:对式 (3) 进行求导,求出最大似然所对应的参数值:
    μk=1Nk∑i=1Nγ(i,k)xi(4)

    Σ=1Nk∑i=1Nkγ(i,k)(xi−μk)(xi−μk)T(5) 其中 Nk=∑i=1Nγ(i,k)。根据条件可知,参数 πk 满足 ∑k=1K=1,因此我们在GMM的似然函数中加入拉格朗日乘子log∏i=1Np(xi)+λ(∑k=1K−1),求得该式取得最大值时 πk 对应的值
    πk=NkN(6)
  4. 计算似然函数的值(式(2)),检查似然函数是否收敛。若收敛了,说明似然函数已经取得最大值,此时参数对应的值即为各参数的最大似然估计。否则,则迭代进行E step,M step。

以上步骤的Matlab代码如下:


function varargout = gmm(X, K_or_centroids) 
% ============================================================ 
% Expectation-Maximization iteration implementation of 
% Gaussian Mixture Model. 
% 
% PX = GMM(X, K_OR_CENTROIDS) 
% [PX MODEL] = GMM(X, K_OR_CENTROIDS) 
% 
%  - X: N-by-D data matrix. 
%  - K_OR_CENTROIDS: either K indicating the number of 
%       components or a K-by-D matrix indicating the 
%       choosing of the initial K centroids. 
% 
%  - PX: N-by-K matrix indicating the probability of each 
%       component generating each point. 
%  - MODEL: a structure containing the parameters for a GMM: 
%       MODEL.Miu: a K-by-D matrix. 
%       MODEL.Sigma: a D-by-D-by-K matrix. 
%       MODEL.Pi: a 1-by-K vector. 
% ============================================================ 
    threshold = 1e-15; 
    [N, D] = size(X); 
    if isscalar(K_or_centroids) 
        K = K_or_centroids; 
        % randomly pick centroids 
        rndp = randperm(N); 
        centroids = X(rndp(1:K), :); 
    else 
        K = size(K_or_centroids, 1); 
        centroids = K_or_centroids; 
    end 
    % initial values 
    [pMiu pPi pSigma] = init_params(); 
    Lprev = -inf; 
    while true 
        Px = calc_prob(); 
        % new value for pGamma 
        pGamma = Px .* repmat(pPi, N, 1); 
        pGamma = pGamma ./ repmat(sum(pGamma, 2), 1, K); 
        % new value for parameters of each Component 
        Nk = sum(pGamma, 1); 
        pMiu = diag(1./Nk) * pGamma' * X; 
        pPi = Nk/N; 
        for kk = 1:K 
            Xshift = X-repmat(pMiu(kk, :), N, 1); 
            pSigma(:, :, kk) = (Xshift' * ... 
                (diag(pGamma(:, kk)) * Xshift)) / Nk(kk); 
        end 
        % check for convergence 
        L = sum(log(Px*pPi')); 
        if L-Lprev < threshold 
            break; 
        end 
        Lprev = L; 
    end 
    if nargout == 1 
        varargout = {Px}; 
    else 
        model = []; 
        model.Miu = pMiu; 
        model.Sigma = pSigma; 
        model.Pi = pPi; 
        varargout = {Px, model}; 
    end 
    function [pMiu pPi pSigma] = init_params() 
        pMiu = centroids; 
        pPi = zeros(1, K); 
        pSigma = zeros(D, D, K); 
        % hard assign x to each centroids 
        distmat = repmat(sum(X.*X, 2), 1, K) + ... 
            repmat(sum(pMiu.*pMiu, 2)', N, 1) - ... 
            2*X*pMiu'; 
        [dummy labels] = min(distmat, [], 2); 
        for k=1:K 
            Xk = X(labels == k, :); 
            pPi(k) = size(Xk, 1)/N; 
            pSigma(:, :, k) = cov(Xk); 
        end 
    end 
    function Px = calc_prob() 
        Px = zeros(N, K); 
        for k = 1:K 
            Xshift = X-repmat(pMiu(k, :), N, 1); 
            inv_pSigma = inv(pSigma(:, :, k)); 
            tmp = sum((Xshift*inv_pSigma) .* Xshift, 2); 
            coef = (2*pi)^(-D/2) * sqrt(det(inv_pSigma)); 
            Px(:, k) = coef * exp(-0.5*tmp); 
        end 
    end 
end



利用GMM,我们可以实现GMM的聚类算法。即假设数据来自GMM,在聚类时,根据 πk,μk,Σk 求出数据点 xi属于每个Component的概率,取对应概率最大的Component为 xi 所属的cluster。

 

与K-means比较

相同点:都是可用于聚类的算法;都需要指定K值。

不同点:GMM可以给出一个样本属于某类的概率是多少。

 

 

参考资料:

  1. http://blog.pluskid.org/?p=39
  2. http://www.autonlab.org/tutorials/gmm.html