聚类方法小全(一)

1 K-means

K-means是最简单且十分好用的聚类方法,其所实现的功能就是将 N N N个点分为 K K K类。它的基本步骤可以分为四步:

  • 随机选取 K K K个中心点
  • 将所有的 N N N个点都分配到这 K K K个中心点中去
  • 将每一个组的中心点重新作为 K K K个中心点
  • 重复步骤 2 2 2和步骤 3 3 3

1.1 相关定义

要介绍这样一个算法,我们首先要明白一下定义:

  • 我们的数据集为 { x 1 , x 2 , . . . , x N } , x n ∈ R D \{x_1, x_2, ..., x_N\}, x_n \in R^D {x1,x2,...,xN},xnRD
  • 聚类中心(就是我们要找的 K K K个中心点) μ k , k = 1 , 2 , . . . , K \mu_k, k=1, 2, ..., K μk,k=1,2,...,K
  • 布尔类型的变量 r n k ∈ { 0 , 1 } r_{nk}\in\{0, 1\} rnk{0,1}, 表示对于第 n n n个点,如果它输入第 k k k类,那么 r n k = 1 r_{nk} = 1 rnk=1, 否则 r n k = 0 r_{nk} = 0 rnk=0
  • 做K-means的最终目标就是最小化 J = ∑ n = 1 N ∑ n = 1 K r n k ∣ ∣ x n − μ k ∣ ∣ 2 J = \sum_{n = 1}^N \sum_{n = 1} ^ K r_{nk}||x_n - \mu_k||^2 J=n=1Nn=1Krnk∣∣xnμk2

1.2 迭代方法

要实现这样的最终目标,我们需要简单的借助 E M EM EM的思想,具体的 E M EM EM介绍我会放在后面。简单来说就是需要迭代 r n k r_{nk} rnk μ k \mu_k μk的值。

  • **E(expectation)步骤:**固定 μ k \mu_k μk,在最小化 J J J的情况下求解 r n k r_{nk} rnk。这一步很简单,只需要对每一个点进行操作,找出每一个点最近的 μ k \mu_k μk,然后使得这个点的 r n k = 1 r_{nk} = 1 rnk=1
  • **M(maximization)步骤:**固定 r n k r_{nk} rnk,在最小化 J J J的情况下求解 μ k \mu_k μk。这一步也不麻烦,实际上就是对 J J J求导,使得导数为 0 0 0,即令 2 ∑ n = 1 N r n k ( x n − μ k ) = 0 2\sum_{n = 1}^Nr_{nk}(x_n - \mu_k) = 0 2n=1Nrnk(xnμk)=0,解得 μ k = ∑ n r n k x n ∑ n r n k \mu_k = \frac{\sum_nr_{nk}x_n}{\sum_nr_{nk}} μk=nrnknrnkxn

1.3 实现技巧

在实现K-means的时候,也存在一些小技巧,比如说:

  • 在初始化 μ k \mu_k μk的时候,并不随机选择范围内的点,而是在已有的点中随机选择。
  • 用不同的初始化结果多跑几次,选择其中效果最好的。
  • 在E步骤中,需要计算 x n x_n xn μ k \mu_k μk之间的距离,那么这个时候可以使用KD-Tree等算法进行提速。(我没理解,总感觉直接计算时间复杂度更低, O ( k n ) O(kn) O(kn)嘛)
  • 还可以使用Mini-batch K-Means。在每个E和M的迭代中,选择数据点中的一部分进行迭代。这样做是会更快,但是可能结果误差会更大。下面简单介绍一下:

当我们的Mini-batch选择为1的时候,就叫做Sequential Update,实际上就是对每一个数据点 x n x_n xn进行操作,选择离它最近的中心点 μ k o l d \mu_k^{old} μkold,对这个点进行更新: μ k n e w = μ k o l d + η n ( x n − μ k o l d ) \mu_k^{new} = \mu_k^{old} + \eta_n(x_n - \mu_k^{old}) μknew=μkold+ηn(xnμkold)。这种方法就比较适合数据点不是一下子全部得到的结果。Mini-batch更大的时候也是同样的道理。效果都是差不多的。

1.4 K-Mediods

有一种情况我们需要考虑,那就是如果这些数据点中存在噪声怎么办?就比如说下面图所示的数据点中最右边的那个点,很明显就是噪声,那么我们使用K-Means得到的中心点很明显不是我们想要的(如下图左边所示),这个时候就需要我们使用K-Mediods算法。

image-20230829150609814

这个方法的E步骤和K-Means是一样的,但是M步骤有所不同,它所要最小化的函数并不是 J = ∑ n = 1 N ∑ n = 1 K r n k ∣ ∣ x n − μ k ∣ ∣ 2 J = \sum_{n = 1}^N \sum_{n = 1} ^ K r_{nk}||x_n - \mu_k||^2 J=n=1Nn=1Krnk∣∣xnμk2了,而是 J ~ = ∑ n = 1 N ∑ n = 1 K r n k v ( x n − μ k ) \tilde J = \sum_{n = 1}^N \sum_{n = 1} ^ K r_{nk}v(x_n - \mu_k) J~=n=1Nn=1Krnkv(xnμk)

其中的 v v v函数是指一些并不能用数学方法具体表达的方法,在这里的 v v v函数就是在这些数据点中选择一个点作为 μ k \mu_k μk,然后其他点到这个点的距离之和。

