算法: 基于MST的聚类算法
这是本人的第一篇csdn,经验不足,如果有什么问题欢迎提出。
输入:数据集 𝑋={𝑥1,𝑥2,…,𝑥𝑛},聚类个数 𝑘 输出:样本点类别编号
这个算法就是
1.构建两点的距离矩阵(可看做完全图)。(n*(n-1))/2条边
2.再根据kruskal算法生成最小生成树,
3.然后自己定义有k个类,在这个最小生成树中剪掉前k-1长的边,这样就有了k个类别。
如下图,这是根据kruskal生成的最小生成树。它本来是这个样子
剪掉图中那最长的3条边后,便有了4个类别。
这是设置聚类个数4后的聚类结果
1.先构建距离矩阵
#准备部分
import numpy as np
import matplotlib.pyplot as plt
# 读取数据
data = np.loadtxt(r"数据集\cth3.txt")
num_points = data.shape[0]
distance = np.zeros((num_points, num_points))
# 构建距离矩阵
for i in range(num_points):
for j in range(num_points):
distance[i, j] = np.linalg.norm(data[i] - data[j])
2.kruskal 算法
def kruskal(visit, nonvisit, distance, MST):
array_value = []
array_index = []
for i in range(len(visit)):
temp_value = []
temp_index = []
for j in range(len(nonvisit)):
temp_value.append(distance[visit[i]][nonvisit[j]])
temp_index.append(nonvisit[j])
min_value = min(temp_value)
min_index = nonvisit[temp_value.index(min_value)]
array_value.append(min_value)
array_index.append(min_index)
final_value = min(array_value)
visit_index = visit[array_value.index(final_value)]
final_index = array_index[array_value.index(final_value)]
visit.append(final_index)
nonvisit.remove(final_index)
MST[visit_index][final_index] = final_value
MST[final_index][visit_index] = final_value
return visit, nonvisit, MST
3.找到最长的边,返回得到它的端点
def find_max_edge(MST):
max_value = 0
max_edge = None
for i in range(len(MST)):
for j in range(i+1, len(MST)):
if MST[i][j] > max_value:
max_value = MST[i][j]
max_edge = (i, j)
return max_edge
4.深度优先搜索,在MST矩阵中不断连接,归类点。
def dfs(node, cluster, visited, MST):
for j in range(MST.shape[0]):
if MST[node][j] > 0 and j not in visited:
visited.add(j)
cluster.append(j)
dfs(j, cluster, visited, MST)
5.聚类函数
def cluster(k, MST):
labels = []
if k==1:
i = 2
visited = set([i])
cluster = [i]
dfs(i, cluster, visited, MST)
labels.append(cluster)
return labels
while len(labels) < k:
i, j = find_max_edge(MST)
MST[i][j] = 0 # 断开聚类中的最大边
MST[j][i] = 0
# 重新计算所有簇
labels = []
visited = set()
for node in range(MST.shape[0]):
if node not in visited:
cluster = [node]
visited.add(node)
dfs(node, cluster, visited, MST)
labels.append(cluster)
# 将剩余的点分配到最近的簇
remaining_points = set(range(MST.shape[0])) - set(sum(labels, []))
for point in remaining_points:
min_dist = float('inf')
min_cluster = None
for cluster in labels:
for node in cluster:
if distance[point][node] < min_dist:
min_dist = distance[point][node]
min_cluster = cluster
min_cluster.append(point)
return labels
6.正式部分,聚类可视化,k=4那里是调参的地方,自己根据需求调试。
# 正式部分
num_points = distance.shape[0]
MST = np.zeros((num_points, num_points))
visit = [0]
nonvisit = list(range(1, num_points))
for t in range(num_points - 1):
visit, nonvisit, MST = kruskal(visit, nonvisit, distance, MST)
k = 4 # 设定聚类数为4
cluster_labels = cluster(k, MST)
print(f"Clusters: {cluster_labels}")
# 绘制数据点和分类
plt.figure(figsize=(8, 6))
for cluster_idx, cluster in enumerate(cluster_labels):
cluster_data = data[cluster]
plt.scatter(cluster_data[:, 0], cluster_data[:, 1], label=f'Cluster {cluster_idx+1}')
# 绘制最小生成树的边
for i in range(num_points):
for j in range(i+1, num_points):
if MST[i][j] > 0:
x_values = [data[i, 0], data[j, 0]]
y_values = [data[i, 1], data[j, 1]]
plt.plot(x_values, y_values, color='g', alpha=0.5)
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Data Points with Clusters Visualization')
plt.legend()
plt.grid(True)
plt.show()
以上代码合在一起就是一个完整的代码(可以运行)
本文所演示的数据集已经放在文章顶部