第14章 聚类方法
习题14.1
试写出分裂聚类算法,自上而下地对数据进行聚类,并给出其算法复杂度。
解答:
解答思路:
- 给出一般聚类方法概述
- 给出分裂聚类的定义
- 给出分裂聚类预先确定的要素
- 写出分裂聚类算法,并计算复杂度
- 自编程实现分裂聚类算法
解答步骤:
第1步:一般聚类方法概述
根据书中第14章的聚类方法介绍:
聚类是针对给定的样本,依据它们的特征的相似度或距离,将其归并到若干个“类”或“簇”的数据分析问题。一个类是给定样本集合的一个子集。直观上,相似的样本聚集在相同的类,不相似的样本分散在不同的类。常用的聚类算法包括层次聚类和
均值聚类。层次聚类又分为聚合(自下而上)和分裂(自上而下)两种方法。
第2步:分裂聚类的定义
根据书中第14章的分裂聚类介绍:
分裂法开始将所有样本分到一个类,之后将已有类中相距最远的样本分到两个新的类,重复此操作直到满足停止条件,得到层次化的类别。
第3步:分裂聚类预先确定的要素
分裂聚类的具体过程如下:对于给定的样本集合,开始将所有样本分到一个类,然后按照一定分裂方法,例如类中距离最大,将最满足规则条件的样本分到两个新的类;如此反复进行,每次减少剩余未分类的样本,直到满足停止条件,如所有样本都分到了对应的类中。
由此可知,分裂聚类需要预先确定下面三个要素:
(1)选择要分裂的类方法;
(2)分裂类的方法;
(3)停止条件。
根据这些要素的不同组合,就可以构成不同的分裂聚类方法。选择要分裂的类的方法可以是选择最大直径的类、样本最多的类、最大均值的类、最大SSE的类。分裂类的方法可以是使用贪心算法选择新类中心、K-means算法、Ward方法。停止条件可以是每个类包含一个样本、类的个数达到阈值。
第4步:写出分裂聚类算法,并计算复杂度
分裂聚类算法
输入:
输出:满足设定的样本类别数的样本集合的一个层次化聚类。
(1)构造1个类,该类包含全部样本。
(2)计算
(3)分裂类中距离最大的两个样本,将其分到两个类,并设置为各自的类中心。
(4)计算未分裂的样本与目前各个类中心的距离,分裂类中距离最大的样本作为新的类中心,构造一个新类。
(5)如果类的个数满足设定的样本类别数
(6)根据当前的类中心,按照最近邻的原则对整个数据集进行分类。
计算复杂度:
- 时间复杂度为
:整个算法计算过程中需要计算两两样本之间的复杂度,设 是样本的维度,总体样本为 个,则时间复杂度为 ;设定的样本类别数为 ,则需要重复 次,故时间复杂度为 。 - 空间复杂度为
:需要一个 的矩阵保存两两样本间的距离。
第4步:自编程实现分裂聚类算法
import numpy as np
class DivisiveClustering:
def __init__(self, num_class):
# 聚类类别个数
self.num_class = num_class
# 聚类数据集
self.cluster_data = []
if num_class > 1:
self.cluster_data = [[] for _ in range(num_class)]
def fit(self, data):
"""
:param data: 数据集
"""
num_sample = data.shape[0]
if self.num_class == 1:
# 如果只设定了一类,将所有数据放入到该类中
for d in data:
self.cluster_data.append(d)
else:
# (1) 构造1个类,该类包含全部样本
# 初始化类中心
class_center = []
# (2) 计算n个样本两两之间的欧氏距离
distance = np.zeros((num_sample, num_sample))
for i in range(num_sample):
for j in range(i + 1, num_sample):
distance[j, i] = distance[i, j] = np.linalg.norm(data[i, :] - data[j, :],
ord=2)
# (3) 分裂距离最大的两个样本,并设置为各自的类中心
index = np.where(np.max(distance) == distance)
class_1 = index[1][0]
class_2 = index[1][1]
# 记录已经分裂完成的样本
finished_data = [class_1, class_2]
class_center.append(data[class_1, :])
class_center.append(data[class_2, :])
num_class_temp = 2
# (5) 判断类的个数是否满足设定的样本类别数
while num_class_temp != self.num_class:
# (4.1) 计算未分裂的样本与目前各个类中心的距离
data2class_distance = np.zeros((num_sample, 1))
for i in range(num_sample):
# 计算样本到各类中心的距离总和
data2class_sum = 0
for j, center_data in enumerate(class_center):
if i not in finished_data:
data2class_sum += np.linalg.norm(data[i, :] - center_data)
data2class_distance[i] = data2class_sum
# (4.2) 分裂类间距离最大的样本作为新的类中心,构造一个新类
class_new_index = np.argmax(data2class_distance)
num_class_temp += 1
finished_data.append(class_new_index)
# 添加到类中心集合中
class_center.append(data[class_new_index, :])
# 根据当前的类中心,按照最近邻的原则对整个数据集进行分类
for i in range(num_sample):
data2class_distance = []
for j, center_data in enumerate(class_center):
# 计算每个样本到类中心的距离
data2class_distance.append(np.linalg.norm(data[i, :] - center_data))
# 将样本划分到最近的中心的类中
label = np.argmin(data2class_distance)
self.cluster_data[label].append(data[i, :])# 使用书中例14.2的样本数据集
dataset = np.array([[0, 2],
[0, 0],
[1, 0],
[5, 0],
[5, 2]])
num_class = 2
divi_cluster = DivisiveClustering(num_class=num_class)
divi_cluster.fit(dataset)
print("分类数:", num_class)
for i in range(num_class):
print(f"class_{i}:", divi_cluster.cluster_data[i])分类数: 2
class_0: [array([0, 0]), array([1, 0]), array([5, 0])]
class_1: [array([0, 2]), array([5, 2])]
习题14.2
证明类或簇的四个定义中,第一个定义可推出其他三个定义。
解答:
解答思路:
- 给出定义14.5
- 给出定义14.6,并由定义14.5推导定义14.6
- 给出定义14.7,并由定义14.5推导定义14.7
- 给出定义14.8,并由定义14.5推导定义14.8
解答步骤:
第1步:定义14.5
根据书中第14.1.2节的定义14.5:
用
表示类或簇,用 表示类中的样本, 表示 中样本的个数,用 表示样本 与样本 之间的距离。 定义14.5 设
为给定的正数,若集合 中任意两个样本 ,有 则称
为一个类或簇。
第2步:由定义14.5推导定义14.6
证明:
根据书中第14.1.2节的定义14.6:
定义14.6 设
为给定的正数,若对集合 中任意样本 ,一定存在 中另一个样本 ,使得 则称
为一个类或簇。
由定义14.5可知,
则集合
定义14.6得证。
第3步:由定义14.5推导定义14.7
证明:
根据书中第14.1.2节的定义14.7:
定义14.7 设
为给定的正数,若对集合 中任意一个样本 , 中的另一个样本$ x_j$满足 其中
为G中样本的个数,则称G为一个类或簇。
将集合
所以
定义14.7得证。
第4步:由定义14.5推导定义14.8
证明:
根据书中第14.1.2节的定义14.8:
定义14.8 设
和 为给定的两个正数,如果集合 中任意两个样本 的距离 满足 则称
为一个类或簇。
根据定义14.5可知:
所以
定义14.8得证。
习题14.3
证明式(14.21)成立,即
解答:
解答思路:
- 给出书中公式(14.21)
- 给出可区分球到不可区分盒子的分配策略,得到指数的生成函数
- 利用指数生成函数进行二项式展开,推导并证明公式
解答步骤:
第1步:书中公式(14.21)
根据书中第14.3.2节的描述:
均值聚类就是求解最优化问题: 相似的样本被聚到同类中,损失函数值最小,这个目标函数的最优化能达到聚类的目的。但是,这是一个组合优化问题,
个样本分到 类,所有可能分法的数目是: 这个数字是指数级的。
第2步:给出可区分球到不可区分盒子的分配策略
以下示例来自于《应用组合数学(第2版)》第216页5.5.3节:
的定义是把 个可区分球分配到 个可区分盒子里,其每一个盒子不为空时的方法数量。 首先,考虑把 个可区分球放入标有标签 的可区分盒子里,且每一个盒子都不为空的方法数量 的问题,注意 确定把
个可区分球放入 个不为空的不可区分盒子的分配,然后再标记(排序)这些盒子,接下来计算 。假设球 放入到盒子 中,可以通过给出序列 编码把球放入可区分盒子里的分配,这是 集合 的一个 排列,且 集合中的每一个标签 至少使用一次,因此, 是这一排列的数量,且对于固定的 , 的指数生成函数由下式给出: 其中
是 的展开式中 的系数。
根据《应用组合数学(第2版)》第213页指数生成函数定义:
记
是 集合的 排序的数量,固定 ,则 的普通生成函数由下式给出: 结合从
集合中取 个元素的数量 ,则有下面的表达式: 通过二项式展开可以化简为
,则有: 根据上式可重写为
其中
是 的展开式中 的系数。
如果是任意序列,则一序列的指数生成函数是
说明:
已知,
将第
其中
第3步:进行二项式展开推导公式
《应用组合数学(第2版)》第216页5.5.3节:
根据二项式展开(定理2.7),有
用
取代 ,得到 由于
是 的展开式中 的系数,可得 结合
,可得
将上述公式的
习题14.4
比较
解答:
解答思路:
- 给出
均值聚类算法 - 给出高斯混合模型参数估计的EM算法
- 写出两者的相同点
- 写出两者的不同点
解答步骤:
第1步:
根据书中第14.3.3节的
均值聚类的算法是一个迭代的过程,每次迭代包括两个步骤,首先选择 个类的中心,将样本逐个指派到与其最近的中心的类中,得到一个聚类结果;然后更新每个类的样本的均值,作为类的新的中心;重复以上步骤,直到收敛为止。具体过程如下: 首先,对于给定的中心值 ,求一个划分 ,使得目标函数极小化: 就是说在类中心确定的情况下,将每个样本分到一个类中,使样本和其所属类的中心之间的距离总和最小。求解结果,将每个样本指派到与其最近的中心
的类 中。
然后,对给定的划分,再求各个类的中心 ,使得目标函数极小化: 就是说在划分确定的情况下,使样本和其所属类的中心之间的距离总和最小。求解结果,对于每个包含
个样本的类 ,更新其均值 : 重复以上两个步骤,直到划分不再改变,得到聚类结果。
第2步:高斯混合模型参数估计的EM算法
根据书中第9章的定义9.2的高斯混合模型:
定义9.2(高斯混合模型) 高斯混合模型是指具有如下形式的概率分布模型:
其中,
是系数, , ; 是高斯分布密度,
根据书中第9.3.2节的高斯混合模型参数估计的EM算法:
假设观测数据
由高斯混合模型生成, 其中,
。 1.明确隐变量,写出完全数据的对数似然函数
可定义隐变量如下:
是0-1随机变量。
完全数据的对数似然函数为2.EM算法的E步:依据当前模型参数,计算分模型
对观测数据 的响应度 3.EM算法的M步:计算新一轮迭代的模型参数
重复以上计算,直至对数似然函数值不再有明显的变化为止。
第3步:两者的相同点
- 两者求解的步骤相似:
均值聚类算法和高斯混合模型的EM算法的求解方式都是迭代求解, 均值聚类算法的求解中的E步是将每个样本分配到距离最近的类中心;M步是根据分配后的样本更新各类的均值 - 两者都需要提前指定
值,并且分类都受初始的 值影响 - 两者都有可能收敛到局部最优解
第4步:两者的不同点
- 高斯混合模型的EM算法可以看作
均值聚类算法的软扩展(Soft extension): 均值聚类算法中每一个样本属于 个类别中的某一个类别是确定性的,高斯混合模型的EM算法中每一个样本属于某一类是由 个高斯分布分模型按照某一概率分布表示的; - 待估计的参数不同,换言之,即损失函数不同。
均值聚类算法中需要更新的参数是各类的均值 ,高斯混合模型的EM算法中需要更新的参数是先验 、均值 、方差 。
参考文献
【1】Fred S. Roberts, Barry Tesman, 冯速(译).应用组合数学(原书第2版)[M]. 2007(1):216
