ajout tp n°2
This commit is contained in:
284
TP_2.ipynb
Normal file
284
TP_2.ipynb
Normal file
@@ -0,0 +1,284 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Séance 2 — Parcours & distances (BFS / DFS)\n",
|
||||
"\n",
|
||||
"## Objectifs pédagogiques\n",
|
||||
"- Comprendre les notions de **chemin**, **distance** et ** composantes connexes**.\n",
|
||||
"- Distinguer **BFS** (parcours en largeur) et **DFS** (parcours en profondeur).\n",
|
||||
"- Utiliser `networkx` pour calculer des plus courts chemins dans un graphe **non pondéré**.\n",
|
||||
"- Relier les distances à des interprétations sociologiques (proximité, relais, \"six degrés\").\n",
|
||||
"\n",
|
||||
"## Rappels\n",
|
||||
"- Dans un **graphe non pondéré**, un **plus court chemin** est le chemin avec le **moins d'arêtes**.\n",
|
||||
"- **BFS** explore par **couches** (distance croissante) et permet de trouver un plus court chemin.\n",
|
||||
"- **DFS** explore en **profondeur** (par branches) ; utile pour détecter des cycles/composantes mais **ne garantit pas** un plus court chemin.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# %pip install networkx matplotlib\n",
|
||||
"\n",
|
||||
"import networkx as nx\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"from collections import deque"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1) Graphe de départ : petit réseau social"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Vous pouvez modifier/étendre ce graphe\n",
|
||||
"G = nx.Graph()\n",
|
||||
"G.add_edges_from([\n",
|
||||
" (\"Alice\",\"Bob\"),\n",
|
||||
" (\"Bob\",\"Claire\"),\n",
|
||||
" (\"Claire\",\"Emma\"),\n",
|
||||
" (\"Alice\",\"David\"),\n",
|
||||
" (\"David\",\"Emma\"),\n",
|
||||
" (\"Emma\",\"Fanny\"),\n",
|
||||
" (\"Bob\",\"Gaston\"),\n",
|
||||
"])\n",
|
||||
"\n",
|
||||
"# Visualisation simple\n",
|
||||
"plt.figure()\n",
|
||||
"nx.draw(G, with_labels=True)\n",
|
||||
"plt.show()\n",
|
||||
"\n",
|
||||
"print(\"Nœuds :\", list(G.nodes()))\n",
|
||||
"print(\"Arêtes:\", list(G.edges()))\n",
|
||||
"print(\"Composantes connexes:\", nx.number_connected_components(G))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Question :** Y a-t-il un unique groupe connecté, ou plusieurs ? Impact sociologique : des individus isolés auront des distances infinies vers le reste."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2) Plus courts chemins et distances avec NetworkX"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"source, cible = \"Alice\", \"Fanny\"\n",
|
||||
"chemin = nx.shortest_path(G, source=source, target=cible) # plus court chemin (non pondéré)\n",
|
||||
"dist = nx.shortest_path_length(G, source=source, target=cible)\n",
|
||||
"print(f\"Plus court chemin de {source} à {cible} :\", chemin)\n",
|
||||
"print(f\"Distance (nombre d'arêtes) :\", dist)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Exercice 2.1** : testez 3 autres paires (par ex. `('Gaston','Fanny')`, `('Alice','Claire')`, `('David','Bob')`).\n",
|
||||
"\n",
|
||||
"**Exercice 2.2** : si vous supprimez l'arête `('David','Emma')`, que devient la distance `Alice→Fanny` ?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3) Implémenter un BFS pédagogique (pour comprendre l'ordre d'exploration)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def bfs_layers(graph, start):\n",
|
||||
" \"\"\"Retourne l'ordre de visite et les couches de distance (dict: noeud -> distance)\n",
|
||||
" BFS avec file d'attente (deque).\n",
|
||||
" \"\"\"\n",
|
||||
" visited = set([start])\n",
|
||||
" dist = {start: 0}\n",
|
||||
" order = []\n",
|
||||
" q = deque([start])\n",
|
||||
"\n",
|
||||
" while q:\n",
|
||||
" u = q.popleft()\n",
|
||||
" order.append(u)\n",
|
||||
" for v in graph.neighbors(u):\n",
|
||||
" if v not in visited:\n",
|
||||
" visited.add(v)\n",
|
||||
" dist[v] = dist[u] + 1\n",
|
||||
" q.append(v)\n",
|
||||
" return order, dist\n",
|
||||
"\n",
|
||||
"order, dist = bfs_layers(G, \"Alice\")\n",
|
||||
"print(\"Ordre BFS depuis Alice:\", order)\n",
|
||||
"print(\"Distances depuis Alice:\", dist)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Exercice 3.1** : Comparez les **distances** renvoyées par `bfs_layers` et `nx.shortest_path_length` pour 3 nœuds.\n",
|
||||
"\n",
|
||||
"**Exercice 3.2** : Quel nœud est le plus proche (distance minimale) d'**Alice** ? Le plus lointain ?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4) Implémenter un DFS (ordre d'exploration par branches)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def dfs_order(graph, start, visited=None, order=None):\n",
|
||||
" if visited is None: visited = set()\n",
|
||||
" if order is None: order = []\n",
|
||||
" visited.add(start)\n",
|
||||
" order.append(start)\n",
|
||||
" for v in graph.neighbors(start):\n",
|
||||
" if v not in visited:\n",
|
||||
" dfs_order(graph, v, visited, order)\n",
|
||||
" return order\n",
|
||||
"\n",
|
||||
"print(\"Ordre DFS depuis Alice:\", dfs_order(G, \"Alice\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Exercice 4.1** : Pourquoi **l'ordre DFS** diffère-t-il souvent de l'ordre BFS ?\n",
|
||||
"\n",
|
||||
"**Exercice 4.2** : DFS trouve-t-il un plus court chemin ? Expliquez avec un contre-exemple si possible."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5) Distances globales : diamètre & distance moyenne (si connexe)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if nx.is_connected(G):\n",
|
||||
" # Diamètre = plus longue distance entre deux nœuds\n",
|
||||
" d = nx.diameter(G)\n",
|
||||
" # Distance moyenne (longueur moyenne des plus courts chemins)\n",
|
||||
" apl = nx.average_shortest_path_length(G)\n",
|
||||
" print(\"Diamètre:\", d)\n",
|
||||
" print(\"Distance moyenne:\", apl)\n",
|
||||
"else:\n",
|
||||
" print(\"Le graphe n'est pas connexe : diamètre et distance moyenne ne sont pas définis globalement.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Exercice 5.1** : Ajoutez/supprimez une arête et observez l'effet sur la distance moyenne. Interprétez sociologiquement (ex. apparition d'un **pont** qui réduit les distances)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 6) Étude guidée : \"six degrés de séparation\" (mini-expérience)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Construisons un graphe en anneau + quelques liens longue portée pour réduire drastiquement les distances\n",
|
||||
"H = nx.cycle_graph(12) # 12 individus en cercle (0..11)\n",
|
||||
"H = nx.relabel_nodes(H, {i: f\"P{i}\" for i in range(12)})\n",
|
||||
"H.add_edge(\"P0\",\"P6\") # raccourci longue portée\n",
|
||||
"H.add_edge(\"P3\",\"P9\") # autre raccourci\n",
|
||||
"\n",
|
||||
"plt.figure()\n",
|
||||
"nx.draw(H, with_labels=True)\n",
|
||||
"plt.show()\n",
|
||||
"\n",
|
||||
"print(\"Connexe:\", nx.is_connected(H))\n",
|
||||
"print(\"Distance moyenne:\", nx.average_shortest_path_length(H))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Questions**\n",
|
||||
"1. Que se passe-t-il si on **retire** les liens longue portée ?\n",
|
||||
"2. Pourquoi quelques liens inter-groupes peuvent-ils **réduire fortement** les distances ?\n",
|
||||
"3. Donnez une interprétation en termes de diffusion d'une rumeur/idée."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 7) Synthèse écrite\n",
|
||||
"- Comparez BFS et DFS sur votre graphe.\n",
|
||||
"- Donnez 2 exemples de distances pertinentes en sociologie (ex. accès à l'information, recrutement).\n",
|
||||
"- Proposez une **hypothèse** : l'ajout d'un lien entre deux groupes réduira X ; comment le tester ?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "75d566ac",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python",
|
||||
"version": "3.x"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in New Issue
Block a user