也就是,这个算法的M步骤就是**选择这些数据点中的某个点作为中心点,要求其他店到这个中心点的距离和最小。**那么这个时候M步骤就不能用求导方法 O ( 1 ) O(1) O(1)得到了,就只能逐个遍历了,最好情况下时间复杂度就变成了 O ( k ( n / k ) 2 ) O(k(n/k)^2) O(k(n/k)2)

1.5 奇怪的应用:图片压缩

其实就是对图片的色彩进行压缩。每一个图片所占用的内存实际上是 H ∗ W ∗ R G B H*W*RGB HWRGB,其中RGB是说照片的三原色,每一种颜色实际上都是要用8bit来进行表示,那么实际上占用的内存就是 H ∗ W ∗ 24 H*W*24 HW24。但实际上,是不需要那么多颜色的,一般来说几种颜色就可以较好地表达完一张照片,比如说:

image-20230829154053380

每一种颜色为一个类,那么存储空间就从 H ∗ W ∗ 24 H*W*24 HW24变成了 H ∗ W ∗ K H*W*K HWK,但由于每一个bit都可以用 2 M 2^M 2M,因此可以变成 H ∗ W ∗ l o g 2 K H*W*log_2K HWlog2K

1.6 局限性

K-Means主要存在两个方面的局限性:

  • K K K的数值需要自己去定
  • 每一个点不是这个类就是那个类,不能计算置信度

1.7 代码

from sklearn import datasets
import numpy as np
import open3d as o3d

n_sample = 500
noisy_moon = datasets.make_moons(n_samples=n_sample, noise=.05)
# print(noisy_moon[0])

def dis(a, b) :
    return (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1])

def kmeans(data, k, tolerance, maxIter) :
    idx = np.random.choice(len(data), k, replace=False)
    centroids = data[idx]
    cluster = np.zeros(len(data))
    dist = np.zeros(len(data))
    for i in range(maxIter) :
        for j in range(len(data)) :
            cluster[j] = -1
            dist[j] = 1e10
        for j in range(len(data)) :
            for k in range(len(centroids)) :
                tmp = dis(data[j], centroids[k])
                if tmp < dist[j] :
                    dist[j] = tmp
                    cluster[j] = k

        old_centroids = np.copy(centroids)
        for j in range(len(centroids)) :
            dataTmp = data[cluster == j]
            if len(dataTmp) > 0 :
                centroids[j][0] = np.mean(dataTmp[:, 0])
                centroids[j][1] = np.mean(dataTmp[:, 1])
            else :
                centroids[j] = data[np.random.choice(len(data), 1, replace=False)]

        distortion = np.linalg.norm(centroids - old_centroids)
        if distortion < tolerance :
            break

    return cluster, centroids

# cluster, centroids = kmeans(noisy_moon[0], 2, 0.0001, 1000)
# print(cluster)
datas = np.zeros([len(noisy_moon[0]), 3])
for i in range(len(noisy_moon[0])) :
    datas[i][0] = noisy_moon[0][i][0]
    datas[i][1] = noisy_moon[0][i][1]
    datas[i][2] = 0
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(datas)

cluster, centroids = kmeans(datas, 2, 0.0001, 1000)
color = np.zeros([len(noisy_moon[0]), 3])
for i in range(len(noisy_moon[0])) :
    if cluster[i] == 0 :
        color[i][0] = 1
    else :
        color[i][1] = 1

pcd.colors = o3d.utility.Vector3dVector(color)

o3d.visualization.draw_geometries([pcd])

2 GMM

GMM实际上就是使用高斯模型去表示每一个类,使用这种方式就可以去计算每一个点属于各个类的置信度。

image-20230829155357534

2.1 高斯模型

一维高斯模型为:

N ( x ∣ μ , σ 2 ) = 1 ( 2 π σ 2 ) e x p { − 1 2 σ 2 ( x − μ ) 2 } N(x|\mu, \sigma^2) = \frac{1}{(2\pi \sigma^2)}exp\{-\frac{1}{2\sigma^2}(x - \mu)^2\} N(xμ,σ2)=(2πσ2)1exp{2σ21(xμ)2}

而高维的高斯模型即为:

N ( x ∣ μ , Σ ) = 1 ( 2 π ) D / 2 1 ∣ Σ ∣ 1 / 2 e x p { − 1 2 ( x − μ ) T Σ ( − 1 ) ( x − μ ) } N(\mathbf{x}|\mathbf{\mu}, \mathbf{\Sigma}) = \frac{1}{(2\pi)^{D/2}}\frac{1}{|\Sigma|^{1/2}}exp\{-\frac{1}{2}(\mathbf{x} - \mathbf{\mu})^T\mathbf{\Sigma}^{(-1)}(\mathbf{x} - \mathbf{\mu})\} N(xμ,Σ)=(2π)D/21∣Σ1/21exp{21(xμ)TΣ(1)(xμ)}

2.2 GMM模型

实际上就是好多个高斯模型的线性组合。那么我们可以算出 x x x点存在点的可能性为:

p ( x ) = ∑ k = 1 K π k N ( x ∣ μ k , Σ k ) p(x) = \sum_{k = 1} ^K \pi_kN(x|\mu_k, \Sigma_k) p(x)=k=1KπkN(xμk,Σk)

其中, π k \pi_k πk为第 k k k个高斯模型所占的比重。因此,要描述一个GMM模型,所需要的参数就是 { μ k , Σ k , π k } , k = 1 , 2 , . . . , k \{\mu_k, \Sigma_k, \pi_k\}, k = 1, 2, ..., k {μk,Σk,πk},k=1,2,...,k

