这篇博客发出来后,我用 Rust 复现代码出现问题。为此,我对对照了 sklearn 的相关代码,反复比较了两天,发现一处 bug,把 += 误写成了 =,导致数据量大的时候完全无法聚类。这个debug过程让我仔细梳理的 AP 算法的计算过程,今天我对这篇博客做了大规模修改,以便能原样展现原论文思想。
这几天的工作给我的体会是,自己觉得看懂论文了,如果不亲自把代码写出来,对论文原理的理解还是非常肤浅。
1. 基本思路
AP 算法的灵感来自投票选举。我们看下面的故事:
辽阔的草原上居住一群人。为便于组织管理,他们想通过投票选举部落首领,把人群分成若干部落,每个部落有一个首领。
投票行为受两个因素影响:
- 个人支持度: 开始阶段,规则不允许投票给自己,因此,大家最初的投票意向是,把自己的一票投给最亲近的人,比如自己的老公,自己的儿子等。
- 民意支持度: 如果某个打算投票给自己的儿子,但是发现大家都不愿意投票给自己儿子,而自己的侄子支持率还挺高,于是他可能决定退而求其次,支持自己的侄子。
这个方法面临两个问题需要思考:
- 问题1:亲人竞争: 记得台湾地区选举领导人,有一年本来蓝营占优势,但是中间杀出个宋楚瑜,分散了蓝赢得选票,导致本来处于弱势的绿营占了上风。如果一个部落内,有两个人获得的支持度相近,如何决定谁最终胜出呢?有没有对聚类的效果造成负面影响?
- 问题2:选票分散: 如果某个部落内部,父亲投票给母亲、母亲投票给儿子,儿子投票给姐姐,姐姐投票给父亲,部落内每个人的票都不够多,会不会造成聚类失败?
2. 一个简单例子
提供一个简单例子,假设点分布在实数轴上,坐标分别为 :
A=1,B=2,C=3,D=5,E=6 A=1,B=2,C=3,D=5,E=6 A=1,B=2,C=3,D=5,E=6
2.1 相似度矩阵 s
用两个点之间的距离的负数作为两个点之间相似度:
| s(i \ k) | A | B | C | D | E |
|---|---|---|---|---|---|
| A | ? | -1.0 | -2.0 | -4.0 | -5.0 |
| B | -1.0 | ? | -1.0 | -3.0 | -4.0 |
| C | -2.0 | -1.0 | ? | -2.0 | -3.0 |
| D | -4.0 | -3.0 | -2.0 | ? | -1.0 |
| E | -5.0 | -4.0 | -3.0 | -1.0 | ? |
按照距离的负数计算相似度,导致相似度全部都是负数。不过没关系,只要能保证数值越大,相似度越高即可,至于数据的符号,初始阶段并不重要。
对角线 s(i,i)s(i,i)s(i,i) 表示自己与自己的相似度,AP算法建议选择上述矩阵中元素的最小值或者中位数。接下来我们选择最小值得到完整的相似度矩阵:
| s(i \ k) | A | B | C | D | E |
|---|---|---|---|---|---|
| A | -5.0 | -1.0 | -2.0 | -4.0 | -5.0 |
| B | -1.0 | -5.0 | -1.0 | -3.0 | -4.0 |
| C | -2.0 | -1.0 | -5.0 | -2.0 | -3.0 |
| D | -4.0 | -3.0 | -2.0 | -5.0 | -1.0 |
| E | -5.0 | -4.0 | -3.0 | -1.0 | -5.0 |
相似度矩阵可以这样理解,行 iii 代表选民,列 kkk 代表竞选人。因为 s(i,i)s(i,i)s(i,i) 选择了矩阵元素的最小值,这表示开始阶段,每个人都不希望自己被选举为领导人。接下来的过程,我们要说服某些优势候选人提升自己成为领导人的意愿,同时也要说服选民选择把票投给具备民意基础的优势候选人。
2.2 个人支持度矩阵 r
上面的相似度矩阵虽然在一定程度上反映了亲情关系,但是,不同行之间数据是不能进行比较的。例如,第1行第2列最大值是-1,意味着选民1会投票给2。但是第2行的最大值-1有两个,意味着选民2会投票给选民1和3。第2行的两个-1才相当于第一行的一个-1。因此,我们需要把相似度矩阵 sss 归一化,得到一个标准化的"个人支持度矩阵"。
归一化的方法,是每一行的每一个元素,都要与其他列最大的元素做差,计算自己在选民 i 这里与最强竞争对手的竞争优势。显然,个人支持度矩阵每一行最多有一个元素大于零。具体用下面的公式生成个人支持度矩阵 rrr:
rnew(i,k)←s(i,k)−maxk′≠k{
s(i,k′)+a(i,k′)}(1)\tag1 r_{new}(i,k) \gets s(i,k)-\max_{k' \neq k}\{s(i,k')+a(i,k')\} rnew(i,k)←s(i,k)−k′=kmax{
s(i,k′)+a(i,k′)}(1)
其中 a(i,k′)a(i,k')a(i,

本文介绍了作者在使用Rust重现实现聚类算法AP过程中遇到的bug,以及通过对比sklearn代码和深入理解AP算法的计算过程来修复问题的经历。AP算法灵感来源于投票选举,通过个人支持度和民意支持度矩阵进行迭代更新,最终确定聚类中心。作者通过实例详细阐述了AP算法的计算步骤,包括相似度矩阵、个人支持度矩阵和民意支持度矩阵的构建和更新,并探讨了算法在处理亲人竞争和选票分散情况下的表现。

1万+

被折叠的 条评论
为什么被折叠?



