573 lines
23 KiB
Plaintext
573 lines
23 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# 🧮 Séance 2 — Représenter un graphe : matrice, liste d'adjacence, incidence\n",
|
||
"\n",
|
||
"## Objectifs pédagogiques\n",
|
||
"À la fin de cette séance, vous serez capables de :\n",
|
||
"- représenter un graphe à l'aide d'une **matrice d'adjacence** et d'une **liste d'adjacence** ;\n",
|
||
"- représenter un graphe à l'aide d'une **matrice/liste d'incidence** (sommets × arêtes) ;\n",
|
||
"- choisir la représentation la plus adaptée selon la taille et la densité d'un réseau ;\n",
|
||
"- interpréter les liens sociaux à partir de ces représentations ;\n",
|
||
"- comprendre la **symétrie**, le **degré** et les **liens indirects** dans un réseau ;\n",
|
||
"- construire et explorer ces représentations avec **Python**."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Introduction\n",
|
||
"En sociologie, on cherche souvent à représenter **les relations entre individus** : qui connaît qui, qui travaille avec qui, qui échange le plus, etc.\n",
|
||
"\n",
|
||
"Un **graphe** permet de modéliser ces interactions :\n",
|
||
"- **nœuds (ou sommets)** → les individus\n",
|
||
"- **arêtes (ou liens)** → les relations entre eux\n",
|
||
"\n",
|
||
"Mais il existe plusieurs manières, plus mathématiques, de représenter ces relations : la **matrice d'adjacence**, la **liste d'adjacence**, et la **matrice/liste d'incidence**. Chacune a ses avantages selon la taille du réseau et ce qu'on veut en faire."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Définition\n",
|
||
"Pour un graphe $G = (V, E)$ à *n* sommets, la **matrice d'adjacence** $A$ est une matrice carrée *n × n* où :\n",
|
||
"\n",
|
||
"$$A_{ij} = \\begin{cases}1 & \\text{si une arête relie le sommet } i \\text{ au sommet } j \\\\0 & \\text{sinon}\\end{cases}$$\n",
|
||
"\n",
|
||
"- Dans un **graphe non dirigé**, $A$ est **symétrique** : $A_{ij} = A_{ji}$\n",
|
||
"- Dans un **graphe dirigé**, $A$ peut être **asymétrique** : $A_{ij} = 1$ ne signifie pas forcément $A_{ji} = 1$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Partie 1 — Représentation papier\n",
|
||
"### 1. Graphe de départ\n",
|
||
"Voici un petit réseau d'amitié entre cinq personnes :\n",
|
||
"\n",
|
||
"```\n",
|
||
"Alice — Bob — Claire\n",
|
||
" │ │\n",
|
||
" David Emma\n",
|
||
"```\n",
|
||
"\n",
|
||
"**Consigne :**\n",
|
||
"1. Listez les sommets : `Alice, Bob, Claire, David, Emma`.\n",
|
||
"2. Complétez la matrice d'adjacence correspondante :\n",
|
||
"\n",
|
||
"| | Alice | Bob | Claire | David | Emma |\n",
|
||
"|:------|:------:|:---:|:------:|:------:|:----:|\n",
|
||
"| Alice | 0 | | | | |\n",
|
||
"| Bob | | 0 | | | |\n",
|
||
"| Claire| | | 0 | | |\n",
|
||
"| David | | | | 0 | |\n",
|
||
"| Emma | | | | | 0 |\n",
|
||
"\n",
|
||
"(Remplissez avec des 1 là où il existe un lien.)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 2. Questions d'analyse\n",
|
||
"1. Quel est le **degré** de chaque individu (combien de liens possède-t-il) ?\n",
|
||
"2. Quel est l'individu le plus **central** dans ce réseau ?\n",
|
||
"3. Si on ajoute un lien entre *David* et *Emma*, comment la matrice change-t-elle ?\n",
|
||
"4. Que signifie le fait que la matrice soit **symétrique** ?\n",
|
||
"5. En sociologie, que représenterait une matrice **non symétrique** ? (donnez un exemple concret)\n",
|
||
"\n",
|
||
"**Explication :**\n",
|
||
"\n",
|
||
"- Une matrice **symétrique** signifie que les relations sont **réciproques** : si Alice est amie avec Bob, Bob l'est aussi avec Alice. Cela correspond à des relations mutuelles (amitié, collaboration, parenté, etc.).\n",
|
||
"- Une matrice **non symétrique** représente des relations **non réciproques** : par exemple, *A suit B* sur Twitter, *A cite B* dans un article scientifique, ou *A supervise B* dans une organisation."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Partie 2 — Exploration Python"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"metadata": {},
|
||
"execution_count": null,
|
||
"outputs": [],
|
||
"source": [
|
||
"import networkx as nx\n",
|
||
"import numpy as np\n",
|
||
"import matplotlib.pyplot as plt"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 1. Créer et afficher la matrice"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"metadata": {},
|
||
"execution_count": null,
|
||
"outputs": [],
|
||
"source": [
|
||
"G = nx.Graph()\n",
|
||
"G.add_edges_from([\n",
|
||
" (\"Alice\",\"Bob\"),\n",
|
||
" (\"Bob\",\"Claire\"),\n",
|
||
" (\"Alice\",\"David\"),\n",
|
||
" (\"Bob\",\"Emma\")\n",
|
||
"])\n",
|
||
"\n",
|
||
"# Obtenir la matrice d'adjacence\n",
|
||
"A = nx.to_numpy_array(G, nodelist=G.nodes())\n",
|
||
"print(list(G.nodes()))\n",
|
||
"print(A.astype(int))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 2. Visualiser le graphe"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"metadata": {},
|
||
"execution_count": null,
|
||
"outputs": [],
|
||
"source": [
|
||
"plt.figure()\n",
|
||
"nx.draw(G, with_labels=True, node_color=\"lightblue\", node_size=1000)\n",
|
||
"plt.show()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 3. Explorer la structure du réseau"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"metadata": {},
|
||
"execution_count": null,
|
||
"outputs": [],
|
||
"source": [
|
||
"# Degré de chaque sommet\n",
|
||
"print(\"Degré de chaque individu :\", dict(G.degree()))\n",
|
||
"\n",
|
||
"# Densité du réseau (rapport entre liens existants et liens possibles)\n",
|
||
"print(\"Densité du réseau :\", round(nx.density(G), 2))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 4. Liens indirects : le carré de la matrice"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"metadata": {},
|
||
"execution_count": null,
|
||
"outputs": [],
|
||
"source": [
|
||
"A2 = np.linalg.matrix_power(A, 2)\n",
|
||
"print(\"A² =\\n\", A2.astype(int))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Interprétation :\n",
|
||
"- Si `A²[i][j] > 0`, cela signifie qu'il existe **un ami commun** entre les nœuds *i* et *j*.\n",
|
||
"- En sociologie : cela mesure les **liens indirects**, c'est-à-dire les \"amis d'amis\"."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Pourquoi ne met-on pas les éléments eux-mêmes au carré ?\n",
|
||
"\n",
|
||
"Quand on écrit **A²**, cela signifie **A × A**, c'est-à-dire qu'on multiplie la matrice par elle-même selon les règles de la multiplication matricielle.\n",
|
||
"\n",
|
||
"On ne calcule **pas** $(A_{ij})^2$, car cela n'aurait aucun intérêt :\n",
|
||
"- $0^2 = 0$ et $1^2 = 1$, donc la matrice ne changerait pas.\n",
|
||
"- Le but du carré matriciel est de compter **les chemins de longueur 2** entre les nœuds.\n",
|
||
"\n",
|
||
"Formellement :\n",
|
||
"$$A^2_{ij} = \\sum_k A_{ik} \\times A_{kj}$$\n",
|
||
"\n",
|
||
"Cela signifie que $A^2_{ij}$ indique combien de façons il existe d'aller du nœud *i* au nœud *j* en passant par **exactement un autre nœud**.\n",
|
||
"\n",
|
||
"**Exemple :**\n",
|
||
"Si $A =$\n",
|
||
"$$\n",
|
||
"\\begin{bmatrix}\n",
|
||
"0 & 1 & 0 \\\\\n",
|
||
"1 & 0 & 1 \\\\\n",
|
||
"0 & 1 & 0\n",
|
||
"\\end{bmatrix}\n",
|
||
"$$\n",
|
||
"alors $A^2 =$\n",
|
||
"$$\n",
|
||
"\\begin{bmatrix}\n",
|
||
"1 & 0 & 1 \\\\\n",
|
||
"0 & 2 & 0 \\\\\n",
|
||
"1 & 0 & 1\n",
|
||
"\\end{bmatrix}\n",
|
||
"$$\n",
|
||
"\n",
|
||
"- $A^2_{13} = 1$ : il existe un chemin de longueur 2 entre 1 et 3 (en passant par 2).\n",
|
||
"- $A^2_{22} = 2$ : le sommet 2 a deux chemins de longueur 2 qui reviennent à lui-même.\n",
|
||
"\n",
|
||
"**Résumé :**\n",
|
||
"\n",
|
||
"| Calcul | Signification | Utilité |\n",
|
||
"|:--------|:--------------|:--------|\n",
|
||
"| $(A_{ij})^2$ | Élève chaque case au carré | Inutile (0 et 1 inchangés) |\n",
|
||
"| $A^2 = A × A$ | Produit matriciel | Donne les **liens indirects** (chemins de longueur 2) |"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Partie 3 — Liste d'adjacence\n",
|
||
"\n",
|
||
"La matrice d'adjacence a un défaut : pour un réseau de 500 personnes, elle contient 500 × 500 = 250 000 cases, même si chacune n'a que 10 amis en moyenne (la plupart des cases valent alors 0). Or les réseaux sociaux réels sont presque toujours **creux** (*sparse*) : chaque individu ne connaît qu'une petite fraction du groupe.\n",
|
||
"\n",
|
||
"La **liste d'adjacence** répond à ce problème : au lieu d'une grille, on associe à **chaque sommet la liste de ses voisins**. On ne stocke que les liens qui existent réellement.\n",
|
||
"\n",
|
||
"$$\\text{Alice} \\rightarrow [\\text{Bob}, \\text{David}]$$\n",
|
||
"$$\\text{Bob} \\rightarrow [\\text{Alice}, \\text{Claire}, \\text{Emma}]$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 1. Construire la liste d'adjacence"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"metadata": {},
|
||
"execution_count": null,
|
||
"outputs": [],
|
||
"source": [
|
||
"# NetworkX construit directement la liste d'adjacence à partir du graphe G\n",
|
||
"liste_adjacence = nx.to_dict_of_lists(G)\n",
|
||
"\n",
|
||
"for personne, amis in liste_adjacence.items():\n",
|
||
" print(f\"{personne} → {amis}\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 2. Comparer matrice et liste d'adjacence\n",
|
||
"\n",
|
||
"**Questions :**\n",
|
||
"1. Combien de \"cases\" contient la matrice d'adjacence de ce petit réseau à 5 personnes ? Combien de liens contient la liste d'adjacence ?\n",
|
||
"2. Pour un réseau de 10 000 personnes où chacune a en moyenne 50 ami·es, quelle représentation prendrait le moins de mémoire ?\n",
|
||
"3. Pour répondre rapidement à la question *\"Alice et Emma sont-elles amies ?\"*, quelle représentation est la plus directe ?\n",
|
||
"4. Pour répondre à *\"quels sont les ami·es de Bob ?\"*, quelle représentation est la plus directe ?\n",
|
||
"\n",
|
||
"**En résumé :** la matrice d'adjacence est pratique pour les calculs matriciels (comme $A^2$) et les réseaux **denses**. La liste d'adjacence est plus économe en mémoire et plus rapide à parcourir pour les réseaux **creux** — c'est-à-dire la grande majorité des réseaux sociaux réels."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Partie 4 — Matrice et liste d'incidence\n",
|
||
"\n",
|
||
"Les représentations précédentes croisent des **sommets avec des sommets** (qui est relié à qui). La **matrice d'incidence** change de point de vue : elle croise des **sommets avec des arêtes** (quel individu est concerné par quelle relation).\n",
|
||
"\n",
|
||
"Pour un graphe à *n* sommets et *m* arêtes, la matrice d'incidence $B$ est une matrice *n × m* où :\n",
|
||
"\n",
|
||
"$$B_{ie} = \\begin{cases}1 & \\text{si le sommet } i \\text{ est une extrémité de l'arête } e \\\\0 & \\text{sinon}\\end{cases}$$\n",
|
||
"\n",
|
||
"Chaque **colonne** représente donc une relation (une arête), avec exactement deux 1 : ses deux extrémités.\n",
|
||
"\n",
|
||
"Cette idée rejoint celle du **graphe biparti** vue en Introduction (COURS.md — individus ↔ opinions, individus ↔ événements) : on peut voir la matrice d'incidence comme \"qui participe à quelle relation\", exactement comme on notait \"qui participe à quel événement\"."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 1. Construire la matrice d'incidence"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"metadata": {},
|
||
"execution_count": null,
|
||
"outputs": [],
|
||
"source": [
|
||
"# Construction manuelle de la matrice d'incidence avec numpy\n",
|
||
"# (une colonne par arête, deux 1 par colonne : les deux extrémités)\n",
|
||
"liste_aretes = list(G.edges())\n",
|
||
"sommets = list(G.nodes())\n",
|
||
"\n",
|
||
"B = np.zeros((len(sommets), len(liste_aretes)), dtype=int)\n",
|
||
"for colonne, (u, v) in enumerate(liste_aretes):\n",
|
||
" B[sommets.index(u), colonne] = 1\n",
|
||
" B[sommets.index(v), colonne] = 1\n",
|
||
"\n",
|
||
"print(\"Arêtes (colonnes) :\", liste_aretes)\n",
|
||
"print(sommets)\n",
|
||
"print(B)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Interprétation : chaque colonne de $B$ contient exactement deux 1, ceux des deux personnes impliquées dans cette relation. Une ligne \"pleine de 0\" signifierait un individu isolé, qui n'apparaît dans aucune relation.\n",
|
||
"\n",
|
||
"### 2. Liste d'incidence\n",
|
||
"\n",
|
||
"De la même façon qu'on a allégé la matrice d'adjacence en liste d'adjacence, on peut alléger la matrice d'incidence : au lieu d'une grille sommets × arêtes, on liste simplement, pour chaque arête, ses deux extrémités. C'est en fait exactement ce que renvoie `G.edges()` :"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"metadata": {},
|
||
"execution_count": null,
|
||
"outputs": [],
|
||
"source": [
|
||
"# La liste d'incidence : pour chaque arête, ses deux extrémités\n",
|
||
"for i, (u, v) in enumerate(G.edges()):\n",
|
||
" print(f\"Arête {i} : {u} — {v}\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"**Application sociologique :** cette matrice sommets × arêtes met en avant les relations elles-mêmes plutôt que les individus. En pratique, en sociologie, elle reste peu utilisée : elle contient exactement la même information que la matrice d'adjacence, sous une forme plus encombrante.\n",
|
||
"\n",
|
||
"> ⚠️ **Attention à un piège de vocabulaire.** En analyse des réseaux sociaux, on appelle aussi « matrice d'incidence » un objet **différent** : une matrice **individus × événements**. Ce n'est pas la même chose que la matrice sommets × arêtes ci-dessus, et c'est celle-là qui est vraiment utile au sociologue. C'est l'objet de la partie 5."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Partie 5 — L'incidence utile au sociologue : individus × événements\n",
|
||
"\n",
|
||
"### 1. Pourquoi changer d'objet\n",
|
||
"\n",
|
||
"Dans la partie 4, chaque colonne représentait une **arête** et contenait donc exactement deux 1 : les deux extrémités de la relation.\n",
|
||
"\n",
|
||
"Mais en sociologie, **on n'observe presque jamais les liens directement**. On n'a pas la liste des amitiés : on a des listes de présence. Qui siège dans quel conseil d'administration, qui signe quelle pétition, qui assiste à quelle réunion, qui adhère à quelle association.\n",
|
||
"\n",
|
||
"On construit alors une matrice $B$ de taille *individus × événements* :\n",
|
||
"\n",
|
||
"$$B_{ie} = \\begin{cases}1 & \\text{si l'individu } i \\text{ participe à l'événement } e \\\\ 0 & \\text{sinon}\\end{cases}$$\n",
|
||
"\n",
|
||
"**La différence est structurelle :** une colonne n'est plus une arête mais un événement, et elle contient autant de 1 qu'il y a de participants. Une réunion à cinq personnes donne une colonne à cinq 1.\n",
|
||
"\n",
|
||
"C'est ce que Breiger (1974) appelle la **dualité des personnes et des groupes** : les individus sont reliés par les événements qu'ils partagent, et les événements sont reliés par les individus qu'ils rassemblent."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 2. Construire la matrice d'affiliation\n",
|
||
"\n",
|
||
"Reprenons nos cinq personnes, mais en observant cette fois leurs **participations** à quatre événements associatifs, et non plus leurs amitiés."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"personnes = [\"Alice\", \"Bob\", \"Claire\", \"David\", \"Emma\"]\n",
|
||
"evenements = [\"Réunion A\", \"Atelier B\", \"Sortie C\", \"Conseil D\"]\n",
|
||
"\n",
|
||
"participations = {\n",
|
||
" \"Alice\": [\"Réunion A\", \"Atelier B\"],\n",
|
||
" \"Bob\": [\"Réunion A\", \"Conseil D\"],\n",
|
||
" \"Claire\": [\"Atelier B\", \"Sortie C\", \"Conseil D\"],\n",
|
||
" \"David\": [\"Atelier B\", \"Sortie C\", \"Conseil D\"],\n",
|
||
" \"Emma\": [\"Sortie C\"],\n",
|
||
"}\n",
|
||
"\n",
|
||
"B = np.zeros((len(personnes), len(evenements)), dtype=int)\n",
|
||
"for i, personne in enumerate(personnes):\n",
|
||
" for evenement in participations[personne]:\n",
|
||
" B[i, evenements.index(evenement)] = 1\n",
|
||
"\n",
|
||
"print(\"Colonnes :\", evenements)\n",
|
||
"print(personnes)\n",
|
||
"print(B)\n",
|
||
"print()\n",
|
||
"print(\"Nombre de 1 par colonne :\", B.sum(axis=0))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Observez la dernière ligne : les colonnes somment à 2, 3, 3 et 3, et non à 2 partout. C'est la preuve concrète qu'il ne s'agit **pas** de la matrice sommets × arêtes de la partie 4."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 3. La projection : transformer des co-présences en réseau\n",
|
||
"\n",
|
||
"Voici l'opération qui rend cette matrice utile. Deux produits matriciels suffisent :\n",
|
||
"\n",
|
||
"- $C = B \\, B^{T}$ est une matrice **individus × individus** : $C_{ij}$ compte les événements que $i$ et $j$ ont en commun ;\n",
|
||
"- $D = B^{T} B$ est une matrice **événements × événements** : $D_{ef}$ compte les personnes présentes à la fois en $e$ et en $f$.\n",
|
||
"\n",
|
||
"Autrement dit, on part de données d'affiliation, qui sont ce qu'on collecte réellement, et on en déduit un réseau interpersonnel, qui est ce qu'on veut analyser."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"C = B @ B.T # individus × individus\n",
|
||
"D = B.T @ B # événements × événements\n",
|
||
"\n",
|
||
"print(\"C = B @ B.T (individus × individus)\")\n",
|
||
"print(personnes)\n",
|
||
"print(C)\n",
|
||
"print()\n",
|
||
"\n",
|
||
"print(\"Nombre d'événements par personne (diagonale de C) :\")\n",
|
||
"for i, personne in enumerate(personnes):\n",
|
||
" print(f\" {personne} : {C[i, i]}\")\n",
|
||
"print()\n",
|
||
"\n",
|
||
"print(\"Co-participations (hors diagonale) :\")\n",
|
||
"for i in range(len(personnes)):\n",
|
||
" for j in range(i + 1, len(personnes)):\n",
|
||
" if C[i, j] > 0:\n",
|
||
" print(f\" {personnes[i]} et {personnes[j]} : {C[i, j]} événement(s) en commun\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"### 4. Lecture sociologique\n",
|
||
"\n",
|
||
"Deux choses se lisent directement dans $C$ :\n",
|
||
"\n",
|
||
"- **la diagonale** donne le nombre d'événements de chacun, c'est-à-dire son **degré d'engagement** dans la vie collective. Emma en a 1, Claire et David en ont 3 ;\n",
|
||
"- **les valeurs hors diagonale** mesurent la force du lien indirect. Claire et David partagent **3 événements** : c'est le lien le plus fort du réseau.\n",
|
||
"\n",
|
||
"Or, si vous remontez au graphe d'amitié du début de la séance, **Claire et David ne sont reliés par aucune arête**. Leur proximité est totalement invisible dans la matrice d'adjacence, et elle saute aux yeux dans la projection.\n",
|
||
"\n",
|
||
"C'est exactement ce que le sociologue cherche : des liens que les acteurs ne déclarent pas, mais que leurs pratiques révèlent.\n",
|
||
"\n",
|
||
"> **Attention à l'interprétation.** Partager trois réunions ne prouve pas qu'on se connaisse, encore moins qu'on s'apprécie. La projection produit une **hypothèse** de lien, à confronter à d'autres sources. Deux personnes peuvent siéger dans le même conseil sans s'être jamais adressé la parole."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"print(\"D = B.T @ B (événements × événements)\")\n",
|
||
"print(evenements)\n",
|
||
"print(D)\n",
|
||
"print()\n",
|
||
"print(\"Nombre de participants par événement (diagonale de D) :\")\n",
|
||
"for e, evenement in enumerate(evenements):\n",
|
||
" print(f\" {evenement} : {D[e, e]}\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"La matrice $D$ se lit symétriquement : deux événements qui partagent beaucoup de participants relèvent probablement du **même milieu**. C'est ainsi qu'on repère, par exemple, que certaines instances recrutent dans le même vivier."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Synthèse\n",
|
||
"| Concept mathématique | Interprétation sociologique |\n",
|
||
"|:----------------------|:----------------------------|\n",
|
||
"| 1 dans la matrice d'adjacence | lien direct entre deux individus |\n",
|
||
"| 0 dans la matrice d'adjacence | absence de lien |\n",
|
||
"| somme d'une ligne (matrice) / longueur d'une liste (liste d'adjacence) | degré (popularité / nombre de connexions) |\n",
|
||
"| symétrie | réciprocité des relations |\n",
|
||
"| $A^2$ | existence de relations indirectes |\n",
|
||
"| densité | cohésion du groupe |\n",
|
||
"| liste d'adjacence | représentation compacte, adaptée aux réseaux creux (la plupart des réseaux sociaux réels) |\n",
|
||
"| matrice/liste d'incidence (sommets × arêtes) | met en avant les relations elles-mêmes ; même information que l'adjacence, sous une forme plus lourde |\n",
|
||
"| matrice d'affiliation (individus × événements) | données réellement collectées : qui participe à quoi |\n",
|
||
"| $B B^{T}$ | co-participations : force du lien indirect entre deux individus |\n",
|
||
"| $B^{T} B$ | proximité entre événements : recrutent-ils dans le même milieu ? |\n",
|
||
"\n",
|
||
"| Représentation | Taille | Adaptée à |\n",
|
||
"|:-----------------|:--------|:-----------|\n",
|
||
"| Matrice d'adjacence | *n × n* | petits réseaux, réseaux denses, calculs matriciels |\n",
|
||
"| Liste d'adjacence | proportionnelle au nombre de liens | grands réseaux creux (cas le plus fréquent) |\n",
|
||
"| Matrice/liste d'incidence | *n × m* (sommets × arêtes) | surtout théorique ; peu utilisée en sociologie |\n",
|
||
"| Matrice d'affiliation | *n × p* (individus × événements) | réseaux à deux modes : présences, adhésions, signatures |"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Questions de réflexion\n",
|
||
"1. En quoi la matrice d'adjacence permet-elle de **quantifier** un réseau social ?\n",
|
||
"2. Si une matrice est très dense, que peut-on en conclure sur le **type de groupe** étudié ?\n",
|
||
"3. Comment pourriez-vous pondérer les liens dans cette matrice pour représenter l'**intensité** des relations ?\n",
|
||
"4. Vous devez analyser le réseau de tou·tes les utilisateur·rices d'un réseau social (des millions de personnes, chacune avec quelques centaines d'ami·es en moyenne). Justifiez votre choix entre matrice et liste d'adjacence.\n",
|
||
"5. Donnez un exemple d'enquête où vous disposeriez d'une matrice d'affiliation (individus × événements) plutôt que d'une matrice d'adjacence. Qu'apporterait la projection $B B^{T}$ dans ce cas ?\n",
|
||
"6. Claire et David ne sont reliés par aucune arête dans le graphe d'amitié, mais partagent trois événements. Comment interpréteriez-vous cela ? Quelles précautions prendre avant d'en conclure qu'elles et ils se connaissent ?"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Python 3",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"name": "python",
|
||
"pygments_lexer": "ipython3"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 4
|
||
}
|