但是我们知道 p ( x ) p(x) p(x)是没有用的,我们并不是要生成点,而是已经有了很多点我们需要去进行聚类。

2.3 数学基础

首先,我们定义一个布尔类型的变量 z k ∈ { 0 , 1 } , ∑ k z k = 1 z_k \in \{0, 1\}, \sum_kz_k = 1 zk{0,1},kzk=1,这个指的是一种事件,就是表示“这个点属于第 k k k类”这个事件

那么, p ( z k = 1 ) = π k p(z_k = 1) = \pi_k p(zk=1)=πk就是一种先验分布,等同于K-Means中的 r n k r_{nk} rnk,不同的是他并不是说非 0 0 0 1 1 1,而是说是存在概率的。那么,什么叫先验分布呢?就是说这个空间内任意存在一个点,咱也不知道这个点具体会在哪里,就是它属于哪一个高斯分布的概率。那我都完全不知道点在哪里,那只能通过权重来进行判断了不是嘛?它所占的比重越大, π k \pi_k πk就越大。后验就是知道了高斯分布,也知道了 x x x在哪里,求出 p ( z ∣ x ) p(z|x) p(zx),也就是这个点属于分布 z z z的概率。

那么这个后验分布就可以用贝叶斯公式来进行计算:

p ( z ∣ x ) = p ( x ∣ z ) p ( z ) p ( x ) , p ( x ) = ∑ z p ( z ) p ( x ∣ z ) p(z|x) = \frac{p(x|z)p(z)}{p(x)}, p(x) = \sum_zp(z)p(x|z) p(zx)=p(x)p(xz)p(z),p(x)=zp(z)p(xz)

其中, p ( z ) p(z) p(z)是先验分布, p ( x ) p(x) p(x)则是2.2节中所介绍的, p ( x ∣ z ) p(x|z) p(xz)就之后再介绍一下。

接下来需要介绍一种表示方法:

我们的 z k = 1 z_k = 1 zk=1事件也可以表示为一种1-of-k的方法,也就是 z = [ z 1 , . . . , z k , . . . , z K ] z = [z_1, ..., z_k, ..., z_K] z=[z1,...,zk,...,zK],其中只有 z k = 1 z_k = 1 zk=1,其他的为 0 0 0。这样表示的话,我们之前所提到的先验分布 p ( z k = 1 ) = π k p(z_k = 1) = \pi_k p(zk=1)=πk就表示为 p ( z ) = Π k = 1 K π k z k p(z) = \Pi_{k = 1}^K \pi_k^{z_k} p(z)=Πk=1Kπkzk。这也很好理解,毕竟其他值都是 0 0 0,任何数的 0 0 0次方都为 1 1 1,因此就和没有乘是一样的效果。

上面一段的意思就是: p ( z k = 1 ) = π k p(z_k = 1) = \pi_k p(zk=1)=πk等同于 p ( z ) = Π k = 1 K π k z k p(z) = \Pi_{k = 1}^K \pi_k^{z_k} p(z)=Πk=1Kπkzk

我们再来看 p ( x ∣ z k = 1 ) p(x|z_k = 1) p(xzk=1),这个其实就坍塌成了一个普通的高斯分布,也就是 p ( x ∣ z k = 1 ) = N ( x ∣ μ k , Σ k ) p(x|z_k = 1) = N(x|\mu_k, \Sigma_k) p(xzk=1)=N(xμk,Σk)

再用上上面那一大段所描述的思想,是不是其实就是 p ( x ∣ z ) = Π k = 1 K N ( x ∣ μ k , Σ k ) z k p(x|z) = \Pi_{k = 1}^K N(x|\mu_k, \Sigma_k)^{z_k} p(xz)=Πk=1KN(xμk,Σk)zk

然后,我们利用联合分布进行计算,也就是 p ( x ) = ∑ z p ( x , z ) p(x) = \sum_zp(x, z) p(x)=zp(x,z),再利用全概率公式,即可得到:

p ( x ) = ∑ z p ( z ) p ( x ∣ z ) = ∑ k = 1 K π k N ( x ∣ μ k , Σ k ) p(x) = \sum_zp(z)p(x|z) = \sum_{k = 1}^K \pi_kN(x|\mu_k, \Sigma_k) p(x)=zp(z)p(xz)=k=1KπkN(xμk,Σk)

这下我们就可以计算出后验分布 p ( z ∣ x ) p(z|x) p(zx)咯,我们用 γ ( z k ) \gamma(z_k) γ(zk)来表示 p ( z k = 1 ∣ x ) p(z_k = 1|x) p(zk=1∣x),那么就会有:

p ( z ∣ x ) = p ( z , x ) p ( x ) = p ( z ) p ( x ∣ z ) ∑ j = 1 K p ( x ∣ z j ) p ( z j ) p(z|x) = \frac{p(z, x)}{p(x)} = \frac{p(z)p(x|z)}{\sum_{j = 1} ^ Kp(x|z_j)p(z_j)} p(zx)=p(x)p(z,x)=j=1Kp(xzj)p(zj)p(z)p(xz)

γ ( z k ) ≡ p ( z k = 1 ∣ x ) = p ( z k = 1 ) p ( x ∣ z k = 1 ) Σ j = 1 K p ( x ∣ z j = 1 ) p ( z j = 1 ) = π k N ( x n ∣ μ k , Σ k ) ∑ j = 1 K π j N ( x n ∣ μ j , Σ j ) \gamma(z_k) \equiv p(z_k = 1 | x) = \frac{p(z_k = 1)p(x|z_k = 1)}{\Sigma_{j = 1}^Kp(x|z_j = 1)p(z_j = 1)} = \frac{\pi_kN(x_n|\mu_k, \Sigma_k)}{\sum_{j = 1}^K \pi_jN(x_n|\mu_j, \Sigma_j)} γ(zk)p(zk=1∣x)=Σj=1Kp(xzj=1)p(zj=1)p(zk=1)p(xzk=1)=j=1KπjN(xnμj,Σj)πkN(xnμk,Σk)

