PageRank 计算博客园用户排名

PageRank 通过网页与网页之间的链接关系计算各网页权重,一般权重高的网页特点是:链接向它的网页数量多、链向它的网页其权重也较高。PageRank 就是通过这样的连接关系,一轮轮迭代计算后得出各网页的权重。

思路拓展一下,其实人与人之间也是连接着的,在社会的人际关系网中,每个人的社会地位和身价也是不同的。以微博为例,我们都有关注者和粉丝(类似网页之间的链接),可以发现所谓的“大V”基本上粉丝数量多,并且粉丝里不乏很多其他“大V”,所以这个帐号的价值就大。

同样博客园也具有类似的社交关系,用户可以选择“关注的人”以及“关注我的人”,理论上是可以用 PageRank 算法算出哪些用户更受大家欢迎,于是本文代大家八卦了一下,文章较长,只想看排名的同学请直接拉到末尾。。。

PageRank 算法简介

1. 数学模型

《数学之美》第10章的延伸阅读部分,对 PageRank 的计算方法进行了简单介绍,但原书有些错误,修改后描述如下:

我们设向量 B 为第一、第二…第N个网页的网页排名

矩阵 A 代表网页之间的权重输出关系,其中 amn 代表第 m 个网页向第 n 个网页的输出权重。

输出权重计算较为简单:假设 m 一共有10个出链,指向 n 的一共有2个,那么 m 向 n 输出的权重就为 2/10。

现在问题变为:A 是已知的,我们要通过计算得到 B。

假设 Bi 是第 i 次迭代的结果,那么

初始假设所有网页的排名都是 1/N (N为网页总数量),即

通过上述迭代计算,最终 Bi 会收敛,即 Bi 无限趋近于 B,此时 B = B × A。

2. 具体示例

假设有网页A、B、C、D,它们之间的链接关系如下图所示

计算 B1 如下:

不断迭代,计算结果如下:

第 1次迭代: 0.125, 0.333, 0.083, 0.458
第 2次迭代: 0.042, 0.500, 0.042, 0.417
第 3次迭代: 0.021, 0.431, 0.014, 0.535
第 4次迭代: 0.007, 0.542, 0.007, 0.444
第 5次迭代: 0.003, 0.447, 0.002, 0.547
第 6次迭代: 0.001, 0.549, 0.001, 0.449
第 7次迭代: 0.001, 0.449, 0.000, 0.550
第 8次迭代: 0.000, 0.550, 0.000, 0.450
第 9次迭代: 0.000, 0.450, 0.000, 0.550
第10次迭代: 0.000, 0.550, 0.000, 0.450
... ...

我们可以发现,A 和 C 的权重变为0,而 B 和 D 的权重也趋于在 0.5 附近摆动。从图中也可以观察出:A 和 C 之间有互相链接,但它们又把权重输出给了 B 和 D,而 B 和 D之间互相链接,并不向 A 或 C 输出任何权重,所以久而久之权重就都转移到 B 和 D 了。

PageRank 的改进

上面是最简单正常的情况,考虑一下两种特殊情况:

   

第一种情况是,B 存在导向自己的链接,迭代计算过程是:

第 1次迭代: 0.125, 0.583, 0.083, 0.208
第 2次迭代: 0.042, 0.833, 0.042, 0.083
第 3次迭代: 0.021, 0.931, 0.014, 0.035
第 4次迭代: 0.007, 0.972, 0.007, 0.014
第 5次迭代: 0.003, 0.988, 0.002, 0.006
第 6次迭代: 0.001, 0.995, 0.001, 0.002
第 7次迭代: 0.001, 0.998, 0.000, 0.001
第 8次迭代: 0.000, 0.999, 0.000, 0.000
第 9次迭代: 0.000, 1.000, 0.000, 0.000
第10次迭代: 0.000, 1.000, 0.000, 0.000
... ...

我们发现最终 B 权重变为1,其它所有网页的权重都变为了0 =。=!

第二种情况是 B 是孤立于其它网页的,既没有入链也没有出链,迭代计算过程是:

