3. 快速上手:加载图数据(Karate Club示例),运行默认参数聚类
3.1 为什么选Karate Club?
说白了,Zachary's Karate Club就是图聚类界的「Hello World」。一个美国大学空手道俱乐部的社交网络,34个人,78条边。俱乐部因为教练和主席闹掰了,分成了两派。这个真实分裂结果,正好拿来验证聚类算法靠不靠谱。
我个人习惯,学新算法头一件事就是拿这个数据集跑一遍。为什么?
- 图够小,跑起来快,调试方便
- 有 Ground Truth(真实分裂结果),能直观评估效果
- 结构不复杂,但社区边界清晰,非常适合初学者建立感觉
嗯,这里要注意一点:Karate Club虽然经典,但它只有两个真实社区。实际业务里的社区数多得多。不过拿来练手,它足够让你快速理解Leiden聚类的输出长什么样。
3.2 环境准备:你需要装哪些库?
运行这套例子,你只需要三个Python库。安装命令很简单:
pip install leidenalg igraph matplotlib
我遇到过有人卡在版本问题上。igraph和leidenalg的版本必须匹配。简单做法:全部升级到最新版。
pip install --upgrade leidenalg igraph matplotlib
3.3 加载Karate Club数据
igraph自带Karate Club数据集,一行代码就能加载。我个人喜欢把这一步单独写,便于后面换数据时只改这里。
import igraph as ig
# 加载内置的Karate Club图
graph = ig.Graph.Famous("Zachary")
print(f"节点数: {graph.vcount()}, 边数: {graph.ecount()}")
输出是这样的:
节点数: 34, 边数: 78
如果输出不一样,检查一下igraph版本。我曾经遇到过老版本没有"Zachary"这个内置图,升级就好了。
3.4 运行默认参数聚类
Leiden算法的默认参数设计得相当合理,大部分时候第一次跑就能得到不错的结果。直接看代码:
import leidenalg
# 运行Leiden聚类,全部使用默认参数
partition = leidenalg.find_partition(
graph,
leidenalg.ModularityVertexPartition
)
# 查看聚类结果
print(f"社区数量: {len(partition)}")
print(f"模块度: {partition.modularity}")
print(f"每个社区的成员数量: {[len(members) for members in partition]}")
跑完后,你会看到类似这样的输出:
社区数量: 4
模块度: 0.4188
每个社区的成员数量: [12, 4, 5, 13]
等等,我记得Karate Club真实分裂是两个社区,怎么默认参数跑出来4个?
别慌,这恰恰是Leiden算法的一个优点。它发现了更精细的子结构。这4个社区基本上是真实两派内部的进一步细分。你可以理解为:大社区里还有小圈子。
3.5 查看每个社区的成员
光看数字不够,咱们得看看具体哪些人被分到了同一个社区:
for i, members in enumerate(partition):
print(f"社区 {i}: {members}")
输出示例:
社区 0: [8, 9, 13, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32]
社区 1: [1, 2, 3, 4, 5, 6, 7, 11, 12, 17, 21]
社区 2: [0, 10, 16, 19, 33]
社区 3: [11, 12]
注意,节点编号0到33对应着俱乐部成员。真实分裂中,节点0是教练,节点33是主席。仔细看——教练和主席被分在了不同社区,大体上与真实分裂一致。但社区3只有两个成员(11和12),说明它们可能处于两个大社区的边界位置。
3.6 可视化快速验证
代码跑完了,我想立刻看看图长什么样。写个简单的可视化:
import matplotlib.pyplot as plt
# 设置节点颜色
colors = partition.membership
ig.plot(
partition,
vertex_color=colors,
vertex_size=20,
bbox=(400, 400),
target="karate_club_default.png"
)
print("聚类结果已保存为 karate_club_default.png")
打开图片,你会看到节点被涂成了4种颜色,相同颜色的节点在图上基本聚集在一起。这验证了Leiden算法的基本能力——它确实能把密集连接的区域识别出来。
3.7 核心知识小结
这一趟跑下来,你其实已经掌握了Leiden聚类的核心流程:
| 步骤 | 关键操作 | 输出 |
|---|---|---|
| 1. 加载图 | igraph.Graph.Famous() 或从文件/网络加载 | igraph对象,包含节点和边 |
| 2. 实例化算法 | leidenalg.ModularityVertexPartition | 指定优化目标(默认用模块度) |
| 3. 运行聚类 | leidenalg.find_partition() | 分区对象,包含社区归属和模块度 |
| 4. 分析结果 | partition.modularity, len(partition), partition.membership | 模块度值、社区数、每个节点的社区ID |
3.8 本章知识体系
下面这张图可以帮你把刚才的操作串起来:
3.9 一个小的避坑指南
你可能会遇到下面几个问题,都是我或者身边同事踩过的坑:
- 装了leidenalg但导入报错:检查igraph版本是否匹配。简单方法:
pip show leidenalg igraph看看版本号,如果不是最新就升级。 - 结果每次都不相同:Leiden算法有随机性。默认情况下seed参数是0,但不同机器或不同igraph版本可能表现不同。你想复现结果的话,显式设置种子:
partition = leidenalg.find_partition(
graph,
leidenalg.ModularityVertexPartition,
seed=42 # 固定随机种子
)
- 模块度是负的:嗯,这个不太常见。通常是你加载的图本身就不具有明显的社区结构。比如随机图,或者全连接图。换个数据集试试就好了。