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
如果你用的Python环境比较乱(比如我有段时间同时装了好几个科学计算发行版),建议新建一个虚拟环境来跑这个实验。别嫌麻烦,后面调参数时就知道干净环境有多重要了。

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 本章知识体系

下面这张图可以帮你把刚才的操作串起来:

Leiden聚类快速上手流程 步骤1 加载图数据 步骤2 选择分区类型 步骤3 执行聚类 步骤4 分析聚类结果 调优反馈:不满意就调整参数 内置 / 文件 / 数据库加载 默认:ModularityVertexPartition 默认参数:分辨率1.0,随机种子0

3.9 一个小的避坑指南

你可能会遇到下面几个问题,都是我或者身边同事踩过的坑:

  • 装了leidenalg但导入报错:检查igraph版本是否匹配。简单方法:pip show leidenalg igraph 看看版本号,如果不是最新就升级。
  • 结果每次都不相同:Leiden算法有随机性。默认情况下seed参数是0,但不同机器或不同igraph版本可能表现不同。你想复现结果的话,显式设置种子:
partition = leidenalg.find_partition(
    graph, 
    leidenalg.ModularityVertexPartition,
    seed=42  # 固定随机种子
)
  • 模块度是负的:嗯,这个不太常见。通常是你加载的图本身就不具有明显的社区结构。比如随机图,或者全连接图。换个数据集试试就好了。
这一章你学会了三件事:怎么加载Karate Club数据、怎么跑默认Leiden聚类、怎么解读输出结果。后面所有参数调试都建立在这个基础上。别小看这一小步——你已经在用工业级的社区发现算法了。