Created
March 28, 2023 19:35
-
-
Save JadedBlueEyes/6a7eecd637ce7f71a38b348e76f2158f to your computer and use it in GitHub Desktop.
Pagerank implemented in plain JS and with graphology.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Graph from "graphology"; | |
const defaultDampening = 0.85; | |
const defaultIterations = 40 | |
// graph, or page map: the pages that exist, and that each page links to | |
/** | |
* | |
* @param {Graph} graph | |
* @param {number} iterations | |
* @param {number} dampening | |
* @param {*} initialScores | |
* @returns scores | |
*/ | |
export function pageRank (graph, iterations, dampening, initialScores) { | |
// dampening factor - how likely the user is to continue clicking | |
dampening = dampening ?? defaultDampening | |
iterations = iterations ?? defaultIterations | |
let scores = {} | |
// set the initial score of each page | |
if (initialScores) { | |
graph.nodes().forEach((node) => { | |
scores[node] = initialScores[node] ?? 1.0; | |
}) | |
} else { | |
graph.nodes().forEach((node) => { | |
scores[node] = 1.0; | |
}) | |
} | |
let i = iterations; | |
while (i >= 0) { | |
// We want to calculate in stages, so store the new values until all values have been calculated | |
let iterationScores = {} | |
// Calculate the new score for each page according to the pagerank formula | |
graph.nodes().forEach((node) => { | |
let score = 1 - dampening | |
graph.inboundEdges(node).forEach((edge) => { | |
let neighbor = graph.source(edge) | |
let count = graph.outEdges(neighbor).length | |
let edgeScore = scores[neighbor] / count | |
score = score + dampening * edgeScore | |
}) | |
iterationScores[node] = score | |
}) | |
// update the stored final values and continue the loop | |
scores = iterationScores | |
i = i - 1; | |
} | |
return scores | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const defaultDampening = 0.85; | |
const defaultIterations = 40 | |
// graph, or page map: the pages that exist, and that each page links to | |
export function pageRank (graph, iterations, dampening, initialScores) { | |
// dampening factor - how likely the user is to continue clicking | |
dampening = dampening ?? defaultDampening | |
iterations = iterations ?? defaultIterations | |
let scores = {} | |
// set the initial score of each page | |
for (let node in graph) { | |
scores[node] = initialScores[node] || 1.0; | |
} | |
// invert the graph. eg. page a is linked to by pages e and f | |
let invertedGraph = {} | |
for (let node in graph) { | |
invertedGraph[node] = []; | |
} | |
for (let node in graph) { | |
graph[node].forEach((edge) => { | |
invertedGraph[edge].push(node) | |
}) | |
} | |
let i = iterations; | |
while (i >= 0) { | |
// We want to calculate in stages, so store the new values until all values have been calculated | |
let iterationScores = {} | |
// Calculate the new score for each page according to the pagerank formula | |
for (let node in graph) { | |
let score = 1 - dampening | |
invertedGraph[node].forEach((edge) => { | |
let count = graph[edge].length | |
let edgeScore = scores[edge] / count | |
score = score + dampening * edgeScore | |
}) | |
iterationScores[node] = score | |
} | |
// update the stored final values and continue the loop | |
scores = iterationScores | |
i = i - 1; | |
} | |
return scores | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment