Refonte du cours en 12 séances alignées sur le programme officiel
This commit is contained in:
190
Seance_10_PageRank_LabelPropagation.ipynb
Normal file
190
Seance_10_PageRank_LabelPropagation.ipynb
Normal file
@@ -0,0 +1,190 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 🔍 Séance 10 — Page-rank et propagation d'étiquettes\n",
|
||||
"\n",
|
||||
"## Objectifs pédagogiques\n",
|
||||
"À la fin de cette séance, vous serez capables de :\n",
|
||||
"- comprendre l'intuition de l'algorithme du **page-rank** et le calculer avec `networkx` ;\n",
|
||||
"- comprendre le principe de la **propagation d'étiquettes** (label propagation) pour détecter des communautés ;\n",
|
||||
"- relier ces deux algorithmes au reste du cours (centralité, diffusion par BFS).\n",
|
||||
"\n",
|
||||
"## Introduction\n",
|
||||
"En Séance 8, on a vu trois façons de mesurer l'importance d'un individu : le degré, la proximité, l'intermédiarité. Le **page-rank** en propose une quatrième, plus subtile : être suivi par une personne elle-même très suivie compte plus que d'être suivi par dix personnes obscures. C'est l'algorithme qui a fait le succès de Google pour classer les pages web (une page est importante si des pages elles-mêmes importantes pointent vers elle).\n",
|
||||
"\n",
|
||||
"La **propagation d'étiquettes**, elle, répond à une tout autre question : comment détecter automatiquement des **communautés** dans un réseau, sans les connaître à l'avance ? On retrouve ici l'idée de diffusion vue en Séance 5, mais appliquée différemment : au lieu de propager une information depuis une seule source, chaque personne adopte peu à peu l'étiquette majoritaire de son entourage."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Partie 1 — Page-rank\n",
|
||||
"\n",
|
||||
"Le principe intuitif est celui du **\"surfeur aléatoire\"** : imaginez une personne qui clique aléatoirement sur les liens d'une page web à l'autre, indéfiniment. Le page-rank d'une page est la probabilité qu'à un instant donné, le surfeur se trouve sur cette page. Une page reçoit un score d'autant plus élevé qu'elle est pointée par des pages elles-mêmes très visitées.\n",
|
||||
"\n",
|
||||
"Transposé à un réseau social, cela devient : *qui suit qui* est une arête **orientée**, et le page-rank d'une personne dépend de la quantité **et de la qualité** de celles et ceux qui la suivent."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Un réseau de \"qui suit qui\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {},
|
||||
"execution_count": null,
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import networkx as nx\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"# Graphe orienté : une arête A -> B signifie \"A suit B\"\n",
|
||||
"G = nx.DiGraph()\n",
|
||||
"G.add_edges_from([\n",
|
||||
" (\"Bob\", \"Alice\"),\n",
|
||||
" (\"David\", \"Alice\"),\n",
|
||||
" (\"Emma\", \"Alice\"),\n",
|
||||
" (\"Alice\", \"Chloé\"), # Alice, très suivie, suit aussi Chloé\n",
|
||||
"])\n",
|
||||
"\n",
|
||||
"plt.figure()\n",
|
||||
"pos = nx.spring_layout(G, seed=0)\n",
|
||||
"nx.draw(G, pos, with_labels=True, node_color=\"lightblue\", node_size=1200, arrows=True, arrowsize=20)\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Calculer le page-rank\n",
|
||||
"\n",
|
||||
"NetworkX calcule directement le page-rank de chaque sommet.\n",
|
||||
"\n",
|
||||
"> Si vous obtenez `ModuleNotFoundError: No module named 'scipy'`, exécutez d'abord `%pip install scipy` dans une cellule, puis relancez."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {},
|
||||
"execution_count": null,
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"pr = nx.pagerank(G)\n",
|
||||
"for personne, score in sorted(pr.items(), key=lambda x: -x[1]):\n",
|
||||
" print(f\"{personne} : {round(score, 3)}\")\n",
|
||||
"\n",
|
||||
"print(\"\\nPour comparaison, degré entrant (nombre de personnes qui suivent) :\")\n",
|
||||
"for personne, deg in sorted(G.in_degree(), key=lambda x: -x[1]):\n",
|
||||
" print(f\"{personne} : {deg}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Interprétation :** Alice a 3 personnes qui la suivent (Bob, David, Emma), mais Chloé n'en a qu'**une seule** — Alice elle-même. Pourtant, le page-rank de Chloé dépasse celui d'Alice ! C'est exactement l'idée du \"surfeur aléatoire\" : être suivi par une seule personne très centrale (Alice, qui concentre le trafic entrant du réseau) rapporte plus que d'être suivi par plusieurs personnes elles-mêmes peu suivies.\n",
|
||||
"\n",
|
||||
"**Questions :**\n",
|
||||
"1. Le classement par page-rank est-il le même que le classement par simple degré entrant ? Que montre cette différence ?\n",
|
||||
"2. Si Bob, David et Emma se mettaient aussi à suivre Chloé (en plus d'Alice), que deviendrait le page-rank de Chloé ?\n",
|
||||
"3. En quoi ce principe rejoint-il la centralité d'intermédiarité vue en Séance 8 (une position stratégique compte plus qu'un grand nombre de liens) ?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Partie 2 — Propagation d'étiquettes (détection de communautés)\n",
|
||||
"\n",
|
||||
"**Principe :** au départ, chaque personne a sa propre étiquette (son nom). À chaque étape, chaque personne adopte l'étiquette **la plus fréquente parmi ses voisin·es**. On répète jusqu'à ce que plus personne ne change d'étiquette. Les personnes qui finissent avec la même étiquette forment une **communauté** détectée automatiquement — sans qu'on ait eu besoin de la définir à l'avance.\n",
|
||||
"\n",
|
||||
"On reprend le réseau à 7 personnes des Séances 5 et 8."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {},
|
||||
"execution_count": null,
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from networkx.algorithms.community import asyn_lpa_communities\n",
|
||||
"\n",
|
||||
"H = nx.Graph()\n",
|
||||
"H.add_edges_from([\n",
|
||||
" ('Alice', 'Bob'), ('Alice', 'Emma'),\n",
|
||||
" ('Bob', 'Chloé'), ('Bob', 'Félix'),\n",
|
||||
" ('Chloé', 'David'), ('Chloé', 'Gaël')\n",
|
||||
"])\n",
|
||||
"\n",
|
||||
"communautes = list(asyn_lpa_communities(H, seed=3))\n",
|
||||
"for i, communaute in enumerate(communautes):\n",
|
||||
" print(f\"Communauté {i+1} : {sorted(communaute)}\")\n",
|
||||
"\n",
|
||||
"# Visualisation avec une couleur par communauté détectée\n",
|
||||
"palette = [\"lightblue\", \"lightgreen\", \"lightcoral\", \"khaki\"]\n",
|
||||
"couleur_par_personne = {}\n",
|
||||
"for i, communaute in enumerate(communautes):\n",
|
||||
" for personne in communaute:\n",
|
||||
" couleur_par_personne[personne] = palette[i]\n",
|
||||
"\n",
|
||||
"plt.figure()\n",
|
||||
"pos = nx.spring_layout(H, seed=0)\n",
|
||||
"nx.draw(H, pos, with_labels=True, node_size=1200,\n",
|
||||
" node_color=[couleur_par_personne[n] for n in H.nodes()])\n",
|
||||
"plt.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Interprétation :** l'algorithme retrouve automatiquement deux groupes : {Alice, Bob, Emma, Félix} d'un côté, {Chloé, David, Gaël} de l'autre — sans qu'on lui ait jamais dit où étaient les frontières. Remarquez que **Bob** se retrouve dans le groupe d'Alice alors qu'en Séance 8 il avait la plus forte centralité d'intermédiarité avec Chloé : la propagation d'étiquettes doit \"trancher\", même pour les personnes-ponts qui, dans la réalité, appartiennent un peu aux deux groupes à la fois.\n",
|
||||
"\n",
|
||||
"**Questions :**\n",
|
||||
"1. Réexécutez la cellule en changeant le `seed`. Le résultat change-t-il ? Que cela vous apprend-il sur la fiabilité de cet algorithme sur de petits réseaux ?\n",
|
||||
"2. Bob et Chloé, identifié·es comme \"ponts\" en Séance 5-8, se retrouvent chacun·e dans un groupe différent ici. Est-ce cohérent avec leur rôle de pont ? Pourquoi la méthode a-t-elle du mal à les classer ?\n",
|
||||
"3. Sur un réseau de plusieurs milliers de personnes, pourquoi la détection automatique de communautés est-elle plus utile qu'une lecture \"à l'œil\" du graphe ?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Synthèse\n",
|
||||
"\n",
|
||||
"| Algorithme | Question posée | Ce qu'il donne |\n",
|
||||
"|:------------|:------------------|:------------------|\n",
|
||||
"| Page-rank | Qui est important, en tenant compte de la qualité de ses connexions ? | Un score d'importance par personne |\n",
|
||||
"| Propagation d'étiquettes | Quels sous-groupes se dessinent naturellement dans ce réseau ? | Une partition du réseau en communautés |\n",
|
||||
"\n",
|
||||
"## Pour clore le cours\n",
|
||||
"Ce cours a parcouru tout le programme officiel de graphes : définitions et représentations (Séances 1-3), parcours et distances (Séances 4-5), graphes pondérés (Séances 6-7), et enfin ces mesures plus avancées (Séances 8-10). Un même fil rouge — un petit réseau social imaginaire — a servi de terrain d'expérimentation du début à la fin.\n",
|
||||
"\n",
|
||||
"**Questions de synthèse générale :**\n",
|
||||
"1. Parmi tous les algorithmes vus ce semestre (BFS, DFS, Dijkstra, centralité, coloration, page-rank, label propagation), lequel vous semble le plus directement utile pour un mémoire ou une enquête de sociologie ?\n",
|
||||
"2. Choisissez un phénomène social qui vous intéresse (mobilisation collective, diffusion d'une mode, ségrégation résidentielle...). Quel(s) outil(s) de ce cours utiliseriez-vous pour l'étudier, et pourquoi ?"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"pygments_lexer": "ipython3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
Reference in New Issue
Block a user