一、概念
聚类是将数据集中的样本划分为若干个不相交的子集,每个子集称为一个簇。同一簇中的样本尽可能相似,不同簇中的样本尽可能不同。
二、目标与用途
1. 目标
- 使得簇内的样本之间具有较高的相似度,而簇间的样本具有较低的相似度。
- 通常使用某种距离度量来衡量样本之间的相似性,常见的距离度量有欧氏距离、曼哈顿距离等。
2. 用途
- 数据探索:帮助理解数据的分布和结构。
- 图像分割、文本分类等领域:可以将相似的图像区域或文本归为一类。
- 作为其他机器学习任务的预处理步骤:例如在分类任务中,可以先对数据进行聚类,然后对每个簇分别进行分类,提高分类的准确性。
三、常见聚类算法
1. K 均值(K-Means)算法
- 算法步骤:
- 随机选择 K 个样本作为初始聚类中心。
- 对于每个样本,计算它到每个聚类中心的距离,将其分配到距离最近的聚类中心所在的簇。
- 对于每个簇,重新计算其聚类中心,即该簇中所有样本的均值。
- 重复步骤 2 和 3,直到聚类中心不再变化或达到最大迭代次数。
- 特点:简单、快速,适用于处理大规模数据,但需要预先指定簇的个数 K,且对初始聚类中心敏感。
2. 层次聚类算法
- 算法分为凝聚层次聚类和分裂层次聚类两种。
- 凝聚层次聚类:从每个样本作为一个单独的簇开始,逐步合并最相似的簇,直到满足某种停止条件。
- 分裂层次聚类:从所有样本作为一个簇开始,逐步分裂成更小的簇,直到满足停止条件。
- 特点:可以得到不同层次的聚类结果,便于观察数据的层次结构,但计算复杂度较高。
相似度计算
- 层次聚类使用欧式距离来计算不同类别数据点间的距离(相似度)。
四、计算距离
五、评估指标
1. 内部指标
- 常用的内部指标有误差平方和(SSE)等。SSE 是指每个样本到其所属簇中心的距离之和,SSE 越小,说明聚类效果越好。
2. 外部指标
- 当有外部的类别标注信息时,可以使用外部指标来评估聚类结果。例如,兰德指数(Rand Index)衡量了聚类结果与真实类别标注之间的一致性。
六、python实现
import queue
import math
import copy
import numpy as np
import matplotlib.pyplot as plt
class clusterNode:
def __init__(self, value, id=[], left=None, right=None, distance=-1, count=-1, check=0):
'''
value: 该节点的数值,合并节点时等于原来节点值的平均值
id:节点的id,包含该节点下的所有单个元素
left和right:合并得到该节点的两个子节点
distance:两个子节点的距离
count:该节点所包含的单个元素个数
check:标识符,用于遍历时记录该节点是否被遍历过
'''
self.value = value
self.id = id
self.left = left
self.right = right
self.distance = distance
self.count = count
self.check = check
def show(self):
# 显示节点相关属性
print(self.value, ' ', self.left.id if self.left != None else None, ' ', \
self.right.id if self.right != None else None, ' ', self.distance, ' ', self.count)
class hcluster:
def distance(self, x, y):
# 计算两个节点的距离,可以换成别的距离
return math.sqrt(pow((x.value - y.value), 2))
def minDist(self, dataset):
# 计算所有节点中距离最小的节点对
mindist = 1000
for i in range(len(dataset) - 1):
if dataset[i].check == 1:
# 略过合并过的节点
continue
for j in range(i + 1, len(dataset)):
if dataset[j].check == 1:
continue
dist = self.distance(dataset[i], dataset[j])
if dist < mindist:
mindist = dist
x, y = i, j
return mindist, x, y
# 返回最小距离、距离最小的两个节点的索引
def fit(self, data):
dataset = [clusterNode(value=item, id=[(chr(ord('a') + i))], count=1) for i, item in enumerate(data)]
# 将输入的数据元素转化成节点,并存入节点的列表
length = len(dataset)
Backup = copy.deepcopy(dataset)
# 备份数据
while (True):
mindist, x, y = self.minDist(dataset)
dataset[x].check = 1
dataset[y].check = 1
tmpid = copy.deepcopy(dataset[x].id)
tmpid.extend(dataset[y].id)
dataset.append(clusterNode(value=(dataset[x].value + dataset[y].value) / 2, id=tmpid, \
left=dataset[x], right=dataset[y], distance=mindist,
count=dataset[x].count + dataset[y].count))
# 生成新节点
if len(tmpid) == length:
# 当新生成的节点已经包含所有元素时,退出循环,完成聚类
break
for item in dataset:
item.show()
return dataset
def show(self, dataset, num):
plt.figure(1)
showqueue = queue.Queue()
# 存放节点信息的队列
showqueue.put(dataset[len(dataset) - 1])
# 存入根节点
showqueue.put(num)
# 存入根节点的中心横坐标
while not showqueue.empty():
index = showqueue.get()
# 当前绘制的节点
i = showqueue.get()
# 当前绘制节点中心的横坐标
left = i - (index.count) / 2
right = i + (index.count) / 2
if index.left != None:
x = [left, right]
y = [index.distance, index.distance]
plt.plot(x, y)
x = [left, left]
y = [index.distance, index.left.distance]
plt.plot(x, y)
showqueue.put(index.left)
showqueue.put(left)
if index.right != None:
x = [right, right]
y = [index.distance, index.right.distance]
plt.plot(x, y)
showqueue.put(index.right)
showqueue.put(right)
plt.show()
def setData(num):
# 生成num个随机数据
Data = list(np.random.randint(1, 100, size=num))
return Data
if __name__ == '__main__':
num = 20
dataset = setData(num)
h = hcluster()
resultset = h.fit(dataset)
h.show(resultset, num)
- 运行结果
总之,聚类是机器学习中一种重要的无监督学习方法,在数据挖掘、模式识别等领域有着广泛的应用。