为何Leiden算法无法在Iris数据集上识别社区?
Leiden算法在Iris数据集上聚类失效的原因与解决思路
核心问题:图的构建逻辑不符合Leiden算法的适用场景
Leiden是社区检测算法,本质是在图中寻找局部连接紧密的子图(社区),它的设计前提是图是稀疏的、存在局部连接差异的。而你直接用全连接的距离/相关矩阵构建的是稠密图——每个样本节点和所有其他样本都有边,这种图没有“局部紧密区域”的概念,自然无法得到合理的社区划分。
另外,边权重的逻辑也完全搞反了:
- 距离矩阵的数值越大,代表样本越不相似,但Leiden算法默认边权重越大,节点越应该被划分到同一社区,相当于你把“不相似的样本”强行绑定,结果必然异常。
- 用
abs(1-np.corrcoef(X))构建的矩阵,相关度越高的样本边权重越小,同样和算法的权重期望相反。
修正方案:构建符合要求的稀疏图
1. 选择合适的图结构
推荐两种方式:
- k近邻图(k-NN Graph):每个样本只与最相似的k个样本建立连接(k一般选5-20,根据数据集调整),过滤掉不相似的样本连接,让图变得稀疏。
- epsilon邻域图:设定一个距离阈值,只保留距离小于阈值的边,同样实现稀疏化。
2. 转换边权重为正向相似度
把距离/相关关系转换为算法可识别的“相似度权重”:
- 距离转相似度:可以用
1 - 归一化后的距离,或者np.exp(-距离/阈值)(高斯核转换),让相似样本的边权重更大。 - 相关系数直接作为权重:用
np.corrcoef(X)的结果(相关度越高,权重越大),不需要做1-的转换。
修正后的代码示例
import numpy as np from sklearn import datasets import igraph as ig import leidenalg from sklearn.preprocessing import StandardScaler from sklearn.neighbors import kneighbors_graph from sklearn.metrics import adjusted_rand_score # 加载Iris数据集 iris = datasets.load_iris() X = iris.data y = iris.target # 数据标准化 scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # 构建k近邻图(k=10),用余弦距离计算 knn_graph = kneighbors_graph(X_scaled, n_neighbors=10, mode='distance', metric='cosine') # 转换为余弦相似度权重:1 - 余弦距离 adj_matrix = 1 - knn_graph.toarray() # 构建带权图,指定边权重为相似度值 graph = ig.Graph.Weighted_Adjacency(adj_matrix, mode='upper') # 调整分辨率参数,观察簇数量变化 for res in np.arange(0.5, 2.0, 0.1): partition = leidenalg.find_partition(graph, leidenalg.CPMVertexPartition, resolution_parameter=res, weights='weight') cluster_count = len(np.unique(partition.membership)) print(f"分辨率={res:.1f},簇数量={cluster_count}") # 评估聚类结果与真实标签的匹配度 best_partition = leidenalg.find_partition(graph, leidenalg.CPMVertexPartition, resolution_parameter=0.8, weights='weight') print(f"调整兰德指数(与真实标签):{adjusted_rand_score(y, best_partition.membership):.3f}")
额外说明
- 当图的结构正确后,调整分辨率参数才会得到合理的簇数量变化,而不是之前的极端情况。
- 可以尝试不同的k值(比如5、15)和相似度转换方式,找到最适合Iris数据集的参数。
内容的提问来源于stack exchange,提问作者Carles
相关产品推荐
相关产品推荐

