ふくふくHukuhuku Inc.
EP.10Algorithms 10分公開: 2026-05-11

PageRank:Google を作ったグラフ中心性アルゴリズムを Python で再現

「重要なページからリンクされているページが重要」を再帰的に解く PageRank。Google が 1998 年に発明、現在も Twitter のフォロー / 論文の引用解析で生きる。

#PageRank#グラフ#Google#中心性
CO📔 Google Colab で開く(上から順にセルを実行)
シェア

1998 年、スタンフォード大学院生の Larry Page と Sergey Brin は「ウェブのリンク構造を行列の固有ベクトルとして解く」 という論文を発表。これが Google の出発点となった PageRank。リンクがある = 投票する、というシンプルな考え方を再帰的に展開し、線形代数の美しさで解く。

1. これで何が動いているか

  • Google 検索 (1998-現在も核の一部)
  • Twitter のフォローグラフ影響力スコア
  • 論文引用解析 (Eigenfactor / SCImago)
  • Facebook の友人推薦 (グラフ中心性として)
  • 生物学: タンパク質相互作用ネットワーク
  • Google Maps の道路網解析

2. 仕組みのざっくり

  • ウェブをグラフとして表現: ノード = ページ、エッジ = ハイパーリンク
  • 重要度を 1/N で初期化
  • 反復: r_new[i] = (1-d)/N + d × Σ (r[j] / out_degree(j)) for j → i
  • ダンピングファクター d=0.85: ランダムジャンプを混ぜる
  • 収束: 30-50 反復で十分 (誤差 < 1e-6)
数学的に何をしてるか

遷移行列 M (j → i の確率) の固有値 1 の固有ベクトルを求めている。Power Iteration (べき乗法) は最大固有値の固有ベクトルに収束する基本アルゴリズム。Perron-Frobenius の定理により正の固有ベクトルが必ず存在する。

3. Python 実装 (動作確認済)

5 ノードのグラフでの PageRank
Python
import numpy as np
def pagerank(adj, d=0.85, max_iter=100, tol=1e-9):    '''    adj: N x N の隣接行列 (adj[i][j]=1 なら i → j のリンク)    '''    N = len(adj)    # 行ごとに正規化 (確率行列にする)    out_deg = adj.sum(axis=1, keepdims=True)    out_deg[out_deg == 0] = 1  # dangling node 対策    M = adj / out_deg
    # 初期化    r = np.ones(N) / N
    # Power Iteration    for it in range(max_iter):        r_new = (1 - d) / N + d * M.T @ r        if np.abs(r_new - r).sum() < tol:            print(f'収束: {it+1} 反復')            break        r = r_new
    return r_new
# 5 ページのウェブ# A → B, A → C# B → C# C → A, C → D# D → E# E → Aadj = np.array([    [0, 1, 1, 0, 0],  # A    [0, 0, 1, 0, 0],  # B    [1, 0, 0, 1, 0],  # C    [0, 0, 0, 0, 1],  # D    [1, 0, 0, 0, 0],  # E], dtype=float)
ranks = pagerank(adj)labels = ['A', 'B', 'C', 'D', 'E']ranked = sorted(zip(labels, ranks), key=lambda x: -x[1])print('\nPageRank ランキング:')for name, r in ranked:    print(f'  {name}: {r:.4f}')
# 実機実行結果 (例):# A: 0.278  ← C と E からリンクされて高い# C: 0.274  ← A と B からリンクされて高い# E: 0.154# B: 0.148# D: 0.146

4. NetworkX を使った実用版

実用ライブラリ NetworkX
Python
import networkx as nx
# 同じグラフを NetworkX でG = nx.DiGraph()edges = [('A','B'), ('A','C'), ('B','C'),         ('C','A'), ('C','D'), ('D','E'), ('E','A')]G.add_edges_from(edges)
ranks = nx.pagerank(G, alpha=0.85)for n, r in sorted(ranks.items(), key=lambda x: -x[1]):    print(f'  {n}: {r:.4f}')

5. パラメータの効果

d (damping)意味効果
0.0全員ランダムジャンプ全ノード均等 (PageRank の意味なし)
0.5中庸リンク構造の影響半分
0.85Google の標準リンク構造を主、ジャンプで安定化
1.0完全リンク追従ループ / dangling で発散・収束しないことも

6. メリットとデメリット

  • メリット: グラフ構造のみで計算可能、コンテンツ非依存
  • メリット: 大規模グラフ (10 億ノード) でも O(N+E) で計算可能
  • メリット: 任意の有向グラフに適用可 (フォロー、引用、道路網)
  • デメリット: コンテンツの内容を見ない (BM25 / TF-IDF と組合せが必須)
  • デメリット: 「リンクファーム」等のスパムに脆弱 (TrustRank / SpamRank で補正)

7. 関連アルゴリズム

  • HITS (Hyperlink-Induced Topic Search): hub と authority を分離
  • TrustRank: スパム耐性を持つ拡張
  • Personalized PageRank: ユーザごとのジャンプ先を変えて推薦に応用
  • SimRank: 類似ノードを見つけるグラフアルゴリズム
  • LeaderRank: スパム耐性のある拡張

8. 次の話

EP.11 では Reservoir Sampling を扱います。ストリームから k 件を等確率でサンプリングする 美しいアルゴリズム ── ABTest / ログサンプリング / 機械学習で活躍する 1 行の魔法。

シェア

この記事の感想を教えてください

あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。

シリーズの外も探す:

まずは、現状を聞かせてください。

要件が固まっていなくて大丈夫です。現状診断と方針提案までを無料でお手伝いします。

無料相談フォームへ hello [at] hukuhuku [dot] co [dot] jp