公號:碼農充電站pro
主頁:https://codeshellme.github.iohtml
以前介紹過K 均值算法,它是一種聚類算法。今天介紹EM 算法,它也是聚類算法,但比K 均值算法更加靈活強大。python
EM 的全稱爲 Expectation Maximization,中文爲指望最大化算法,它是一個不斷觀察和調整的過程。git
咱們先來看一下和麪的過程。github
一般狀況下,若是你事先不知道面與水的比例,和麪過程多是下面這樣:算法
這個和麪過程,就是一個EM 過程:shell
在介紹K 均值 聚類算法時,展現過一個給二維座標點進行聚類的例子。dom
咱們再來看一下這個例子,以下圖:函數
上圖是一個聚類的過程,共有6 個步驟:優化
紅色x
和藍色x
。紅色x
和藍色x
的距離,距離紅色x
近的點標紅色,距離藍色x
近的點標藍色。紅色x
和藍色x
的距離,距離紅色x
近的點標紅色,距離藍色x
近的點標藍色。通過以上步驟就完成了一個聚類過程。3d
實際上,K 均值算法也是一個EM 過程:
將二維數據點的聚類過程,擴展爲通常性的聚類問題,EM 算法是這樣一個模型:對於待分類的數據點,EM 算法讓計算機經過一個不斷迭代的過程,來構建一個分類模型。
EM 算法分爲兩個過程:
以二維數據點的聚類過程爲例,咱們定義:
那麼二維數據點聚類的M 過程,就是尋求最大化的D 和 -d。咱們但願的聚類結果是,同一類的點距離較近,不一樣類之間距離較遠。
EM 算法不是單個算法,而是一類算法。只要知足EM 這兩個過程的算法均可以被稱爲EM 算法。常見的EM 算法有GMM 高斯混合模型和HMM 隱馬爾科夫模型。
高等數學中有一門課叫作《機率論與數理統計》,其中講到了參數估計。
統計推斷是數理統計的重要組成部分,它是指利用來自整體的樣本提供的信息,對整體的某些特徵進行估計或推斷,從而認識總體。
統計推斷分爲兩大類:參數估計和假設檢驗。
咱們假設,對於某個數據集,其分佈函數的基本形式已知,但其中含有一個或多個未知參數。
參數估計就是討論如何根據來自整體的樣本提供的信息對未知參數作出估計。參數估計包括點估計和區間估計。其中,點估計中有兩種方法:矩估計法和最大似然估計法。
最大似然估計是一種經過已知結果,估計未知參數的方法。
EM 算法使用的是最大似然估計的原理,它經過觀察樣本,來找出樣本的模型參數。
下面經過一個投硬幣的例子,來看下EM 算法的計算過程。
這個例子來自《Nature》(天然)期刊的論文《What is the expectation maximization algorithm?》(什麼是指望最大化算法?)。
假定有兩枚不一樣的硬幣 A 和 B,它們的重量分佈 θA 和 θB 是未知的,則能夠經過拋擲硬幣,計算正反面各自出現的次數來估計θA 和 θB。
方法是在每一輪中隨機抽出一枚硬幣拋擲 10 次,一樣的過程執行 5 輪,根據這 50 次投幣的結果來計算 θA 和 θB 的最大似然估計。
投擲硬幣的過程,記錄以下:
第1 到5 次分別投擲的硬幣是 B,A,A,B,A。H 表明正面,T 表明負面。將上圖轉化爲表格,以下:
次數 | 硬幣 | 正面數 | 負面數 |
---|---|---|---|
1 | B | 5 | 5 |
2 | A | 9 | 1 |
3 | A | 8 | 2 |
4 | B | 4 | 6 |
5 | A | 7 | 3 |
經過這個表格,能夠直接計算 θA 和 θB,以下:
顯然,若是知道每次投擲的硬幣是A 仍是B,那麼計算θA 和 θB 是很是簡單的。
可是,若是不知道每次投擲的硬幣是A 仍是B,該如何計算θA 和 θB 呢?
此時咱們將上面表格中的硬幣一列隱藏起來,這時硬幣就是隱變量。因此咱們只知道以下數據:
次數 | 正面數 | 負面數 |
---|---|---|
1 | 5 | 5 |
2 | 9 | 1 |
3 | 8 | 2 |
4 | 4 | 6 |
5 | 7 | 3 |
這時想要計算 θA 和 θB,就要用最大似然估計的原理。
計算過程以下圖:
第一步
先爲 θA 和 θB 設定一個初始值,好比 θA = 0.6,θB = 0.5。
第二步
咱們知道每一輪投幣的正 / 負面的次數:
而後,根據每一輪的 P(HmTn|A) 和 P(HmTn|B),能夠計算出每一輪的正 / 負面次數。
m 爲正面次數,n 爲負面次數。
對於硬幣A,結果以下:
輪數 | P(HmTn|A) | m | n | 正面數 | 負面數 |
---|---|---|---|---|---|
1 | 0.45 | 5 | 5 | 0.45*5=2.2 | 0.45*5=2.2 |
2 | 0.8 | 9 | 1 | 0.8*9=7.2 | 0.8*1=0.8 |
3 | 0.73 | 8 | 2 | 0.73*8=5.9 | 0.73*2=1.5 |
4 | 0.35 | 4 | 6 | 0.35*4=1.4 | 0.35*6=2.1 |
5 | 0.65 | 7 | 3 | 0.65*7=4.5 | 0.65*3=1.9 |
總計 | - | - | - | 21.3 | 8.6 |
對於硬幣B,結果以下:
輪數 | P(HmTn|B) | m | n | 正面數 | 負面數 |
---|---|---|---|---|---|
1 | 0.55 | 5 | 5 | 0.55*5=2.8 | 0.55*5=2.8 |
2 | 0.2 | 9 | 1 | 0.2*9=1.8 | 0.2*1=0.2 |
3 | 0.27 | 8 | 2 | 0.27*8=2.1 | 0.27*2=0.5 |
4 | 0.65 | 4 | 6 | 0.65*4=2.6 | 0.65*6=3.9 |
5 | 0.35 | 7 | 3 | 0.35*7=2.5 | 0.35*3=1.1 |
總計 | - | - | - | 11.7 | 8.4 |
第三步
根據上面兩個表格,能夠得出(第1次迭代的結果) θA 和 θB:
根據這個估計值,再次回到第一步去計算。
如此往復第1、2、三步,通過10次迭代以後,θA 和 θB 的估計值爲:
最終,θA 和 θB 將收斂到一個幾乎不變的值,此時迭代結束。這樣咱們就求解出了θA 和 θB 的最大似然估計值。
咱們將上述過程當中,第一步稱爲初始化參數,第二步稱爲觀察預期,第三步稱爲從新估計參數。
第1、二步爲E 過程,第三步爲M 過程,這就是EM 算法的過程。
若是咱們有一個待聚類的數據集,咱們把潛在的類別當作隱變量,樣本當作觀察值,這樣就能夠把聚類問題轉化成參數估計問題。這就是EM 聚類的原理。
與 K 均值算法相比,K 均值算法是經過距離來區分樣本之間的差異,且每一個樣本在計算的時候只能屬於一個分類,咱們稱之爲硬聚類算法。
而 EM 聚類在求解的過程當中,實際上每一個樣本都有必定的機率和每一個聚類相關,這叫作軟聚類算法。
EM 聚類算法存在兩個比較明顯的問題。
第一個問題是,EM 算法計算複雜,收斂較慢,不太適合大規模數據集和高維數據。
第二個問題是,EM 算法不必定能給出全局最優解:
上文中介紹過,常見的EM 算法有GMM 高斯混合模型和HMM 隱馬爾科夫模型。這裏主要介紹GMM 高斯混合模型的實現。
sklearn 庫的mixture 模塊中的GaussianMixture 類是GMM 算法的實現。
先來看下 GaussianMixture 類的原型:
GaussianMixture( n_components=1, covariance_type='full', tol=0.001, reg_covar=1e-06, max_iter=100, n_init=1, init_params='kmeans', weights_init=None, means_init=None, precisions_init=None, random_state=None, warm_start=False, verbose=0, verbose_interval=10)
這裏介紹幾個重要的參數:
在《決策樹算法-實戰篇-鳶尾花及波士頓房價預測》中咱們介紹過鳶尾花數據集。這裏咱們使用GMM 算法對該數據進行聚類。
首先加載數據集:
from sklearn.datasets import load_iris iris = load_iris() # 加載數據集 features = iris.data # 獲取特徵集 labels = iris.target # 獲取目標集
在聚類算法中,只須要特徵數據 features
,而不須要目標數據labels
,但可使用 labels
對聚類的結果作驗證。
構造GMM聚類:
from sklearn.mixture import GaussianMixture # 原數據中有 3 個分類,因此這裏咱們將 n_components 設置爲 3 gmm = GaussianMixture(n_components=3, covariance_type='full')
對數據集進行聚類:
prediction_labels = gmm.fit_predict(features)
查看原始分類:
>>> print(labels) [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2]
查看聚類結果:
>>> print(prediction_labels) [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 2 1 2 1 1 1 1 2 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2]
對比原始分類和聚類結果,聚類結果中只有個別數據分類錯誤,我用紅圈
標了出來:
咱們可使用 Calinski-Harabaz 指標對聚類結果進行評估。
sklearn 庫實現了該指標的計算,即 calinski_harabasz_score 方法,該方法會計算出一個分值,分數越高,表明聚類效果越好,也就是相同類中的差別性小,不一樣類之間的差別性大。
下面對鳶尾花數據集的聚類結果進行評估,傳入特徵數據和聚類結果:
>>> from sklearn.metrics import calinski_harabasz_score >>> calinski_harabasz_score(features, prediction_labels) 481.78070899745234
咱們也能夠傳入特徵數據和原始結果:
>>> calinski_harabasz_score(features, labels) 487.33087637489984
能夠看到,對於原始結果計算出的分值是487.33,對於預測結果計算出的分值是481.78,相差並很少,說明預測結果仍是不錯。
通常狀況下,一個須要聚類的數據集並無目標數據,因此只能對預測結果進行評分。咱們須要人工對聚類的含義結果進行分析。
本篇文章主要介紹了以下內容:
(本節完。)
推薦閱讀:
歡迎關注做者公衆號,獲取更多技術乾貨。