一、算法介绍
PageRank (PR) 是谷歌搜索引擎对搜索网页结果进行排名的一种算法。网页排名是衡量网页重要性的一种方法。现今我们可以将其用于衡量图中顶点的重要程度。
PageRank,中文我们可以叫做页面排名算法, 是以“网页”和联合创始人拉里 · 佩奇的名字命名的。(PageRank)用来衡量每个点相对于其它点的影响程度 。该算法根据某点被指向的数量,及指向点的重要程度来计算图中每个点的重要性。该算法通常使用在搜索引擎的页面排名中,一个页面的“得票数”由所有指向它的页面的重要性来决定。用户的浏览操作相当于PageRank的迭代操作,用户浏览该页面的概率我们称为damping(阻尼系数),不再往下浏览的概率为1-damping 。
二、使用场景
1. PageRank算法适用于网页排序、社交网络重点人物发掘,可用于找出网络中影响力较高的用户或者名气较大的网站。
2. 科学家对领域的贡献,不能单单考虑其引文数量,而且还需要考虑每次引文的实际影响。具体可以参考《The Pagerank-Index: Going beyond Citation Counts in Quantifying Scientific Impact of Researchers》。
3. 在生物学中,代谢图是有向图,我们将生物反应建立为节点,如果反应u产生反应之后生成产物v,那么就有了u到v的有向边,可以通过PageRank去评估大型蛋白质组学研究的稳定性分析。具体详情参考《When the Web meets the cell: using personalized PageRank for analyzing protein interaction networks》 。
4. 在机器学习中寻找对抽取最有 影响的特征, 并在自然语言处理 中对文本进行实体相关性排序。
三、算法实现
3.1 算法计算公式
整体公式:
对于某个节点i,其对应PR值大小的计算公式如下:
该公式引入了随机浏览者(random surfer)的概念,PageRank理论认为一个使用者在随机浏览网页的情况下,最终会趋于终止。这也是damping factor(阻尼因子),存在的重要原因,其表示下一继续点击的网页的概率。当然我在浏览网页的时候会遇到没有外部链接的情况,为了处理这种情况(这些页面会像“黑洞”一样吞噬掉用户继续向下浏览的概率)所带来的问题,我们让这类网页的PR值将被所有网页均分,即用户范围下一个页面的概率将会从所有网页中选取。那么该值应该设置为多少好呢?经过多方研究测试一般会设置阻尼因子在0.85左右。
参数介绍:
这里, 是目标节点 是集合中所有节点的数量。 是链入 节点的集合,是节点 链出节点的数量,而 是集合中所有节点的数量。
3.2. 案例推导
根据上图数据,让我们计算图中E的PageRank的得分吧,首先该算法需要输入迭代轮数为5,阻尼系数为0.85。
1.让我们确定计算节点E, 全图总点数11。
2.由于需要进行迭代计算。首先我们设置全图每个点的初始值为1(一般采用这个值),当然算法可以通过算法参数调整:
顶点ID | PageRank初始得分 |
---|---|
1 | 1 |
2 | 1 |
3 | 1 |
4 | 1 |
5 | 1 |
6 | 1 |
7 | 1 |
8 | 1 |
9 | 1 |
10 | 1 |
11 | 1 |
然后让我们计算每个点的贡献值:
顶点ID | 每个点访问其他点的概率 |
---|---|
1 | 1/11 |
2 | 1/2 |
3 | 1/2 |
4 | 1/2 |
5 | 1/2 |
6 | 1 |
7 | 1 |
8 | 1/2 |
9 | 1 |
10 | 1 |
11 | 1/2 |
上述分母为出边数量,当某个点的出边数量为0时,我们为了防止陷入陷阱,采用了1/N ,N为全局
点数量,即当点的邻居数为0时,我们就采用1/N。
2.1.在确定好初始分数之后,让我们开始第一轮迭代吧.
2.2.在进行第一轮迭代之后算法的结果
2.3.让我们在进行第二轮迭代吧
2.4 从上述的公式我们应该已经知道PageRank算法的计算逻辑了吧,只要不断的按这个方式进行迭代5,既可以得到最终的PageRanK得分
2.5 即通过5轮的迭代我们可以得出E点的最终得分为4.059365234375
四、代码实现
/**
* version: 1.0
* author: road
* data: 20220714
*/
public class PageRank {
private GraphApi graphApi;
//reduce computational cost
private double[] initValues;
private double[] preValue;
private double[] curValue;
private double delta;
public PageRank(GraphApi graphApi){
this.graphApi = graphApi;
}
public double[] compute(int iteration, double damping, double initValue) {
delta = 1 - damping;
init(damping, initValue);
int vertexSize = graphApi.getVertexSize();
preValue = new double[vertexSize];
curValue = new double[vertexSize];
int[] vertexIds = graphApi.getVertex();
for(int i = 0; i < iteration; i++) {
System.arraycopy(curValue, 0, preValue, 0, vertexSize);
for (int id : vertexIds) {
double sum = 0;
int[] inEdge = graphApi.getInEdge(id);
for (int inId : inEdge) {
sum += initValues[inId] * preValue[inId];
}
//(1-d) + sum
curValue[id] = delta +sum;
}
}
return curValue;
}
private void init(double damping, double initValue) {
int vertexSize = graphApi.getVertexSize();
initValues = new double[vertexSize];
Arrays.fill(curValue, initValue);
int[] vertexIds = graphApi.getVertex();
for (int id : vertexIds) {
int outDegree = graphApi.getOutEdge(id).length;
if(outDegree != 0) {
initValues[id] = damping / outDegree;
}
}
}
}
代码详情: TGraph/PageRank.java at main · RoadTLife/TGraph · GitHub
五、参考引用
【1】The Anatomy of a Search Engine PageRank算法
【2】https://en.wikipedia.org/wiki/PageRank wiki官网PageRank介绍论文