読者です 読者をやめる 読者になる 読者になる

はてな村民のPageRank

id:yamaukと申します.最近はてな村にやってきた新参者です.よろしくお願いします.

新参者としましては,はてな村で有力なユーザが誰なのかを抑えておきたいところです.そこで簡単なプログラムを書いて,有力村民をリストアップしてみることにしました.

何をもって有力とするかは色々と考えられますが,今回は基本的な方針として,はてなスターを沢山もらっているユーザを有力村民とみなすことにしました.

ただし,付与されたスターの数をそのまま有力度とすることには色々と問題があるため,今回はPageRankと呼ばれる指標を使います*1PageRankはWebページ間のリンク構造からページの重要度を決定するアルゴリズムですが,今回はスター付与の関係をリンク構造とみなし,ユーザの有力度の決定に用います.PageRankについてはWikipediaの記事を参照してください.

では,具体的な手法をみていきましょう.

手法

スター付与の関係を有向グラフで表現し,PageRankを計算することで村民の有力度を決定します.

グラフは次のように構築します. 各ユーザをノードとします.ユーザBのコメントに,ユーザAがスターを付けた場合,ノードAからノードBにエッジを張ります. また,各エッジにはスター数で重みを付けておきます.なお,自身のコメントへのセルフスター(ループ)は,本エントリでは無視することにします.

f:id:yamauk:20150531112042p:plain

このようにして構築したグラフの各ノードに対して,PageRankを計算します.

実験

実験には以下のツールを使用しました.

  • Python (+BeautifulSoup, NetworkX)
  • Redis

また,実験に使用したプログラムのソースをGitHubにアップしています. 汚いソースで申し訳ありません.コメント等大歓迎です.

github.com

データ収集

ホッテントリのリスト

今回の実験では,はてなブックマークホッテントリ(http://b.hatena.ne.jp/hotentry)内のエントリを対象とします. 全てのウェブページをクロールすることは不可能であるため,最もスター付与合戦が盛んであると思われるホッテントリに対象を絞りました. また,対象期間は2014/1/1〜2015/4/30としました.*2

ホッテントリのURLリストの取得には以下のプログラムを使用しました.

hatena/get_hotentry.py at master · yamauk/hatena · GitHub

結果として,以下のようなホッテントリのリストを取得しました.

対象期間 記事数
2014/1/1〜2015/4/30 24140
スター情報

次にはてなスターのデータを収集します.はてなブックマークにははてなスター取得APIが用意されているため,ブックマークに付与されたスターの情報は容易に取得することができます.取得した情報からスター付与関係グラフの隣接リストを作成し,Redisに保存しておきます.

スター情報の取得および隣接リストの作成には以下のプログラムを使用しました.

hatena/get_star.py at master · yamauk/hatena · GitHub

取得したスター情報の統計を以下に示します.2014/1/1〜2015/4/30内のホッテントリブコメについたスターの情報であることに注意してください*3

ユーザ数 総スター数
25829 3767176

ちなみに,スター付与数のトップ3は以下の通りでした.

# ID スター付与数
1 kiya2015 151827
2 watto 107427
3 guldeen 43102

なかなか迫力がありますね.

グラフ構築とPageRank計算

さて,いよいよスター付与関係グラフを構築し*4PageRankを計算してみます.

先程Redisに保存した隣接リストから,以下のようにしてグラフを構築します.グラフの構築にはNetworkXを使用しました.

hatena/star_network_pagerank.py at master · yamauk/hatena · GitHub

G.add_edge(k, key, weight=v)

とすることで,ノードkからノードkeyに対して,重みvでエッジを張っています(これは,ホッテントリ内におけるkeyさんの全てのコメントに対して,合計v個のスターをkさんが付与したことを意味します).

構築したグラフに対してPageRankを計算してみましょう. PageRankを求めるにはグラフの遷移確率行列の固有値計算などが必要ですが,実はNetworkXのnetworkx.pagerank_scipyメソッドを使って簡単に計算することができます. 先ほどのソースの終わり頃にある,

 pagerank = nx.pagerank_scipy(G, alpha=0.85)

PageRankを計算しています*5. NetworkXは便利ですね.

結果

上記の設定のもと,各ユーザのPageRankを計算した結果を以下に掲載します.

# ID PageRank
1 feita 0.00764836939752
2 xevra 0.00478677706214
3 cider_kondo 0.00421880118293
4 IkaMaru 0.00325257360166
5 nekora 0.00296871347355
6 watto 0.00281244908991
7 jt_noSke 0.0026119632306
8 REV 0.0026030801699
9 wideangle 0.00259544671919
10 nakakzs 0.00252683475568
11 shields-pikes 0.00242718948013
12 kanose 0.00238339397978
13 whkr 0.0023766727969
14 TakamoriTarou 0.00233194015572
15 uturi 0.00231578830442
16 htnmiki 0.00227776074556
17 augsUK 0.00216262880401
18 Gl17 0.00213353383319
19 QJV97FCr 0.00208664557829
20 mahal 0.00208207225066

栄えあるPageRankトップはid:feitaさんであることが分かりました. 個人的にははてな村の村長と噂されるid:kanoseさんがトップである予想していましたが,id:kanoseさんは12位という結果になりました.残念ですね.

以下に全てのユーザのPageRankを貼っておきます.

hatena/result20140101-20150430_selfstar_removed.log at master · yamauk/hatena · GitHub

感想

何となく実感にあった結果が得られた気がします.よかったですね.

今回はホッテントリに対象を絞りましたが,「世の中」や「政治と経済」など,他のカテゴリを対象にしても面白そうです. また,スター情報ではなく,お気に入りユーザー情報を使ってPageRankを求めると,また違った結果が得られるかもしれませんね.

最後に少し言い訳を.本エントリでやっていることは統計分析でも何でもなく,ただのお遊びです.使用する手法,使用するデータによって結果は異なります.各位,お手柔らかにお願いします.

参照文献

はてブAPIでwebサービスを作りたい全ての人に向けて書きました

pythonとnetworkxを使ったPageRank解析 - 研究ブログ

*1:NetworkXでのPageRank計算を試したかっただけ,というのは内緒です.

*2:去年1年分+今年の現時点までのエントリです.期末が4/30なのは実際にクロールを開始した日が5/1だったためで,特に意味はありません.

*3:思ったよりユーザ数が少なく出ています.プログラムにバグがあるかもしれません.や,実はホッテントリブコメにスターをつける人間ってそんなに多くないのかもしれません(ポジティブ思考).

*4:本質的には隣接リストを作った時点でグラフを構築したと言えますが,細かいことは置いておきましょう.

*5:パラメタalphaはdamping factorです.