PageRank 문서의 구현 코드다. if __name__ == "__main__": 아래가 자체 테스트다.
"""PageRank 구현과 자체 테스트.
문서: 25.PageRank
pagerank(links, n, d=0.85, tol=1e-10, max_iter=1000) -> (r, iterations)
links: {페이지: [링크한 페이지들]}, 페이지 번호는 0..n-1(0-based).
나가는 링크가 없는 페이지(댕글링)는 모든 페이지로 고르게 링크한 것으로 본다.
한 반복은 링크 수 m에 대해 O(n + m)이다. 조밀한 구글 행렬을 만들지 않는다.
"""
def pagerank(links, n, d=0.85, tol=1e-10, max_iter=1000):
r = [1.0 / n] * n
for it in range(1, max_iter + 1):
dangling = sum(r[i] for i in range(n) if not links.get(i))
new = [(1 - d) / n + d * dangling / n] * n
for i, outs in links.items():
if outs:
share = d * r[i] / len(outs)
for j in outs:
new[j] += share
diff = sum(abs(a - b) for a, b in zip(new, r))
r = new
if diff < tol:
return r, it
return r, max_iter
if __name__ == "__main__":
links = {0: [1, 2], 1: [2], 2: [0], 3: [2]}
r, it = pagerank(links, 4)
assert abs(sum(r) - 1) < 1e-12
assert [round(x, 4) for x in r] == [0.3725, 0.1958, 0.3941, 0.0375]
# 대칭 그래프(사이클)는 모두 같은 점수
r, _ = pagerank({i: [(i + 1) % 5] for i in range(5)}, 5)
assert all(abs(x - 0.2) < 1e-9 for x in r)
# 댕글링 페이지가 있어도 합이 1
r, _ = pagerank({0: [1], 1: [], 2: [0, 1]}, 3)
assert abs(sum(r) - 1) < 1e-12 and min(r) > 0
print("impl tests passed")