但是!虽然我们可以计算出每一个点分布给每一个高斯分布的概率,可是高斯分布的参数( μ , Σ , π \mu,\Sigma,\pi μ,Σ,π)完全没有去进行计算,上面过程是假设已经确定好了而已。那么,应该如何去进行计算呢?这个时候就要用到MLE算法了。

2.4 MLE(Maximum Likelihood)

2.4.1 奇点问题

假如说,有一个分布是一个圆形的,也就是 Σ k = σ k 2 I \Sigma_k = \sigma_k^2I Σk=σk2I,然后这个点的位置就在这个分布的中心,也就是 x n = μ j x_n = \mu_j xn=μj,那么就会有:

N ( x n ∣ x n , σ j 2 I ) = 1 ( 2 π ) 1 / 2 1 σ j N(x_n|x_n, \sigma_j^2I) = \frac{1}{(2\pi)^{1/2}\frac{1}{\sigma_j}} N(xnxn,σj2I)=(2π)1/2σj11

但如果 σ j \sigma_j σj很小的话,这个值就会非常大,甚至会达到 inf ⁡ \inf inf,也就是说一个分布里面只有一个点的话就容易出现这种情况。那么该如何避免奇点问题呢?最好的解决方式就是不使用MLE,转而使用MAP或者贝叶斯接近。

但是那两种方法太过麻烦,因此可以在 Σ k \Sigma_k Σk很小,就重新给它初始化一个很大的值就好了。

2.4.2 MLE的具体步骤

实际上这个过程就是要让各个分布能够很好的拟合点,实际上也就是最大化 p ( x ) p(x) p(x)

对于单个点来说, p ( x ) = ∑ k = 1 K π k N ( x ∣ μ k , Σ k ) p(x) = \sum_{k = 1}^K\pi_kN(x|\mu_k, \Sigma_k) p(x)=k=1KπkN(xμk,Σk)

最终目标是要每个点的 p ( x ) p(x) p(x)连乘值最大,但是连乘是很难进行计算的,因此我们可以取对数,从而使得乘法变成加法:

ln ⁡ p ( X ∣ π , μ , Σ ) = ∑ n = 1 N ln ⁡ { ∑ k = 1 K π k N ( x n ∣ μ k , Σ k ) } \ln p(X|\pi, \mu, \Sigma) = \sum_{n = 1}^N\ln\{\sum_{k = 1}^K\pi_kN(x_n|\mu_k, \Sigma_k)\} lnp(Xπ,μ,Σ)=n=1Nln{k=1KπkN(xnμk,Σk)},然后将其最大化。

有三个参数该怎么办呢?很简单,这三个每次都固定两个,然后变化其中的一个。具体步骤我们放在下面:

2.4.3 对 μ k \mu_k μk进行操作

上面这一大串,我们首先对 μ k \mu_k μk求导,让它等于 0 0 0,结果就是:

0 = − ∑ n = 1 N π k N ( x n ∣ μ k , Σ k ) Σ j π j N ( x n ∣ μ j , Σ j ) ∑ k ( x n − μ k ) 0 = -\sum_{n = 1} ^N \frac{\pi_kN(x_n|\mu_k, \Sigma_k)}{\Sigma_j\pi_jN(x_n|\mu_j, \Sigma_j)}\sum_k(x_n - \mu_k) 0=n=1NΣjπjN(xnμj,Σj)πkN(xnμk,Σk)k(xnμk)

我们注意到,中间这一大坨( π k N ( x n ∣ μ k , Σ k ) Σ j π j N ( x n ∣ μ j , Σ j ) \frac{\pi_kN(x_n|\mu_k, \Sigma_k)}{\Sigma_j\pi_jN(x_n|\mu_j, \Sigma_j)} ΣjπjN(xnμj,Σj)πkN(xnμk,Σk))是我们之前算的后验概率 γ ( z n k ) \gamma(z_{nk}) γ(znk),那么就可以将上面的公式简化为:

0 = − ∑ n = 1 N γ ( z n k ) ∑ k ( x n − μ k ) 0 = -\sum_{n = 1}^N \gamma(z_{nk})\sum_k(x_n - \mu_k) 0=n=1Nγ(znk)k(xnμk)

计算一下:

符号和 Σ k \Sigma_k Σk都是可以去掉的: 0 = ∑ n = 1 N γ ( z n k ) ( x n − μ k ) 0 = \sum_{n = 1} ^N \gamma(z_{nk})(x_n - \mu_k) 0=n=1Nγ(znk)(xnμk)

∑ n = 1 N γ ( z n k ) x n = μ k ∑ n = 1 N γ ( z n k ) \sum_{n = 1}^N\gamma(z_{nk})x_n = \mu_k\sum_{n = 1}^N\gamma(z_{nk}) n=1Nγ(znk)xn=μkn=1Nγ(znk)

μ k = 1 N k ∑ n = 1 N γ ( z n k ) x n , N k = ∑ n = 1 N γ ( z n k ) \mu_k = \frac{1}{N_k}\sum_{n = 1}^N\gamma(z_{nk})x_n, N_k = \sum_{n = 1}^N\gamma(z_{nk}) μk=Nk1n=1Nγ(znk)xn,Nk=n=1Nγ(znk)

