高斯混合模型(Guassian Mixed Model, GMM)也是一种常见的聚类算法,与K均值算法类似,同样使用了EM算法进行迭代计算。高斯混合模型假设每个簇的数据都是符合高斯分布的,当前数据呈现的分布就是各个簇的高斯分布叠加在一起的结果。
图5.6是一个数据分布的样例,如果只用一个高斯分布来拟合图中的数据,图中所有的椭圆即为高斯分布的二倍标准差所对应的椭圆。直观来说,图中的数据明显分为两簇,因此只用一个高斯分布来拟合是不太合理的,需要推广到用多个高斯分布的叠加来对数据进行拟合。
图5.7是用两个高斯分布的叠加来拟合得到的结果。这就引出了高斯混合模型,即用多个高斯分布函数的线性组合来对数据分布进行拟合。理论上,高斯混合模型可以拟合出任意类型的分布。
高斯混合模型的核心思想是什么?
说起高斯分布,大家都不陌生,通常身高、分数等都大致符合高斯分布。因此,当我们研究各类数据时,假设同一类的数据符合高斯分布,也是很简单自然的假设;当数据事实上有多个类,或者我们希望将数据划分为一些簇时,可以假设不同簇中的样本各自服从不同的高斯分布,由此得到的聚类算法称为高斯混合模型。
高斯混合模型的核心思想是,假设数据可以看作从多个高斯分布中生成出来的。在该假设下,每个单独的分模型都是标准高斯模型,其均值和方差是待估计的参数。此外,每个分模型都还有一个参数,可以理解为权重或生成数据的概率。高斯混合模型的公式为
高斯混合模型是一个生成式模型。可以这样理解数据的生成过程,假设一个最简单的情况,即只有两个一维标准高斯分布的分模型N(0,1)和N(5,1),其权重分别为0.7和0.3。那么,在生成第一个数据点时,先按照权重的比例,随机选择一个分布,比如选择第一个高斯分布,接着从N(0,1)中生成一个点,如-0.5,便是第一个数据点。在生成第二个数据点时,随机选择到第二个高斯分布N(5,1),生成了第二个点4.7。如此循环执行,便生成出了所有的数据点。
是如何迭代计算的?
然而,通常我们并不能直接得到高斯混合模型的参数,而是观察到了一系列数据点,给出一个类别的数量K后,希望求得最佳的K个高斯分模型。因此,高斯混合模型的计算,便成了最佳的均值,方差、参数的寻找,这类问题通常通过最大似然估计来求解。遗憾的是,此问题中直接使用最大似然估计,得到的是一个复杂的非凸函数,目标函数是和的对数,难以展开和对其求偏导。
在这种情况下,可以使用EM算法框架来求解该优化问题。EM算法是在最大化目标函数时,先固定一个变量使整体函数变为凸优化函数,求导得到最值,然后利用最优参数更新被固定的变量,进入下一个循环。具体到高斯混合模型的求解,EM算法的迭代过程如下。
首先,初始随机选择各参数的值,然后,重复下述两步,直到收敛。
(1)E步骤。根据当前的参数,计算每个点由某个分模型生成的概率。
(2)M步骤。使用E步骤估计出的概率,来改进每个分模型的均值方差和权重。
也就是说,我们并不知道最佳的K个高斯分布的各自3个参数,也不知道每个数据点究竟是哪个高斯分布生成的。所以每次循环时,先固定当前的高斯分布不变,获得每个数据点由各个高斯分布生成的概率。然后固定该生成概率不变,根据数据点和生成概率,获得一个组更佳的高斯分布。循环往复直到参数不再变化,或者变化非常小时,便得到了比较合理的一组高斯分布。
高斯混合模型与K均值算法的相同点是,他们都是用于聚类的算法;都需要指定K值;都是使用EM算法来求解;都往往只能收敛与局部最优。
而它相比于K均值算法的优点是,可以给出一个样本属于某类概率是多少;不仅仅可以用于聚类,还可以用于概率密度的估计;并且可以用于生成新的样本点。
示例代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.mixture import GaussianMixture
from sklearn.datasets import make_blobs
# 生成一些样本数据
np.random.seed(42)
X, _ = make_blobs(n_samples=300, centers=4, cluster_std=1.0, random_state=42)
# 使用高斯混合模型进行拟合
gmm = GaussianMixture(n_components=4, random_state=42)
gmm.fit(X)
# 预测每个样本所属的簇
labels = gmm.predict(X)
# 获取高斯混合模型的均值和协方差矩阵
means = gmm.means_
covariances = gmm.covariances_
# 绘制样本数据和簇中心
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', s=50, alpha=0.7)
plt.scatter(means[:, 0], means[:, 1], marker='X', c='red', s=200, label='Cluster Centers')
plt.title('Gaussian Mixture Model')
plt.legend()
plt.show()
这个例子中,我们使用make_blobs
函数生成一些聚类样本数据,然后使用GaussianMixture
类拟合这些数据。通过调整n_components
参数,你可以指定模型中的高斯分量数量。最后,我们绘制样本数据以及模型学到的簇中心。实际应用中,根据你的数据集和问题对代码进行调整。