基于最小生成树的聚类

算法: 基于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()

以上代码合在一起就是一个完整的代码(可以运行)

本文所演示的数据集已经放在文章顶部

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值