其中, N k N_k Nk感性理解,实际上就是有多少个点属于第 k k k类,就算后验概率为 0.5 0.5 0.5,也就是有 50 % 50\% 50%的概率属于 k k k,那也就可以算有 0.5 0.5 0.5个点属于 k k k。那么,实际上 μ k \mu_k μk不就是每个点的加权平均嘛?

2.4.4 对 Σ k \Sigma_k Σk进行操作

仍然是对 Σ k \Sigma_k Σk进行求导,得到的结果为:

Σ k = 1 N k ∑ n = 1 N γ ( z n k ) ( x n − μ k ) ( x n − μ k ) T \Sigma_k = \frac{1}{N_k}\sum_{n = 1}^N\gamma(z_{nk})(x_n - \mu_k)(x_n - \mu_k)^T Σk=Nk1n=1Nγ(znk)(xnμk)(xnμk)T

可以注意到,这个是对方差的加权平均。

2.4.5 对 π k \pi_k πk进行操作

针对 π k \pi_k πk,我们不能够像上面两个参数进行操作了,因为我们的 π k \pi_k πk是有约束条件的:

∑ k = 1 K π k = 1 \sum_{k = 1} ^ K \pi_k = 1 k=1Kπk=1

那么我们就要使用拉格朗日乘子法,也就是让原式子变成:

ln ⁡ p ( X ∣ π , μ , Σ ) + λ ( ∑ k = 1 K π k − 1 ) \ln p(X|\pi, \mu, \Sigma) + \lambda(\sum_{k = 1} ^K \pi_k - 1) lnp(Xπ,μ,Σ)+λ(k=1Kπk1)

然后对 π k \pi_k πk求导让它等于 0 0 0

0 = ∑ n = 1 N N ( x n ∣ μ k , Σ k ) ∑ j = 1 K π j N ( x n ∣ μ k , Σ k ) + λ 0 = \sum_{n = 1} ^N \frac{N(x_n|\mu_k, \Sigma_k)}{\sum_{j = 1}^K\pi_jN(x_n|\mu_k, \Sigma_k)} + \lambda 0=n=1Nj=1KπjN(xnμk,Σk)N(xnμk,Σk)+λ

两边同时乘以 ∑ k = 1 K π k \sum_{k = 1}^K\pi_k k=1Kπk,就会变成 0 = ∑ n = 1 N ∑ k = 1 K π k N ( x n ∣ μ k , Σ k ) ∑ j = 1 K π j N ( x n ∣ μ k , Σ k ) + ∑ k = 1 K π k λ 0 = \sum_{n = 1} ^N\sum_{k = 1}^K \frac{\pi_kN(x_n|\mu_k, \Sigma_k)}{\sum_{j = 1}^K\pi_jN(x_n|\mu_k, \Sigma_k)} + \sum_{k = 1}^K\pi_k\lambda 0=n=1Nk=1Kj=1KπjN(xnμk,Σk)πkN(xnμk,Σk)+k=1Kπkλ

把其中一个求和放到上面去, 0 = ∑ n = 1 N ∑ k = 1 K π k N ( x n ∣ μ k , Σ k ) ∑ j = 1 K π j N ( x n ∣ μ k , Σ k ) + ∑ k = 1 K π k λ 0 = \sum_{n = 1} ^N \frac{\sum_{k = 1}^K\pi_kN(x_n|\mu_k, \Sigma_k)}{\sum_{j = 1}^K\pi_jN(x_n|\mu_k, \Sigma_k)} + \sum_{k = 1}^K\pi_k\lambda 0=n=1Nj=1KπjN(xnμk,Σk)k=1KπkN(xnμk,Σk)+k=1Kπkλ

就算字母不一样,但是分子分母还是一样的,就变成了 0 = ( ∑ n = 1 N 1 ) + λ 0 = (\sum_{n = 1}^N 1) + \lambda 0=(n=1N1)+λ,即 λ = N \lambda = N λ=N

那就变成了 0 = ∑ n = 1 N N ( x n ∣ μ k , Σ k ) ∑ j = 1 K π j N ( x n ∣ μ k , Σ k ) + N 0 = \sum_{n = 1} ^N \frac{N(x_n|\mu_k, \Sigma_k)}{\sum_{j = 1}^K\pi_jN(x_n|\mu_k, \Sigma_k)} + N 0=n=1Nj=1KπjN(xnμk,Σk)N(xnμk,Σk)+N

我们搞一个 π k \pi_k πk出来,变成 0 = 1 π k ∑ n = 1 N π k N ( x n ∣ μ k , Σ k ) ∑ j = 1 K π j N ( x n ∣ μ k , Σ k ) + N 0 = \frac{1}{\pi_k}\sum_{n = 1} ^N \frac{\pi_kN(x_n|\mu_k, \Sigma_k)}{\sum_{j = 1}^K\pi_jN(x_n|\mu_k, \Sigma_k)} + N 0=πk1n=1Nj=1KπjN(xnμk,Σk)πkN(xnμk,Σk)+N

中间这一坨,又变成先验概率 γ ( z n k ) \gamma(z_{nk}) γ(znk)咯,最后又成了 0 = 1 π k ∑ n = 1 N γ ( z n k ) − N 0 = \frac{1}{\pi_k}\sum_{n = 1} ^N \gamma(z_{nk}) - N 0=πk1n=1Nγ(znk)N,结果就是简简单单的 π k = N k N \pi_k = \frac{N_k}{N} πk=NNk

