Calcul du PageRank en Python

Apprenez à implémenter l'algorithme du PageRank en Python pour analyser la distribution du PageRank sur votre site web.

Ce document décrit un script Python permettant de calculer le PageRank d'un ensemble de pages à partir d'une liste de liens, en prenant en compte l'attribut nofollow qui empêche la transmission de PageRank.

Vous pouvez trouvez le code fonctionnel et utilisable directement depuis ce Notebook Google Colab

Dépendances

Le script repose sur les bibliothèques suivantes :

  • pandas : pour manipuler les données tabulaires.
  • networkx : pour la gestion des graphes dirigés.

Installer les dépendances avec pip

pip install pandas networkx
import pandas as pd
import networkx as nx
from google.colab import data_table

Fonction calcul_pagerank

La fonction calcul_pagerank prend en entrée :

  • data (dict) : un dictionnaire contenant les relations entre les pages (source, cible, et nofollow).
  • iterations (int, par défaut 100) : le nombre d'itérations pour l'algorithme.
  • damping_factor (float, par défaut 0.85) : le facteur de téléportation du PageRank (classiquement fixé à 0.85).

Elle renvoit en sortie un dataframe contenant le Pagerank de de chaque noeud.

Étapes du calcul de la fonction

def calcul_pagerank(data, iterations=100, damping_factor=0.85):

1. Création d'un DataFrame à partir des données et conversion de nofollow en booléen

  df = pd.DataFrame(data)
  df["nofollow"] = df["nofollow"].astype(bool)

2. Initialisation du graphe orienté DiGraph avec networkx

  G = nx.DiGraph()

3. Ajout des nœuds pour garantir que toutes les URLs sont présentes

  for url in pd.concat([df["source"], df["target"]]).unique():
      G.add_node(url)

4. Initialisation des valeurs de PageRank

Chaque page commence avec une valeur initiale égale à 1 / nombre de pages.

  initial_pr = 1 / len(G.nodes)
  pagerank = {node: initial_pr for node in G.nodes}

5. Boucle d'itération du PageRank

L'algorithme s'exécute pendant iterations cycles pour assurer la convergence.

  for _ in range(iterations):
      new_pagerank = {node: (1 - damping_factor) / len(G.nodes) for node in G.nodes}  # Facteur de téléportation

6. Calcul du PageRank pour chaque nœud

Pour chaque page (nœud), on :

  • Identifie ses liens sortants.
  • Vérifie si elle a des liens nofollow.
  • Redistribue son PageRank uniquement aux liens follow.
      for node in G.nodes:
          outgoing_links = df[df["source"] == node]
          total_links = len(outgoing_links)

          if total_links > 0:
              pr_to_distribute = pagerank[node] * damping_factor  # Part à redistribuer
              follow_links = outgoing_links[~outgoing_links["nofollow"]]
              nb_follow_links = len(follow_links)

              if nb_follow_links > 0:
                  share_per_link = pr_to_distribute / nb_follow_links  # Partage équitable entre les liens follow
                  for _, row in follow_links.iterrows():
                      new_pagerank[row["target"]] += share_per_link  # Attribution du PageRank

7. Mise à jour des valeurs pour l'itération suivante

      pagerank = new_pagerank

8. Retour du résultat sous forme de DataFrame

  return pd.DataFrame(pagerank.items(), columns=["URL", "PageRank"])

Exécution du script

Un jeu de données de test est défini pour illustrer le fonctionnement de la fonction :

data = {
    "source": ["home", "home", "B", "C"],
    "target": ["B", "C", "home", "home"],
    "nofollow": [0, 0, 0, 0]  # 1 = nofollow (le lien ne transmet pas de PageRank)
}

Le calcul du PageRank est lancé et les résultats sont affichés :

pri = calcul_pagerank(data)

Code complet :


import pandas as pd
import networkx as nx

def calcul_pagerank(data,iterations=100,damping_factor=0.85):
  df = pd.DataFrame(data)
  df["nofollow"] = df["nofollow"].astype(bool)

  # 2. Initialisation du graphe
  G = nx.DiGraph()

  # Ajout des noeuds pour assurer que toutes les URLs sont bien présentes
  for url in pd.concat([df["source"], df["target"]]).unique():
      G.add_node(url)

  # 3. Calcul du PageRank en prenant en compte le nofollow
  initial_pr = 1 / len(G.nodes)  # Répartition initiale égale

  # Initialisation des scores de PageRank
  pagerank = {node: initial_pr for node in G.nodes}

  # Boucle d'itération pour convergence (type algo Power Iteration)
  for _ in range(iterations):  # 100 itérations suffisent pour converger en général
      new_pagerank = {node: (1 - damping_factor) / len(G.nodes) for node in G.nodes}  # Restart (facteur téléportation)

      for node in G.nodes:
          outgoing_links = df[df["source"] == node]
          total_links = len(outgoing_links)

          if total_links > 0:
              pr_to_distribute = pagerank[node] * damping_factor  # Part qui va partir de cette URL

              follow_links = outgoing_links[~outgoing_links["nofollow"]]
              nb_follow_links = len(follow_links)

              if nb_follow_links > 0:
                  share_per_link = pr_to_distribute / nb_follow_links  # Partage sur les liens follow
                  for _, row in follow_links.iterrows():
                      new_pagerank[row["target"]] += share_per_link  # On crédite uniquement les liens follow

      pagerank = new_pagerank  # Mise à jour pour la prochaine itération

  # 4. Conversion en DataFrame et affichage avec Google Colab
  return pd.DataFrame(pagerank.items(), columns=["URL", "PageRank"])

data = {
    "source": ["home", "home", "B", "C"],
    "target": ["B", "C", "home", "home"],
    "nofollow": [0, 0, 0, 0]  # 1 = nofollow (le lien ne transmet pas de PageRank)
}
pri = calcul_pagerank(data)
print(pri)