計算高斯混合模型的可分性和重疊度(Overlap Rate, OLR)

簡介

本文章實現了Haojun Sun提出的一種計算高斯混合模型(GMM)重疊率的方法(論文:Measuring the component overlapping in the Gaussian mixture model)。這篇文論提出的方法可以計算任意兩個混合高斯分佈之間的重疊度。該方法可以用來評價GMM模型的好壞,我在我的論文中使用了這個算法,用來評價高斯混合模型聚類的可分性。

關於高斯混合模型(GMM)的相關概念可以參考另一篇博文:高斯混合模型及其EM算法的理解

使用GMM聚類或分析兩個高斯混合分佈的數據時,我們有時會希望兩個高斯分佈離得越遠越好,這樣表示數據纔有可分性。但很多情況下兩個高斯分佈會有重疊。一維和二維的重疊情況如下所示(圖片取自作者論文)。

overlap example

我們可以計算一些指標來間接反映兩個高斯分佈的重疊情況。比如可以計算Mahalanobis距離,Bhattacharyya距離或Kullback-Leibler (KL)距離,可以衡量兩個高斯分佈的相似性。但是Mahalanobis距離預設兩個分佈具有相同的協方差,Bhattacharyya距離和KL距離都考慮了協方差,但卻沒有考慮高斯混合分佈的混合係數(mixing coefficient)。而且KL距離對高維的正態分佈沒有解析解,計算複雜。

這篇論文提出的計算OLR的方法考慮了高斯混合分佈中的所有參數,包括均值,協方差和混合係數

OLR計算

假設有nndd維的樣本X={X1,...,Xn}\boldsymbol{X} = \{X_1,..., X_n\}. 其中XiX_i是一個dd維向量。一個混合高斯模型的pdf可以表示爲:
p(X)=i=1kαiGi(X,μi,Σi)(1)p(X) = \sum_{i=1}^k \alpha_iG_i(X, \mu_i, \Sigma_i) \tag{1}
其中αi\alpha_i是混合係數,滿足αi>0\alpha_i > 0i=1kαi=1\sum_{i=1}^k\alpha_i=1.

Gi(X)G_i(X)是一個dd維高斯分佈,可以表示爲下面的形式:
Gi(X)=1(2π)d/2Σi1/2exp(12(Xμi)TΣi1(Xμi))(2)G_i(X) = \frac{1}{(2\pi)^{d/2} |\Sigma_i|^{1/2}} \exp \left( \frac{1}{2} (X-\mu_i)^T \Sigma_i^{-1}(X-\mu_i)\right) \tag{2}

以二維高斯分佈爲例。當兩個高斯分佈有重疊時,會形成鞍狀。如上圖的d和e,二維高斯分佈混合時會出現兩個峯和一個鞍部;當兩個分佈幾乎完全混合時,鞍部可能消失,但峯還在,此時明顯的峯只有一個,如上圖中的f。