2.5 总结算法

主要分为四步:

  • 首先,初始化 μ k , Σ k , π k \mu_k, \Sigma_k, \pi_k μk,Σk,πk
  • **E(expectation)步骤:**计算相应的后验概率 γ ( z k ) = π k N ( x n ∣ μ k , Σ k ) ∑ j = 1 K π j N ( x n ∣ μ j , Σ j ) \gamma(z_k) = \frac{\pi_kN(x_n|\mu_k, \Sigma_k)}{\sum_{j = 1}^K \pi_jN(x_n|\mu_j, \Sigma_j)} γ(zk)=j=1KπjN(xnμj,Σj)πkN(xnμk,Σk)
  • **M(maximization)步骤:**更新 μ k , Σ k , π k \mu_k, \Sigma_k, \pi_k μk,Σk,πk,即:
    • μ k n e w = 1 N k ∑ n = 1 N γ ( z n k ) x n \mu_k^{new} = \frac{1}{N_k}\sum_{n = 1}^N\gamma(z_{nk})x_n μknew=Nk1n=1Nγ(znk)xn
    • Σ k n e w = 1 N k ∑ n = 1 N γ ( z n k ) ( x n − μ k ) ( x n − μ k ) T \Sigma_k^{new} = \frac{1}{N_k}\sum_{n = 1}^N\gamma(z_{nk})(x_n - \mu_k)(x_n - \mu_k)^T Σknew=Nk1n=1Nγ(znk)(xnμk)(xnμk)T
    • π k n e w = N k N \pi_k^{new} = \frac{N_k}{N} πknew=NNk
    • N k = ∑ n = 1 N γ ( z n k ) N_k = \sum_{n = 1}^N\gamma(z_{nk}) Nk=n=1Nγ(znk)
  • 然后计算 ln ⁡ p ( X ∣ π , μ , Σ ) = ∑ n = 1 N ln ⁡ { ∑ k = 1 K π k N ( x n ∣ μ k , Σ k ) } \ln p(X|\pi, \mu, \Sigma) = \sum_{n = 1}^N\ln\{\sum_{k = 1}^K\pi_kN(x_n|\mu_k, \Sigma_k)\} lnp(Xπ,μ,Σ)=n=1Nln{k=1KπkN(xnμk,Σk)},收敛了即可停止

2.6 代码

from sklearn import datasets
import numpy as np
from scipy.stats import multivariate_normal
import open3d as o3d

n_sample = 500
noisy_moon = datasets.make_moons(n_samples=n_sample, noise=.05)
# da = datasets.make_circles(n_samples=n_sample, factor=.5, noise=.05)
data = noisy_moon[0]

def GMM(data, k, tolerance, maxIter):
    n, dim = data.shape
    mu = data[np.random.choice(range(n), k, replace=False)]
    var = np.array([np.eye(dim)] * k)
    w = np.ones([n, k]) / k
    pi = np.ones(k) / k
    nll = np.inf

    for j in range(maxIter):
        # E Step
        pdfs = np.zeros(((n, k)))
        for i in range(k):
            pdfs[:, i] = pi[i] * multivariate_normal.pdf(data, mean=mu[i], cov=np.diag(var[i]))

        w = pdfs / pdfs.sum(axis=1).reshape(-1, 1)

        # M Step
        # pi
        Nk = w.sum(axis=0)
        pi = Nk / Nk.sum()
        # mu
        for i in range(k):
            mu[i] = np.multiply(w[:, i].reshape(-1, 1), data).sum(axis=0) / Nk[i]
        # var
        for i in range(k):
            var[i] = np.average((data - mu[i]) ** 2, axis=0, weights=w[:, i])
        # nll
        last_nll = nll
        nll = np.sum(np.log(pdfs.sum(axis=0)))
        if np.abs(nll - last_nll) < tolerance:
            break
    return np.argmax(w, axis=1)

cluster = GMM(data, 2, 0.0001, 1000)
datas = np.zeros([len(noisy_moon[0]), 3])
for i in range(len(noisy_moon[0])) :
    datas[i][0] = noisy_moon[0][i][0]
    datas[i][1] = noisy_moon[0][i][1]
    datas[i][2] = 0
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(datas)

color = np.zeros([len(noisy_moon[0]), 3])
for i in range(len(noisy_moon[0])) :
    if cluster[i] == 0 :
        color[i][0] = 1
    else :
        color[i][1] = 1

pcd.colors = o3d.utility.Vector3dVector(color)

o3d.visualization.draw_geometries([pcd])

3 EM

