一种无监督学习方法,通过无标签的训练样本,学习数据潜在规律,将数据集中的样本划分为多个不相交的子集(簇 cluster),每个子集可能会对应一个潜在的概念,为进一步数据分析提供基础。
聚类是个模糊且庞大的算法,几个常见的聚类模型:
- 质心聚类(原型聚类):每个聚类由一个中心向量表示,可以不属于数据集。
- 密度聚类:聚类被定义为密度高于数据集其余部分的区域,稀疏区域中的对象通常被认为是噪声和边界点。
- 分布模型聚类:被定义为最有可能属于同一分布的对象。这种方法可以捕获属性之间的相关性和依赖性,但对于许多真实数据集,可能没有简明定义的数学模型.
- 连通性聚类:根据一个样本附近样本的相似性,将他们连接起来,所有连在一起的样本被认为是一个簇
算法
k-means
是一种质心聚类。给定数据集D,需要k个原型(均值向量)μ={μ1,…,μk},来划分为 k 个簇C={C1,…Ck}。
目标是:minμ∑in∑x∈Ci∣∣x−μj∣∣2,是个非凸NP问题,只能通过迭代下降近似得到一个局部最优解
优化过程伪代码完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| dataset:list k:int
def distance(a:vector,b:vector)->scalar:...
rand_idx = random.sample(range(len(dataset)), k) prototypes = [dataset[idx] for idx in rand_idx]
while True: clusters: list[list[np.ndarray]] = [[] for _ in range(k)] for sample in dataset: d = [distance(sample, prototypes[j]) for j in range(k)] idx = d.index(min(d)) clusters[idx].append(sample) updated = False for i in range(k): prototype: np.ndarray = np.average(clusters[i], axis=0) if all(prototype != prototypes[i]): updated = True prototypes[i] = prototype print(prototypes) if not updated: return prototypes
|
缺点
- 对原型的初始化比较敏感,且只能得到局部最优,所以通常需要使用多个不同的初始化原型,选取效果最好的一个。
- 根据与原型的距离,根据距离来讲数据分为球状类的簇,这导致对于非凸的数据效果不好。
变种
- kmeans++:优化了初始原型的选择,尽量选择相距较远的样本点作为初始原型,能一定程度上避免陷入局部最优。
- k-medians 将原型更新为平均数改为更新为中位数,k-medoids 将原型更新改为选择数据集中的样本。
- fuzzy c-means: 不再明确将样本划分为某个簇,而是通过隶属度来表示属于某个簇的程度。
高斯混合聚类
是一种分布模型聚类。
多元高斯分布的概率密度函数(模型):
p(x∣μ,Σ)=(2π)2n∣Σ∣211e−21(x−μ)TΣ−1(x−μ)(1)
μ∈Rn是均值向量,Σ∈Rn×n是协方差矩阵。混合高斯分布(混合模型):
pM(x)=i∑kαi⋅p(x∣μi,Σi)(2)
后验分布,zi=j表示样本xi由第j个模型生成:
pM(zi=j∣xi)=∑l=1kαl⋅p(xi∣μl,Σl)αj⋅p(xi∣μi,Σi)(3)
显然我们无法直接极大似然,因为我们无法知道某个样本点属于哪个簇(子模型),需要以迭代的方式近似估计,通常使用 EM 算法。
使用极大对数似然估计参数值,
LL(D)=ln(i=1∏mPM(xi))=i=1∑nlnP(xi)=i=1∑nln(j=1∑kαj⋅p(xi∣μj,Σj))
求导置零
∂μj∂LL(D)i∑n∑lkαl⋅p(xi∣μl.Σl)αj⋅p(xi∣μj,Σj)(xi−μj)μj=∑i=1npM(zi=j∣xi)∑i=1npM(zi=j∣xi)xi=0=0(4)
即混合成分的均值可通过样本加权平均来估计。由∂Σi∂LL(D)=0得:
Σj=∑inpM(zi=j∣xi)∑inpM(zi=j∣xi)(xi−μj)(xi−μj)T(5)
对于 αj还需要满足约束aj≥0,∑jkαj=1,对拉格朗日形式LL+λ(∑j=1kαj−1)求导置0:
i=1∑n∑l=1kαl⋅p(xi∣μl.Σl)p(xi∣μj,Σj)=−λ
两别同乘以 αj:
i=1∑n∑l=1kαl⋅p(xi∣μl.Σl)αjp(xi∣μj,Σj)=−λαj
两边再对所有混合成分求和:
j=1∑ki=1∑n∑l=1kαl⋅p(xi∣μl.Σl)αjp(xi∣μj,Σj)i=1∑n∑l=1kαl⋅p(xi∣μl.Σl)∑j=1kαjp(xi∣μj,Σj)i=1∑n1n=−j=1∑kλαj=−λj=1∑kαj=−λ⋅1=−λ(6)
因此:
i=1∑n∑l=1kαl⋅p(xi∣μl.Σl)αjp(xi∣μj,Σj)ajaj=nαj=n1i=1∑n∑l=1kαl⋅p(xi∣μl.Σl)αjp(xi∣μj,Σj)=m1i∑npM(zi=j∣xi)(7)
此时可以使用 EM 算法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| n:int k:int dataset:list[vector]
models:list[tulple[float,vector[n],matrix[n,n]]]=[(rand,rand,rand)*k]
threshold:float = 0.001
pp(index:int,sample:vector,model:list)->float:... mu(index:int,dataset:list[vector])->vector:... sigma(index:int,dataset:list[vector])->matrix:... sigma(index:int,dataset:list[vector])->float:... while True: y:matrix[n,k] for i in range(n): for j in range(k): y[i,k] = pp(j,dataset[i],models) new_models = models for i in range(k): new_models[i] = (alpha(i,dataset),mu(i,dataset),sigma(i,dataset)) alpha[i] = if models-new_models<threshold: break else models = new_models
|
缺陷:
- 多次运行可能会产生不同的结果
- 对于许多真实数据集,可能没有简明定义的数学模型并不是服从高斯分布的
DBSCAN
一种密度聚类算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| dataset:list[vector] unvisited:list[vector] = dataset eps:float M:int clusters:list[vector] noise:list[vector]
get_near_samples(object:vector,dataset:list,eps:float)
while not unvisited.empty(): sample = unvisited[rand(len(unvisited))] unvisited.remove(sample) near_samples = get_near_samples(sample,dataset,eps) if len(near_samples) > M: cluster=[sample] for near_sample in near_samples: unvisited.remove(near_sample) cluster.append(near_sample) if len(get_near_samples(near_sample,dataset))>0: cluster+=get_near_samples(near_sample,dataset) clusters.append(cluster) else: noise.append(sample)
|
缺陷
- 由于它们期望某种密度下降来检测簇边界,在具有高斯分布(人工数据中的常见用例)的数据集上效果不好,因为聚类密度不断降低,无法有效的确定边界。
变体
- OPTICS:是DBSCAN的推广,无需为范围参数 ε 选择合适的值,并产生与连锁聚类相关的分层结果,但是仍然存在DBSCAN的缺陷
- Density-Link-Clustering: 结合了单链接聚类和 OPTICS 的思想,完全消除了 ε 参数,并通过使用 R 树索引提供了优于 OPTICS 的性能改进。
性能度量
聚类结果的评估与聚类本身一样困难。
两种方式:
- 外部评估:使用现有的 ground truth 分类进行比较,即使用带标签的数据。但是标签仅反应了数据一种可能的分区,并不意味着不存在不同甚至更好的聚类。
- 内部评估:通过簇内相似度、不同簇的相似度等特征来评估好坏。