第 1次迭代: 0.125, 0.000, 0.125, 0.250
第 2次迭代: 0.063, 0.000, 0.063, 0.125
第 3次迭代: 0.031, 0.000, 0.031, 0.063
第 4次迭代: 0.016, 0.000, 0.016, 0.031
第 5次迭代: 0.008, 0.000, 0.008, 0.016
第 6次迭代: 0.004, 0.000, 0.004, 0.008
第 7次迭代: 0.002, 0.000, 0.002, 0.004
第 8次迭代: 0.001, 0.000, 0.001, 0.002
第 9次迭代: 0.000, 0.000, 0.000, 0.001
第10次迭代: 0.000, 0.000, 0.000, 0.000
... ...

我们发现所有网页权重都变为了0 =。=!

出现这种情况是因为上面的数学模型出现了问题,该模型认为上网者从一个网页浏览下一个网页都是通过页面的超链接。想象一下正常的上网情景,其实我们在看完一个网页后,可能直接在浏览器输入一个网址,而不通过上一个页面的超链接。

我们假设每个网页被用户通过直接访问方式的概率是相等的,即 1/N,N 为网页总数,设矩阵 e 如下:

设用户通过页面超链接浏览下一网页的概率为 α,则直接访问的方式浏览下一个网页的概率为 1 - α,改进上一节的迭代公式为:

通常情况下设 α 为0.8,上一节”具体示例”的计算变为如下:

迭代过程如下:

第 1次迭代: 0.150, 0.317, 0.117, 0.417
第 2次迭代: 0.097, 0.423, 0.090, 0.390
第 3次迭代: 0.086, 0.388, 0.076, 0.450
第 4次迭代: 0.080, 0.433, 0.073, 0.413
第 5次迭代: 0.079, 0.402, 0.071, 0.447
第 6次迭代: 0.079, 0.429, 0.071, 0.421
第 7次迭代: 0.078, 0.408, 0.071, 0.443
第 8次迭代: 0.078, 0.425, 0.071, 0.426
第 9次迭代: 0.078, 0.412, 0.071, 0.439
第10次迭代: 0.078, 0.422, 0.071, 0.428
第11次迭代: 0.078, 0.414, 0.071, 0.437
第12次迭代: 0.078, 0.421, 0.071, 0.430
第13次迭代: 0.078, 0.415, 0.071, 0.436
第14次迭代: 0.078, 0.419, 0.071, 0.431
第15次迭代: 0.078, 0.416, 0.071, 0.435
第16次迭代: 0.078, 0.419, 0.071, 0.432
第17次迭代: 0.078, 0.416, 0.071, 0.434
第18次迭代: 0.078, 0.418, 0.071, 0.432
第19次迭代: 0.078, 0.417, 0.071, 0.434
第20次迭代: 0.078, 0.418, 0.071, 0.433
... ...

PageRank 算法实现

互联网的网页数量是 Billion 级别的,所以不可能一下子初始化矩阵 A ,试想一下 10亿 × 10亿 的矩阵是什么概念!

这时就用到稀疏矩阵了,定义稀疏矩阵的结构如下(其实是稀疏矩阵的一行):

public class SparseMatrix<T>
{
    public SparseMatrix(T head, double rank)
    {
        Head = head;
        LinkedItems = new List<T>();
        Rank = rank;
    }

    /// <summary>
    ///     稀疏矩阵头
    /// </summary>
    public T Head { get; private set; }

    public double Rank { get; set; }

    /// <summary>
    ///     稀疏矩阵链接的项目
    /// </summary>
    public List<T> LinkedItems { get; set; }

    public void AddLink(T linkedItem)
    {
        LinkedItems.Add(linkedItem);
    }
}

第一节中的链接示例图,就可以用如下代码表示:

Dictionary<char, SparseMatrix<char>> matrix = new Dictionary<char, SparseMatrix<char>>
{
    {‘A‘, new SparseMatrix<char>(‘A‘, 0.25){LinkedItems = new List<char>{‘B‘, ‘C‘, ‘D‘}}},
    {‘B‘, new SparseMatrix<char>(‘B‘, 0.25){LinkedItems = new List<char>{‘D‘}}},
    {‘C‘, new SparseMatrix<char>(‘C‘, 0.25){LinkedItems = new List<char>{‘A‘, ‘D‘}}},
    {‘D‘, new SparseMatrix<char>(‘D‘, 0.25){LinkedItems = new List<char>{‘B‘}}}
};