在上面所介绍的两种聚类方法中,我们都用到了EM的思想。EM就是为了解决模型中的一些参数没有确定的情况,也就是为了解决诸如 p ( X ∣ θ ) p(X|\theta) p(Xθ) θ \theta θ不确定的问题。EM的整体思路主要分为四步:

  • 首先选定初始化参数 θ o l d \theta^{old} θold
  • **E(expectation)步骤:**计算后验概率 p ( Z ∣ X , θ o l d ) p(Z|X,\theta^{old}) p(ZX,θold)
  • **M(maximization)步骤:**求解优化问题来计算 θ n e w \theta^{new} θnew
    • KaTeX parse error: Undefined control sequence: \Q at position 26: …w} = \arg \max \̲Q̲(\theta, \theta…
    • KaTeX parse error: Undefined control sequence: \Q at position 1: \̲Q̲(\theta, \theta…
  • 检查是否收敛,如果不收敛重新回到E步骤。

3.1 用EM解决GMM问题

首先我们知道先验概率有 p ( z ) = Π k = 1 K π n z k p(z) = \Pi_{k = 1}^K\pi_n^{z_k} p(z)=Πk=1Kπnzk

以及 p ( x ∣ z ) = Π k = 1 K N ( x ∣ μ k , Σ k ) z k p(x|z) = \Pi_{k = 1}^KN(x|\mu_k, \Sigma_k)^{z_k} p(xz)=Πk=1KN(xμk,Σk)zk

我们就可以计算出联合分布 p ( X , Z ∣ μ , Σ , π ) = Π n = 1 N Π k = 1 K N ( x n ∣ μ k , Σ k ) z n k p(X, Z|\mu, \Sigma, \pi) = \Pi_{n = 1}^N \Pi_{k = 1}^KN(x_n|\mu_k, \Sigma_k)^{z_{nk}} p(X,Zμ,Σ,π)=Πn=1NΠk=1KN(xnμk,Σk)znk

迎合一下EM算法,取一下对数 ln ⁡ p ( X , Z ∣ μ , Σ , π ) = ∑ n = 1 N ∑ k = 1 K z n k { ln ⁡ π k + ln ⁡ N ( x n ∣ μ k , Σ k ) } \ln p(X, Z|\mu, \Sigma, \pi) = \sum_{n = 1}^N \sum_{k = 1}^Kz_{nk}\{\ln \pi_k + \ln N(x_n|\mu_k, \Sigma_k)\} lnp(X,Zμ,Σ,π)=n=1Nk=1Kznk{lnπk+lnN(xnμk,Σk)}

我们要求的是KaTeX parse error: Undefined control sequence: \Q at position 1: \̲Q̲(\theta, \theta…,那我们就要在对数结果的基础上求一下期望。我们注意到,在 ln ⁡ p ( X , Z ∣ μ , Σ , π ) \ln p(X, Z|\mu, \Sigma, \pi) lnp(X,Zμ,Σ,π)中,后面大括号里面的东西都和 z z z没有关系,所以:

E z [ ln ⁡ p ( X , Z ∣ μ , Σ , π ) ] = ∑ n = 1 N ∑ k = 1 K E [ z n k ] { ln ⁡ π k + ln ⁡ N ( x n ∣ μ k , Σ k ) } E_z[\ln p(X, Z|\mu, \Sigma, \pi)] = \sum_{n = 1}^N \sum_{k = 1}^KE[z_{nk}]\{\ln \pi_k + \ln N(x_n|\mu_k, \Sigma_k)\} Ez[lnp(X,Zμ,Σ,π)]=n=1Nk=1KE[znk]{lnπk+lnN(xnμk,Σk)}

而我们的 z n k z_{nk} znk只有等于 0 0 0和等于 1 1 1两种情况,我们再看一下我们之前所计算的后验概率:

γ ( z k ) ≡ p ( z k = 1 ∣ x ) = p ( z k = 1 ) p ( x ∣ z k = 1 ) Σ j = 1 K p ( x ∣ z j = 1 ) p ( z j = 1 ) = π k N ( x n ∣ μ k , Σ k ) ∑ j = 1 K π j N ( x n ∣ μ j , Σ j ) \gamma(z_k) \equiv p(z_k = 1 | x) = \frac{p(z_k = 1)p(x|z_k = 1)}{\Sigma_{j = 1}^Kp(x|z_j = 1)p(z_j = 1)} = \frac{\pi_kN(x_n|\mu_k, \Sigma_k)}{\sum_{j = 1}^K \pi_jN(x_n|\mu_j, \Sigma_j)} γ(zk)p(zk=1∣x)=Σj=1Kp(xzj=1)p(zj=1)p(zk=1)p(xzk=1)=j=1KπjN(xnμj,Σj)πkN(xnμk,Σk)

所以实际上 E [ z n k ] = 0 ∗ p ( z n k = 0 ∣ x n , μ k , Σ k , π k ) + 1 ∗ p ( z n k = 1 ∣ x n , μ k , Σ k , π k ) = γ ( z n k ) E[z_{nk}] = 0 * p(z_{nk} = 0|x_n, \mu_k, \Sigma_k, \pi_k) + 1 * p(z_{nk} = 1|x_n, \mu_k, \Sigma_k, \pi_k) = \gamma(z_{nk}) E[znk]=0p(znk=0∣xn,μk,Σk,πk)+1p(znk=1∣xn,μk,Σk,πk)=γ(znk)

我们最后的KaTeX parse error: Undefined control sequence: \Q at position 1: \̲Q̲函数就是 Q = E z [ ln ⁡ p ( X , Z ∣ μ , Σ , π ) ] = ∑ n = 1 N ∑ k = 1 K γ ( z n k ) { ln ⁡ π k + ln ⁡ N ( x n ∣ μ k , Σ k ) } Q = E_z[\ln p(X, Z|\mu, \Sigma, \pi)] = \sum_{n = 1}^N \sum_{k = 1}^K\gamma(z_{nk})\{\ln \pi_k + \ln N(x_n|\mu_k, \Sigma_k)\} Q=Ez[lnp(X,Zμ,Σ,π)]=n=1Nk=1Kγ(znk){lnπk+lnN(xnμk,Σk)}

解出来的结果和直接求是一样的:

  • μ k n e w = 1 N k ∑ n = 1 N γ ( z n k ) x n \mu_k^{new} = \frac{1}{N_k}\sum_{n = 1}^N\gamma(z_{nk})x_n μknew=Nk1n=1Nγ(znk)xn
  • Σ k n e w = 1 N k ∑ n = 1 N γ ( z n k ) ( x n − μ k ) ( x n − μ k ) T \Sigma_k^{new} = \frac{1}{N_k}\sum_{n = 1}^N\gamma(z_{nk})(x_n - \mu_k)(x_n - \mu_k)^T Σknew=Nk1n=1Nγ(znk)(xnμk)(xnμk)T
  • π k n e w = N k N \pi_k^{new} = \frac{N_k}{N} πknew=NNk

3.2 K-Means再认识

K-Means实际上就是一种特殊的GMM!

  • GMM中的 γ ( z n k ) \gamma(z_{nk}) γ(znk)实际上就是K-Means中的 r n k r_{nk} rnk
  • K-Means就是 Σ k = 0 \Sigma_k = 0 Σk=0的GMM

证明一下:

我们有 γ ( z k ) ≡ p ( z k = 1 ∣ x ) = p ( z k = 1 ) p ( x ∣ z k = 1 ) Σ j = 1 K p ( x ∣ z j = 1 ) p ( z j = 1 ) = π k N ( x n ∣ μ k , Σ k ) ∑ j = 1 K π j N ( x n ∣ μ j , Σ j ) \gamma(z_k) \equiv p(z_k = 1 | x) = \frac{p(z_k = 1)p(x|z_k = 1)}{\Sigma_{j = 1}^Kp(x|z_j = 1)p(z_j = 1)} = \frac{\pi_kN(x_n|\mu_k, \Sigma_k)}{\sum_{j = 1}^K \pi_jN(x_n|\mu_j, \Sigma_j)} γ(zk)p(zk=1∣x)=Σj=1Kp(xzj=1)p(zj=1)p(zk=1)p(xzk=1)=j=1KπjN(xnμj,Σj)πkN(xnμk,Σk)

在K-Means中,我们认为它的分布都是圆形的,也就是各个方向都是相等的,即 Σ k = ϵ I \Sigma_k = \epsilon I Σk=ϵI

也就是说 p ( x ∣ μ k , Σ k ) = 1 ( 2 π ϵ ) 1 / 2 e x p { − 1 2 ϵ ∣ ∣ x − μ k ∣ ∣ 2 } p(x|\mu_k, \Sigma_k) = \frac{1}{(2\pi\epsilon)^{1/2}}exp\{-\frac{1}{2\epsilon}||x - \mu_k||^2\} p(xμk,Σk)=(2πϵ)1/21exp{2ϵ1∣∣xμk2}

稍微结合一下,就会有在K-Means情况下:

γ ( z n k ) = π k e x p { − ∣ ∣ x n − μ k ∣ ∣ 2 / 2 ϵ } ∑ j π j e x p { − ∣ ∣ x n − μ j ∣ ∣ 2 / 2 ϵ } \gamma(z_{nk}) = \frac{\pi_kexp\{-||x_n - \mu_k||^2 / 2\epsilon\}}{\sum_j\pi_jexp\{-||x_n - \mu_j||^2 / 2\epsilon\}} γ(znk)=jπjexp{∣∣xnμj2/2ϵ}πkexp{∣∣xnμk2/2ϵ}

image-20230830155919908

可以看到,exp函数的系数越大,就下降的越快,而 ϵ \epsilon ϵ又十分接近 0 0 0,因此系数应该是无限大的,也就是说这个函数下降的贼快,不是 0 0 0就是无穷大。那么我们用 j ∗ j* j来表示接近的类。只有当 j = j ∗   a n d   k = j ∗ j = j* \ and\ k = j* j=j and k=j是,才为 1 1 1。因此,这个函数就坍塌为了 r n k r_{nk} rnk

因此带入KaTeX parse error: Undefined control sequence: \Q at position 1: \̲Q̲函数中,得到: Q = E z [ ln ⁡ p ( X , Z ∣ μ , Σ , π ) ] = ∑ n = 1 N ∑ k = 1 K r n k { ln ⁡ π k + ln ⁡ N ( x n ∣ μ k , Σ k ) } Q = E_z[\ln p(X, Z|\mu, \Sigma, \pi)] = \sum_{n = 1}^N \sum_{k = 1}^Kr_{nk}\{\ln \pi_k + \ln N(x_n|\mu_k, \Sigma_k)\} Q=Ez[lnp(X,Zμ,Σ,π)]=n=1Nk=1Krnk{lnπk+lnN(xnμk,Σk)}

又因为我们有 Σ k = ϵ I , ϵ → 0 \Sigma_k = \epsilon I,\epsilon \rightarrow 0 Σk=ϵI,ϵ0

于是就变成了 Q = E z [ ln ⁡ p ( X , Z ∣ μ , Σ , π ) ] = − 1 2 ∑ n = 1 N ∑ k = 1 K r n k ∣ ∣ x n − μ k ∣ ∣ 2 + c o n s t Q = E_z[\ln p(X, Z|\mu, \Sigma, \pi)] = -\frac{1}{2}\sum_{n = 1}^N \sum_{k = 1}^Kr_{nk}||x_n - \mu_k||^2 + const Q=Ez[lnp(X,Zμ,Σ,π)]=21n=1Nk=1Krnk∣∣xnμk2+const

里面的常数就是 π k \pi_k πk乘出来的一坨,没啥用。这样的话实际上就和我们学习K-Means中的 J J J函数长的一样啦。证明完毕。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值