論文中的兩個高斯分佈的OLR定義如下:
OLR(G1,G2)={1if p(X) has one peakp(Xsaddle)p(Xsubmax)if p(X) has two peaks(3)OLR(G_1, G_2) = \begin{cases} 1 &\text{if $p(X)$ has one peak} \\ \frac{p(X_{saddle})}{p(X_{submax})} &\text{if $p(X)$ has two peaks} \end{cases} \tag{3}

其中XsaddleX_{saddle}是pdf中的鞍點(saddle point),XsubmaxX_{submax}是pdf中的較低的峯(lower peak point)。OLR的示意圖如下圖所示。OLR計算的是鞍點的pdf與較低峯的pdf的比值。這麼做是因爲鞍點的pdf與混合係數αi\alpha_i有關。注意到OLR並不是落在重疊區域內數據的比例,因此跟數據量無關,只跟數據的分佈有關。定義中的p(Xsubmax)p(X_{submax})容易求,只需將兩個均值帶入(1)式,取較小的值即可。但是p(Xsaddle)p(X_{saddle})不容直接求得。下面介紹如何計算p(Xsaddle)p(X_{saddle})

OLR

注意到兩個峯點和鞍點在整個曲面上都應該是極值點。因此XsaddleX_{saddle}XsubmaxX_{submax}應該滿足下式:

{px1=Ax1α1G1+Bx1α2G2px2=Ax2α1G1+Bx2α2G2(4) \begin{cases} \frac{\partial p}{\partial x_1} = A_{x_1}\alpha_1G_1 + B_{x_1}\alpha_2 G_2 \\ \frac{\partial p}{\partial x_2} = A_{x_2}\alpha_1G_1 + B_{x_2}\alpha_2 G_2 \end{cases} \tag{4}

其中,

(Ax1Ax2)=Xμ1Σ112=Σ11(Xμ1)(Bx1Bx2)=Xμ2Σ112=Σ11(Xμ2)(5) \begin{aligned} \left( \begin{matrix} A_{x_1} \\ A_{x_2} \end{matrix} \right) = \nabla ||X-\mu_1||_{\Sigma_1^{-1}}^2 = -\Sigma_1^{-1}(X - \mu_1) \\ \left( \begin{matrix} B_{x_1} \\ B_{x_2} \end{matrix} \right) = \nabla ||X-\mu_2||_{\Sigma_1^{-1}}^2 = -\Sigma_1^{-1}(X - \mu_2) \end{aligned} \tag{5}

(4)式式一條曲線。如果XX已知,(5)式可求出。論文接下來證明,峯點和鞍點會在同一條曲線上,曲線方程如下:
Ax1Bx2Bx1Ax2=0(6)A_{x_1} B_{x_2} - B_{x_1} A_{x_2} = 0 \tag{6}

而且,鞍點會在以兩個峯點(均值處的pdf)之間的曲線段上。因此只要從第一個均值開始,沿着曲線(4)一直找到另一個均值,這個過程中的極小值點就是鞍點。得到鞍點的座標,帶入(1)式,就可以求得鞍點的pdf值。(6)式中的曲線稱爲Ridge Curve (RC).

OLR的算法如下:

  1. 輸入混合高斯分佈的參數(μ1,μ2,Σ1,Σ2,α1,α2)(\mu_1, \mu_2, \Sigma_1, \Sigma_2, \alpha_1, \alpha_2)
  2. 計算RC: Ax1Bx2Bx1Ax2=0A_{x_1} B_{x_2} - B_{x_1} A_{x_2} = 0
  3. 沿着RC,從μ1\mu_1μ2\mu_2按步長δ\delta找到RC中p(X)p(X)取得最大值和最小值的點
    3.1 令X0=μ1X_0 = \mu_1X0X_0的下一個點Xi+1X_{i+1}的第一維(x座標)Xi+11={Xi+δ(μ1μ2)}1X_{i+1}^1 = \{X_i + \delta(\mu_1-\mu_2)\}^1.
    3.2 將Xi+11X_{i+1}^1帶入RC方程(6),求得Xi+1X_{i+1}的第二維(y座標)Xi+12X_{i+1}^2
    3.3 根據(1)式計算p(Xi)p(X_i)
    3.4 if p(Xi)p(Xi1)>0p(X_i) - p(X_{i-1}) > 0 and p(Xi)p(Xi+1)>0p(X_i) - p(X_{i+1}) > 0, XiX_i is maximum point (peak)
    3.5 if p(Xi)p(Xi1)<0p(X_i) - p(X_{i-1}) < 0 and p(Xi)p(Xi+1)<0p(X_i) - p(X_{i+1}) < 0, XiX_i is minimum point
  4. 根據(3)式計算OLR

上述算法δ\delta可以取δ=μ1μ2/1000\delta = ||\mu_1 - \mu_2|| / 1000. 作者認爲當OLR小於0.6時,兩個類別可分性良好(visually well separated),當OLR大於0.8時,兩個類別嚴重重疊(strongly overlapping)。

如果是有多個類別的情況,可以計算所有任意兩個類別的重疊度,最後對所有重疊度求均值作爲整體的重疊度。

算法實現

p(Xi)p(X_i)可以用python第三方統計包scipy.stats中的multivariate_normal計算。輸入兩個高斯分佈的參數可以求出pdf值。

完整代碼可以參考GMM Overlap Rate。論文中給出的算法有一些問題。

import math
import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import inv
from scipy.stats import multivariate_normal

class BiGauss(object):
    """docstring for BiGauss"""
    def __init__(self, mu1, mu2, Sigma1, Sigma2, pi1, pi2, steps = 100):
        super(BiGauss, self).__init__()
        self.mu1      = mu1
        self.mu2      = mu2
        self.Sigma1   = Sigma1
        self.Sigma2   = Sigma2
        self.pi1      = pi1
        self.pi2      = pi2
        self.biGauss1 = multivariate_normal(mean = self.mu1, cov = self.Sigma1, allow_singular = True)
        self.biGauss2 = multivariate_normal(mean = self.mu2, cov = self.Sigma2, allow_singular = True)
        self.steps    = steps
        self.inv_Sig1 = -inv(self.Sigma1)
        self.inv_Sig2 = -inv(self.Sigma2)

        # variables to calculate RC
        self.A_1 = self.inv_Sig1[0][0]
        self.B_1 = self.inv_Sig1[0][1]
        self.C_1 = self.inv_Sig1[1][0]
        self.D_1 = self.inv_Sig1[1][1]
        self.A_2 = self.inv_Sig2[0][0]
        self.B_2 = self.inv_Sig2[0][1]
        self.C_2 = self.inv_Sig2[1][0]
        self.D_2 = self.inv_Sig2[1][1]

計算pdf

def pdf(self, x):
        return self.pi1 * self.biGauss1.pdf(x) + self.pi2 * self.biGauss2.pdf(x)

根據xx求出yy,使得(x,y)(x,y)在RC上

def RC(self, x):
        E = self.A_1 * (x - self.mu1[0])
        F = self.C_1 * (x - self.mu1[0])
        G = self.A_2 * (x - self.mu2[0])
        H = self.C_2 * (x - self.mu2[0])

        I = E * self.D_2 - F * self.B_2
        J = H * self.B_1 - G * self.D_1
        K = self.B_1 * self.D_2 - self.B_2 * self.D_1
        M = F * G - E * H

        P = K
        Q = I + J - K * (self.mu2[1] + self.mu1[1])
        S = -(M + I * self.mu2[1] + J * self.mu1[1])

        if Q**2 - 4*P*S < 0:
            return None

        y = max((-Q + math.sqrt(Q**2 - 4*P*S)) / (2*P), (-Q - math.sqrt(Q**2 - 4*P*S)) / (2*P))

        return y

求OLR

def OLR(self):
        e      = math.sqrt((self.mu1[0] - self.mu2[0])**2 + (self.mu1[1] - self.mu2[1])**2) / float(self.steps)
        x_step = e*(self.mu1[0]-self.mu2[0]) # each step for x
        y_step = e*(self.mu1[1]-self.mu2[1]) # each step for y
        p_x    = self.mu1[0] - x_step

        while self.RC(p_x) == None:
            p_x = p_x - x_step
        
        p_y   = self.RC(p_x)
        p     = [p_x, p_y]
        p_pre = self.mu1
        p_min = min(self.pdf(p), self.pdf(p_pre))
        p_max = max(self.pdf(p), self.pdf(p_pre))
        index = 0
        while index < self.steps:
            if self.RC(p[0] - x_step) != None:
                p_next = [p[0] - x_step, self.RC(p[0] - x_step)] # next point on ridge curve
                if self.pdf(p) > self.pdf(p_pre) and self.pdf(p) > self.pdf(p_next):
                    p_max = self.pdf(p)
                if self.pdf(p) < self.pdf(p_pre) and self.pdf(p) < self.pdf(p_next):
                    p_min = self.pdf(p)
            p_pre = p
            p     = p_next
            index += 1

        pdf_mu1 = self.pdf(self.mu1)
        pdf_mu2 = self.pdf(self.mu2)
        return p_min / min(pdf_mu1, pdf_mu2) if p_min < min(pdf_mu1, pdf_mu2) else 1.0

上述代碼有時會計算出OLR大於1的情況,還沒有分析原因,因爲草稿丟了,不知道代碼中的A~S變量代表什麼意思……因此代碼中做了限制,如果求出的OLR大於1,那麼只會返回1.

論文中探討了混合係數、均值間距離和協方差對OLR的影響。論文中給出了一個例子,如下。當α1=0.46\alpha_1 = 0.46時該例子可以取到最小的OLR rminr_{min}. 論文沒有給出rminr_{min}的具體數值,但是給出了OLR隨α1\alpha_1取值變化的曲線圖。上述代碼算出來的結果是rmin=0.660r_{min} = 0.660,也確實在α1=0.46\alpha_1 = 0.46處取得。與曲線圖中的位置吻合。論文中提到當α1=0.3\alpha_1 = 0.3時,ORL等於0.7288,上述代碼給出的結果是0.7270.

示例代碼中也畫出了OLR隨α1\alpha_1變化的曲線圖和OLR隨兩個均值之間距離變化的曲線圖。曲線走勢與論文中的圖示一致,但具體數值有些差別。

這個示例代碼只能計算二維混合高斯模型,更高維的無法計算,但是理論上,這個算法是適用於任何維度的GMM的。

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