通过稀疏矩阵计算,与原先的整个矩阵行列式计算有较大不同,计算次序已经发生了变化。原先矩阵是一行乘以权重的竖列,稀疏矩阵则变为类似于按原先矩阵的竖列与权重相乘。矩阵运算中当然不允许 1 × N 矩阵与 1 × N 矩阵相乘的情况,我们能做的就是先将一项项算好,比如先算 A 这一行,算出 A 给 B、C、D输出多少权重,在一个类似字典类型的数据结构里,给 B、C和 D 各加上一笔,像是一个 Map-Reduce 过程。

public class MapReduce<T>
{
    private readonly Dictionary<T, double> _map;

    public MapReduce()
    {
        _map = new Dictionary<T, double>();
    }

    public double Reduce(T key, double value)
    {
        if (_map.ContainsKey(key))
        {
            _map[key] += value;
            return _map[key];
        }
        _map.Add(key, value);
        return value;
    }

    public double GetOrSetDefaultValue(T key)
    {
        if (_map.ContainsKey(key))
            return _map[key];
        _map.Add(key, 0.0);
        return 0.0;
    }
}

PageRank 设计如下:

public class PageRank<T>
{
    private MapReduce<T> _mapReduce;
    private readonly double _stayProbability;
    private readonly double _averageRank;

    /// <summary>
    ///
    /// </summary>
    /// <param name="totalCount">项目总数</param>
    /// <param name="stayProbability">保持留在某个项目, 不跳转的概率</param>
    public PageRank(int totalCount, double stayProbability = 0.8)
    {
        _mapReduce = new MapReduce<T>();
        _stayProbability = stayProbability;
        _averageRank = 1.0 / totalCount;
    }

    /// <summary>
    ///     计算下一轮PageRank
    /// </summary>
    public void NextCircle()
    {
        _mapReduce = new MapReduce<T>();
    }

    /// <summary>
    ///     计算一条行列式
    /// </summary>
    /// <param name="sparseMatrix">稀疏矩阵</param>
    public void Calc(SparseMatrix<T> sparseMatrix)
    {
        var outputRank = 1.0 / sparseMatrix.LinkedItems.Count;

        foreach (var item in sparseMatrix.LinkedItems)
        {
            _mapReduce.Reduce(item,
                _stayProbability * outputRank * sparseMatrix.Rank);
        }
        //当没有其它链接指向Head的时候, 以防漏项
        _mapReduce.Reduce(sparseMatrix.Head, (1 - _stayProbability) * _averageRank);
    }

    /// <summary>
    ///     一轮PageRank迭代之后, 获取最新的PageRank并更新
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public double GetCurrentRank(T key)
    {
        return _mapReduce.GetOrSetDefaultValue(key);
    }
}

调用示例:

var matrix = new Dictionary<char, SparseMatrix<char>>
{
    {‘A‘, new SparseMatrix<char>(‘A‘, 0.25){LinkedItems = new List<char>{‘B‘, ‘C‘, ‘D‘}}},
    {‘B‘, new SparseMatrix<char>(‘B‘, 0.25){LinkedItems = new List<char>{‘D‘}}},
    {‘C‘, new SparseMatrix<char>(‘C‘, 0.25){LinkedItems = new List<char>{‘A‘, ‘D‘}}},
    {‘D‘, new SparseMatrix<char>(‘D‘, 0.25){LinkedItems = new List<char>{‘B‘}}}
};

var pageRank = new PageRank<char>(matrix.Count);
//计算30轮
for (int i = 1; i <= 30; i++)
{
    pageRank.NextCircle();
    foreach (var item in matrix)
    {
        pageRank.Calc(item.Value);
    }
    foreach (var item in matrix)
    {
        var cRank = pageRank.GetCurrentRank(item.Key);
        item.Value.Rank = cRank;
    }
    var str = string.Join(", ", matrix.Select(item => item.Value.Rank.ToString("N3")));
    Console.WriteLine(string.Format("第{0,2}次迭代: {1}", i, str));
}

开源地址:https://github.com/CreateChen/PageRank

博客园用户权重计算

写一个简单的网络爬虫,爬取博客园所有用户的 Id、关注的人等信息(过程略),最终得到如下结构的表格:

首先八卦一下粉丝数量 Top 20,方便与 PageRank 算出的结果做对比。

下面进入真正的 PageRank 计算了,利用第二节的程序计算,一次迭代计算速度很快,从数据库获取数据并且计算完毕只要6秒,更新数据库的 Rank 字段需要近30秒。下表展示的是第1轮迭代、第15轮的用户的权重:

排名 NickName Rank NickName Rank
1 梦想天空(山边小溪) 0.002165 梦想天空(山边小溪) 0.001346
2 Fish Li 0.00192 dudu 0.001334
3 汤姆大叔 0.001514 Artech 0.00102
4 Jimmy Zhang 0.001281 Fish Li 0.000947
5 M了个J 0.001244 司徒正美 0.000786
6 Artech 0.001164 李永京 0.000746
7 农民伯伯 0.001161 汤姆大叔 0.0007
8 司徒正美 0.000987 趣味苹果开发 0.000677
9 Vamei 0.000953 通用C#系统架构 0.000601
10 tornadomeet 0.000858 M了个J 0.00059
11 伍华聪 0.000787 Jimmy Zhang 0.000586
12 一线码农 0.000786 banban 0.000576
13 吴秦 0.00075 Milo Yip 0.000532
14 dudu 0.000729 张善友 0.000488
15 虫师 0.000722 Jeffrey Zhao 0.00047
16 小坦克 0.000691 觉先 0.000462
17 Rollen Holt 0.000649 SoftwareTeacher 0.000444
18 圣殿骑士 0.000545 博客园团队 0.000434
19 CareySon 0.000538 TerryLee 0.000434
20 文顶顶 0.000538 胡尐睿丶 0.00043
21 小洋(燕洋天) 0.000535 T2噬菌体 0.000422
22 虾皮 0.000529 农民伯伯 0.000415
23 JerryLead 0.000526 Anytao 0.000411
24 李永京 0.000508 圣殿骑士 0.000411
25 方倍工作室 0.000505 深蓝色右手 0.000406
26 cloudgamer 0.000486 伍华聪 0.0004
27 杨中科 0.000483 一线码农 0.000399
28 TerryLee 0.000467 小洋(燕洋天) 0.000388
29 张善友 0.000466 Cat Chen 0.000374
30 深蓝色右手 0.000457 CareySon 0.000371
31 谦虚的天下 0.000445 Vamei 0.000365
32 通用C#系统架构 0.000435 ziqiu.zhang 0.000358
33 胡尐睿丶 0.00042 周 金根 0.000351
34 三生石上 0.000413 伍迷 0.000342
35 KenshinCui 0.000397 xiaotie 0.000332
36 博客园团队 0.000389 谦虚的天下 0.000331
37 酸奶小妹 0.000387 冠军 0.000329
38 Milo Yip 0.000372 吴秦 0.000327
39 伍迷 0.00037 cloudgamer 0.000318
40 子龙山人 0.000369 tornadomeet 0.000305
41 Insus.NET 0.000369 酸奶小妹 0.0003
42 菩提树下的杨过 0.000369 小坦克 0.0003
43 万一 0.000368 【当耐特】 0.000285
44 _Luc_ 0.000367 chenkai 0.000277
45 夏天的森林 0.000354 Justin 0.000274
46 ziqiu.zhang 0.000351 装配脑袋 0.000272
47 Jeffrey Zhao 0.000351 虫师 0.000271
48 叶小钗 0.000343 菩提树下的杨过 0.000271
49 真 OO无双 0.000343 Gnie 0.00027
50 SoftwareTeacher 0.000337 张逸 0.000252
51 webabcd 0.000333 LeftNotEasy 0.000245
52 T2噬菌体 0.000331 小静(Cathy) 0.00024
53 Ruthless 0.000328 Gray Zhang 0.000237
54 peida 0.000327 Jesse Liu 0.000237
55 陈梓瀚(vczh) 0.000324 JerryLead 0.000231
56 聂微东 0.000322 webabcd 0.000228
57 Jesse Liu 0.000317 fly in ocean 0.000225
58 【当耐特】 0.000288 Anders Cui 0.000221
59 西西吹雪 0.000286 代震军 0.000221
60 snandy 0.000286 COM张 0.00022
61 Phinecos(洞庭散人) 0.000286 楠小楠 0.00021
62 David_Tang 0.000283 何戈洲 0.00021
63 yangecnu 0.000282 三生石上 0.000207
64 孤傲苍狼 0.000278 路过秋天 0.000204
65 Learning hard 0.000277 Jake Lin 0.000203
66 Stephen_Liu 0.000272 飞洋过海 0.000201
67 Terry_龙 0.000269 陈希章 0.0002
68 xiaotie 0.000269 叶小钗 0.000198
69 Leo Chin 0.000269 eaglet 0.000197
70 海 子 0.000267 陈梓瀚(vczh) 0.000197
71 Barret Lee 0.000264 _Luc_ 0.000194
72 路过秋天 0.000263 snandy 0.000191
73 Dsp Tian 0.000255 新瓶老酒 0.000186
74 Devin Zhang 0.000255 Bēniaǒ 0.000185
75 苍梧 0.000252 dax.net 0.000185
76 觉先 0.000251 麒麟.NET 0.000185
77 周 金根 0.00025 方倍工作室 0.000183
78 冠军 0.000249 万一 0.000181
79 何戈洲 0.000242 陈硕 0.000179
80 刘冬.NET 0.000237 任力 0.000177
81 hoojo 0.000236 Franky 0.000177
82 Orisun 0.000236 虾皮 0.000173
83 CrazyBingo 0.000235 Stephen_Liu 0.000172
84 代震军 0.000234 石破天惊 0.000172
85 minglz 0.000231 岑安 0.000171
86 Alexia(minmin) 0.000226 杨中科 0.00017
87 Gnie 0.000226 iOS之旅 0.00017
88 邹华栋 0.000225 横刀天笑 0.000169
89 Samaritans 0.000224 邀月 0.000168
90 Aaron艾伦 0.000222 jv9 0.000165
91 邀月 0.000221 聂微东 0.000164
92 Healtheon 0.000219 创想中国(羲闻) 0.000164
93 李林峰的园子 0.000219 CoderZh 0.000163
94 吕震宇 0.000218 Luminji 0.000163
95 沈逸 0.000218 winter-cn 0.000163
96 LeftNotEasy 0.000213 Rollen Holt 0.000161
97 陈希章 0.000212 金色海洋(jyk)阳光男孩 0.000159
98 Hongten 0.000211 重典 0.000159
99 创想中国(羲闻) 0.000211 阿一(杨正祎) 0.000157
100 Cat Chen 0.000208 夜里的烟 0.000157

如果你对完整的计算过程感兴趣,可以下载完整表格。想了解自己的权重及排名请在下方留言。

当然在实际计算排名过程中,不单单依据粉丝与关注者之间的关系,还需要结合文章的质量、更新频率及数量,最后给一个综合的评分。总之:被关注数量越多、经常写文章、文章被赞的次数越多、评论次数多,就越能提升社区影响力。

本文链接:http://www.cnblogs.com/technology/p/PageRank.html

时间: 2024-11-10 20:56:34

PageRank 计算博客园用户排名的相关文章

PageRank实践-博客园用户PageRank排名

博客园用户由关注和粉丝的关系,这与网页的链接关系很类似,于是我就爬了博客园的粉丝与关注用户,然后计算了一下用户的PageRank排名,注意本排名仅仅是个人娱乐,不代表任何利益,而且可能计算有误,望大家不要较真. 关于PageRank的原理和计算方法参看上一篇文章,这篇文章主要介绍一下博客园用户PageRank的结果. 目前博客园用户超过了17万,我以自己为启点,不断的爬取用户的粉丝和关注,最终爬到的用户是132483,还剩4万多的用户没有爬取到,我分析这部分用户是既没有粉丝也不关注其他用户的孤岛

python 爬虫 计算博客园浏览量,刷浏览量

