一、引言
我們談到了用 k-means 進行聚類的方法,這次我們來說一下另一個很流行的算法:Gaussian Mixture Model (GMM)。事實上,GMM 和 k-means 很像,不過 GMM 是學習出一些概率密度函數來(所以 GMM 除了用在 clustering 上之外,還經常被用於 density estimation ),簡單地說,k-means 的結果是每個數據點被 assign 到其中某一個 cluster 了,而 GMM 則給出這些數據點被 assign 到每個 cluster 的概率,又稱作 soft assignment 。
給出一個概率有很多好處,因為它的信息量比簡單的一個結果要多,比如,我可以把這個概率轉換為一個 score ,表示算法對自己得出的這個結果的把握。也許我可以對同一個任務,用多個方法得到結果,最后選取“把握”最大的那個結果;另一個很常見的方法是在諸如疾病診斷之類的場所,機器對於那些很容易分辨的情況(患病或者不患病的概率很高)可以自動區分,而對於那種很難分辨的情況,比如,49% 的概率患病,51% 的概率正常,如果僅僅簡單地使用 50% 的閾值將患者診斷為“正常”的話,風險是非常大的,因此,在機器對自己的結果把握很小的情況下,會“拒絕發表評論”,而把這個任務留給有經驗的醫生去解決。
二、歸納法
一系列數據N要求對他擬合,如果不作要求的話,可以用一個N-1次多項式來完美擬合這N個點,比如拉格朗日插值,牛頓插值等,或者如果不限制次數的話可以找到無窮個完美函數,但是往往咱們要求指數型或者線性,就是需要對信息有機結合,GMM就是這樣,要求用高斯模型來擬合,當然了可以構造任意的混合模型,不過根據中心極限定理等高斯模型比較合適。另外,Mixture Model 本身其實也是可以變得任意復雜的,通過增加 Model 的個數,我們可以任意地逼近任何連續的概率密分布。
三、原理分析
從幾何上講,單高斯分布模型在二維空間應該近似於橢圓,在三維空間上近似於橢球。遺憾的是在很多分類問題中,屬於同一類別的樣本點並不滿足“橢圓”分布的特性。這就引入了高斯混合模型。
通觀整個高斯模型,他主要是由方差和均值兩個參數決定,,對均值和方差的學習,采取不同的學習機制,將直接影響到模型的穩定性、精確性和收斂性。
每個 GMM 由 個 Gaussian 分布組成,每個 Gaussian 稱為一個“Component”,這些 Component 線性加成在一起就組成了 GMM 的概率密度函數:
根據上面的式子,如果我們要從 GMM 的分布中隨機地取一個點的話,實際上可以分為兩步:首先隨機地在這 個 Component 之中選一個,每個 Component 被選中的概率實際上就是它的系數
,選中了 Component 之后,再單獨地考慮從這個 Component 的分布中選取一個點就可以了──這里已經回到了普通的 Gaussian 分布,轉化為了已知的問題。
那么如何用 GMM 來做 clustering 呢?其實很簡單,現在我們有了數據,假定它們是由 GMM 生成出來的,那么我們只要根據數據推出 GMM 的概率分布來就可以了,然后 GMM 的 個 Component 實際上就對應了
個 cluster 了。根據數據來推算概率密度通常被稱作 density estimation ,特別地,當我們在已知(或假定)了概率密度函數的形式,而要估計其中的參數的過程被稱作“參數估計”。
現在假設我們有 個數據點,並假設它們服從某個分布(記作
),現在要確定里面的一些參數的值,例如,在 GMM 中,我們就需要確定
、
和
這些參數。 我們的想法是,找到這樣一組參數,它所確定的概率分布生成這些給定的數據點的概率最大,而這個概率實際上就等於
,我們把這個乘積稱作似然函數 (Likelihood Function)。通常單個點的概率都很小,許多很小的數字相乘起來在計算機里很容易造成浮點數下溢,因此我們通常會對其取對數,把乘積變成加和
,得到 log-likelihood function 。接下來我們只要將這個函數最大化(通常的做法是求導並令導數等於零,然后解方程),亦即找到這樣一組參數值,它讓似然函數取得最大值,我們就認為這是最合適的參數,這樣就完成了參數估計的過程。
下面讓我們來看一看 GMM 的 log-likelihood function :
在最大似然估計里面,由於我們的目的是把乘積的形式分解為求和的形式,即在等式的左右兩邊加上一個log函數,轉化為log后,還有log(a+b)的形式,因此,要進一步求解。
由於在對數函數里面又有加和,我們沒法直接用求導解方程的辦法直接求得最大值。為了解決這個問題,我們采取之前從 GMM 中隨機選點的辦法:分成兩步,實際上也就類似於 K-means 的兩步。
四、EM實現
- 假設模型參數已知,求概率。估計數據由每個 Component 生成的概率(並不是每個 Component 被選中的概率):對於每個數據
來說,它由第
個 Component 生成的概率為
由於式子里的
和
也是需要我們估計的值,我們采用迭代法,在計算
的時候我們假定
和
均已知,我們將取上一次迭代所得的值(或者初始值)。
- 根據概率值和最大似然估計找到參數。估計每個 Component 的參數:現在我們假設上一步中得到的
就是正確的“數據
由 Component
生成的概率”,亦可以當做該 Component 在生成這個數據上所做的貢獻,或者說,我們可以看作
這個值其中有
這部分是由 Component
所生成的。集中考慮所有的數據點,現在實際上可以看作 Component 生成了
這些點。由於每個 Component 都是一個標准的 Gaussian 分布,可以很容易分布求出最大似然所對應的參數值:
其中
,並且
也順理成章地可以估計為
。
- 重復迭代前面兩步,直到似然函數的值收斂為止。
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
函數返回的 Px
是一個 的矩陣,對於每一個
,我們只要取該矩陣第
行中最大的那個概率值所對應的那個 Component 為
所屬的 cluster 就可以實現一個完整的聚類方法了。對於最開始的那個例子。
一個比較好的Matlab實現代碼。
http://www.mathworks.com/matlabcentral/fileexchange/26184-em-algorithm-for-gaussian-mixture-model--em-gmm-
EM的推導參考
http://www.cnblogs.com/jerrylead/archive/2011/04/06/2006936.html
五、圖形化顯示
mvnrnd(mu1,sigma1,200)
這句生成了200*2的矩陣。
mu1 = [1 2]; sigma1 = [3 .2; .2 2]; mu2 = [-1 -2]; sigma2 = [2 0; 0 1]; X = [mvnrnd(mu1,sigma1,200);mvnrnd(mu2,sigma2,100)]; scatter(X(:,1),X(:,2),10,'ko')
六、討論
6.1 kmeans
讓我們先來看看它對於需要進行聚類的數據的一個基本假設吧:對於每一個 cluster ,我們可以選出一個中心點 (center) ,使得該 cluster 中的所有的點到該中心點的距離小於到其他 cluster 的中心的距離。雖然實際情況中得到的數據並不能保證總是滿足這樣的約束,但這通常已經是我們所能達到的最好的結果,而那些誤差通常是固有存在的或者問題本身的不可分性造成的。例如下圖所示的兩個高斯分布,從兩個分布中隨機地抽取一些數據點出來,混雜到一起,現在要讓你將這些混雜在一起的數據點按照它們被生成的那個分布分開來:
由於這兩個分布本身有很大一部分重疊在一起了,例如,對於數據點 2.5 來說,它由兩個分布產生的概率都是相等的,你所做的只能是一個猜測;稍微好一點的情況是 2 ,通常我們會將它歸類為左邊的那個分布,因為概率大一些,然而此時它由右邊的分布生成的概率仍然是比較大的,我們仍然有不小的幾率會猜錯。而整個陰影部分是我們所能達到的最小的猜錯的概率,這來自於問題本身的不可分性,無法避免。因此,我們將 k-means 所依賴的這個假設看作是合理的。
基於這樣一個假設,我們再來導出 k-means 所要優化的目標函數:設我們一共有 N 個數據點需要分為 K 個 cluster ,k-means 要做的就是最小化
這個函數,其中 在數據點 n 被歸類到 cluster k 的時候為 1 ,否則為 0 。直接尋找
和
來最小化
並不容易,不過我們可以采取迭代的辦法:先固定
,選擇最優的
,很容易看出,只要將數據點歸類到離他最近的那個中心就能保證
最小。下一步則固定
,再求最優的
。將
對
求導並令導數等於零,很容易得到
最小的時候
應該滿足:
亦即 的值應當是所有 cluster k 中的數據點的平均值。由於每一次迭代都是取到
的最小值,因此
只會不斷地減小(或者不變),而不會增加,這保證了 k-means 最終會到達一個極小值。雖然 k-means 並不能保證總是能得到全局最優解,但是對於這樣的問題,像 k-means 這種復雜度的算法,這樣的結果已經是很不錯的了。
下面我們來總結一下 k-means 算法的具體步驟:
- 選定 K 個中心
的初值。這個過程通常是針對具體的問題有一些啟發式的選取方法,或者大多數情況下采用隨機選取的辦法。因為前面說過 k-means 並不能保證全局最優,而是否能收斂到全局最優解其實和初值的選取有很大的關系,所以有時候我們會多次選取初值跑 k-means ,並取其中最好的一次結果。
- 將每個數據點歸類到離它最近的那個中心點所代表的 cluster 中。
- 用公式
計算出每個 cluster 的新的中心點。
- 重復第二步,一直到迭代了最大的步數或者前后的
的值相差小於一個閾值為止。
6.2 GMM與kmeans的區別
另外,從上面的分析中我們可以看到 GMM 和 K-means 的迭代求解法其實非常相似(都可以追溯到 EM 算法,下一次會詳細介紹),因此也有和 K-means 同樣的問題──並不能保證總是能取到全局最優,如果運氣比較差,取到不好的初始值,就有可能得到很差的結果。對於 K-means 的情況,我們通常是重復一定次數然后取最好的結果,不過 GMM 每一次迭代的計算量比 K-means 要大許多,一個更流行的做法是先用 K-means (已經重復並取最優值了)得到一個粗略的結果,然后將其作為初值(只要將 K-means 所得的 centroids 傳入 gmm
函數即可),再用 GMM 進行細致迭代。
如我們最開始所討論的,GMM 所得的結果(Px
)不僅僅是數據點的 label ,而包含了數據點標記為每個 label 的概率,很多時候這實際上是非常有用的信息。最后,需要指出的是,GMM 本身只是一個模型,我們這里給出的迭代的辦法並不是唯一的求解方法。感興趣的同學可以自行查找相關資料。
GMM中幾個高斯模型就是幾個聚類簇,也就是說不能聚類是K個,我想用M個或者任意多個高斯模型,而且假設簇終點服從高斯分布,因此個人認為FCM使用更廣泛。
http://blog.pluskid.org/?p=39
http://www.cnblogs.com/CBDoctor/archive/2011/11/06/2236286.html
http://www.cnblogs.com/zhangchaoyang/articles/2624882.html
http://chunqiu.blog.ustc.edu.cn/?p=437