How can links decide which page ranks first?
Link-based ranking scores a page by the pages that link to it. A page that many pages link to, especially important ones, ranks higher.
The idea is that rank flows along links, and you repeat the flow until the numbers settle. By the end you will run it on a small web and read the result.
By the end of this lesson
Note
I can explain how links can rank pages.
Key words
| Word | What it means | Example |
|---|---|---|
| Link | a reference from one page to another | |
| In-link | a link that points at a page | B to C is an in-link of C |
| Out-link | a link that leaves a page | |
| Rank | a share of importance a page holds, all shares adding to 1 | |
| Iteration | repeating one step, using the last answer as the next start | |
| Damping | the share of rank that follows links; the rest is spread evenly |
The cells students fill in are left blank in this preview.
Why do links help to rank pages?
Word scores such as tf-idf only look at the words on a page. Anyone can write a page with the right words. A link is a vote from another page, and it is harder to fake.
So a page with many in-links is likely to be useful. And a link from a well-linked page counts for more than one from a page nobody links to.
How does rank flow along links?
Start by giving every page the same rank: with four pages, 0.25 each. Then, in each round, every page splits its rank equally among the pages it links to, and sends one share down each link.
A page's new rank is what it receives. C has three in-links, so it collects the most.
What is damping?
A page with no in-links would fall to 0, and a loop of pages could keep all the rank. To stop this, each round a share of rank is spread evenly instead of following links. This is called damping.
With a damping of 0.85, a page gets 0.15 divided by the number of pages for free. It then adds 0.85 times what the links bring.
Run one round of the flow
links = {"A": ["B", "C"], "B": ["C"], "C": ["A"], "D": ["C"]}
damping = 0.85
n = len(links)
ranks = {}
for page in links:
ranks[page] = 1 / n
new = {}
for page in links:
new[page] = (1 - damping) / n
for page in links:
share = ranks[page] / len(links[page])
for target in links[page]:
new[target] = new[target] + damping * share
for page in new:
print(page, round(new[page], 3))
# Make D link to A as well as C. Whose rank changes?
Work out one round on four pages
docker exec jupyter python3 -c "links={'A':['B','C'],'B':['C'],'C':['A'],'D':['C']}; r={p:0.25 for p in links}; print({p:round((1-0.85)/4+0.85*sum(r[q]/len(links[q]) for q in links if p in links[q]),3) for p in links})"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Check the rank of C by hand
docker exec jupyter python3 -c "print(round((1-0.85)/4 + 0.85 * (0.25/2 + 0.25/1 + 0.25/1), 3))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Worked example: where C gets its rank
| From | Rank it holds | Links it has | Share sent to C |
|---|---|---|---|
| A | 0.25 | 2 (B and C) | 0.125 |
| B | 0.25 | 1 (C) | 0.25 |
| D | 0.25 | 1 (C) | 0.25 |
| Total from links | 0.625 | ||
| C's new rank | 0.0375 + 0.85 x 0.625 = 0.569 |
The cells students fill in are left blank in this preview.
Why repeat until the numbers settle?
After one round, C is far ahead. But C sends its rank to A, so A rises in round 2, and then A feeds B and C again. Each page's rank depends on the others, which depend on it.
So repeat the round. The changes shrink, and after about 30 rounds the ranks stop moving to three places. That is the answer.
Worked example: the ranks over the rounds
| Round | A | B | C | D |
|---|---|---|---|---|
| 0 (start) | 0.25 | 0.25 | 0.25 | 0.25 |
| 1 | 0.25 | 0.144 | 0.569 | 0.038 |
| 2 | 0.521 | 0.144 | 0.298 | 0.038 |
| 3 | 0.291 | 0.259 | 0.413 | 0.038 |
| 30 (settled) | 0.373 | 0.196 | 0.394 | 0.038 |
The cells students fill in are left blank in this preview.
Repeat the round until it settles
links = {"A": ["B", "C"], "B": ["C"], "C": ["A"], "D": ["C"]}
damping = 0.85
n = len(links)
ranks = {}
for page in links:
ranks[page] = 1 / n
for turn in range(1, 31):
new = {}
for page in links:
new[page] = (1 - damping) / n
for page in links:
share = ranks[page] / len(links[page])
for target in links[page]:
new[target] = new[target] + damping * share
ranks = new
if turn in [1, 2, 3, 30]:
print(turn, round(ranks["A"], 3), round(ranks["B"], 3), round(ranks["C"], 3), round(ranks["D"], 3))
# Print the total of the four ranks after turn 30. What do you expect?
A common mistake
Warning
Many people think the page with the most in-links always wins, and that every link counts the same. A link from a high-ranked page is worth more, and a page that links to many pages gives each only a small share. In the table A beats B even though both have one in-link.
What is link-based ranking used for?
A search system combines a link score with word scores such as tf-idf, and many other signals. A page can be popular but about the wrong thing, so the words still matter.
Because a link is a vote, people try to fake them. Real systems watch for that, which is why a link score is never used alone.
Going further
Draw a web of five pages of your own, such as course pages of your college. Link each to one or two others. Guess which page will rank highest, then run the code on it.
Then give one page a link to itself and see whether that helps it. Say why a real system would ignore such a link.