首先进入博客园的管理页面: 通过观察A-JAX请求,发现博客的分类(categories)是一个json格式的数据即:                                    于是先爬取categories.通过各个分类的页面进而爬去地址,浏览量,打开一个category的页面: 检查网页     这样就得到了每个博客的地址和浏览量了 上代码,其他一些问题在代码中给出注释: import time import requests import json import re from

python网络爬虫(14)博客园用户信息爬取

说明 这里只放代码,方案技术没有更变 代码说明 需要cookies绕过登录,使用selenium在Firefox下模拟.需要安装geck...?插件,另外,数据存储在sqlite,需要安装. Spider.py import HtmlDownloader import HtmlParser import DataOutput import UrlManager import re from selenium import webdriver class Spider(object): def _

UWP 获取博客园积分,并以图标形式呈现变化趋势

先看一下效果吧 1. 分析 说实话,之前还真没在乎过博客园的排名和积分,博客园默认也不给显示.需要自己到选项里面勾选才可以. 之前也有几个大佬写过类似的文章,不过是很早了.博客园关于获取积分的api已经变了. 也不算是api吧,毕竟不是官方公开的.不过自己可以通过查看页面元素,找到博客园的积分url. 在你勾选?了上面的选项之后,打开你的博客主页,比如我的就是https://www.cnblogs.com/hupo376787/ 按F12,调出开发者工具,进入Network选项卡. 如果在下面的

如何高效的利用博客园?

写在前面 在河南工作那会儿,虽然遇到问题也百度过,google过,但是很少留意内容来自哪个网站,也许是工作的内容太简单了,也许是太单调了,之后的之后就很少上网查东西了,因为模块相似,功能相似,代码写了n遍了.真不用了!后来也因为合同到期了,就选择了让我向往已久的北京. 来了北京后,发现自己其实很菜,之前那种玩法都是小儿科.不得不重新充实自己.然后就是不断的学习,不断的提高,一个偶然的机会,群里朋友说起了博客园,也是偶然的一个举动进博客园看了一看,不看不要紧,一看,二看.......从此以后我发现

博客园的模拟登陆(Simulated Login)

查看正常情况下登录博客园时本地浏览器向博客园的服务器发送的数据 依据上一步得到的由本地浏览器发送给博客园服务器的数据包内容进行模拟登陆 scrapy模拟登陆博客园 Reference 1.查看正常情况下登录博客园时本地浏览器向博客园的服务器发送的数据 首先打开博客园登录界面,填入登录用户名和密码,按快捷键 Ctrl+Alt+I 打开开发者管理器,然后点击登录 按钮,则可以在开发者管理器里看到发送的数据包内容. 数据包内容的查看位置如下图所示. 下面贴出了该数据包的内容 1. General 1.

Python爬虫入门教程 54-100 博客园等博客网站自动评论器

爬虫背景 爬虫最核心的问题就是解决重复操作,当一件事情可以重复的进行的时候,就可以用爬虫来解决这个问题,今天要实现的一个基本需求是完成"博客园" 博客的自动评论,其实原理是非常简单的,提炼一下需求 基本需求 登录博客园<不实现,登录单独编写博客> 调用评论接口 返回请求结果 确定流程之后,基本就是找突破口的环节了 实际的去评论一下,然后不管你用什么抓包工具都可以,只要抓取到你想要的数据,即可 评论API如下 Request URL: https://www.cnblogs.

黄聪:博客园的积分和排名算法探讨,积分是怎么计算的?(转)

我们先来看看现行规则,用公式表示为:-------------------------------------------------------------------BlogScore = BeRead + 10 * BeComment + 50 * CommentBlogScore:博客积分BeRead:个人博客所有随笔和文章的阅读数之和BeComment:个人博客被评论总数Comment: 个人所发表的评论总数---------------------------------------

博客园积分与排名升级攻略(转)

博客园积分算法探讨 今天在dudu的<博客园FAQ>上看到了博客积分算法规则.因为同样是搞互联网的,平时工作也涉及到用户积分算法的设计,所以特把此问题拿出来分析探讨.初衷只是纯学术的研究探讨,并不构成对博客园积分机制的意见建议. 我们先来看看现行规则,用公式表示为:-------------------------------------------------------------------BlogScore = BeRead + 10 * BeComment + 50 * Commen