Cours
Pour vous initier à l’analyse de réseaux, suivez le cours Network Analysis in Python (Part 1) de DataCamp.
Les réseaux sont partout : réseaux routiers, réseau d’amis et d’abonnés sur les réseaux sociaux, réseau de collègues au bureau. Ils jouent un rôle majeur dans notre quotidien, de la diffusion d’informations utiles à l’influence sur des élections nationales. Savoir analyser ces réseaux et prendre des décisions éclairées à partir de ces analyses est une compétence essentielle pour tout analyste de données.
Ce tutoriel a pour objectif d’enseigner l’analyse des réseaux sociaux (SNA) avec Python et NetworkX, une bibliothèque Python dédiée à l’étude de la structure, de la dynamique et des fonctions des réseaux complexes. Nous supposons que vous connaissez la syntaxe de base de Python ; aucune connaissance préalable de la SNA n’est requise.
Introduction
Commençons par définir ce que nous entendons par réseaux sociaux. Ci-dessous, vous voyez un réseau où les acteurs de Bollywood sont des nœuds. Ils sont reliés par des traits pleins s’ils ont joué ensemble dans au moins un film.

On observe ainsi qu’Amitabh Bachchan et Abhishek Bachchan ont tourné avec tous les acteurs du réseau, tandis qu’Akshay Kumar n’a collaboré qu’avec les deux Bachchan. Intéressant, n’est-ce pas ?
Ceci est aussi un réseau social. Tout réseau reliant des individus, où les liens représentent la nature de leur relation, est un réseau social. L’analyse de ces réseaux permet de mieux comprendre les personnes qui les composent : qui influence réellement, qui est le plus connecté, etc.
Chaque réseau se compose de :
- Nœuds : les individus dont on modélise le réseau. Les acteurs dans l’exemple ci-dessus.
- Arêtes : les connexions entre nœuds. Elles représentent une relation entre les nœuds du réseau. Dans notre exemple, la relation est d’avoir joué ensemble.
Créer un réseau avec NetworkX
Il existe de nombreux types de réseaux. Nous allons utiliser NetworkX pour construire et analyser différents réseaux. Pour commencer, installez NetworkX : vous pouvez utiliser :
pip install networkx
ou, si vous travaillez avec Anaconda
conda install -c anaconda networkx
Cela installera la dernière version de NetworkX. Les exemples de ce tutoriel ont été réalisés avec Python 3.5 et NetworkX 2.0.
Réseaux symétriques
Le premier réseau d’acteurs présenté ci-dessus est symétrique, car la relation « jouer ensemble dans un film » est symétrique. Si A est lié à B, alors B est aussi lié à A. Recréons ce réseau dans NetworkX.
Nous utiliserons la méthode Graph() pour créer un nouveau réseau et add_edge() pour ajouter une arête entre deux nœuds.
import networkx as nx
G_symmetric = nx.Graph()
G_symmetric.add_edge('Amitabh Bachchan','Abhishek Bachchan')
G_symmetric.add_edge('Amitabh Bachchan','Aamir Khan')
G_symmetric.add_edge('Amitabh Bachchan','Akshay Kumar')
G_symmetric.add_edge('Amitabh Bachchan','Dev Anand')
G_symmetric.add_edge('Abhishek Bachchan','Aamir Khan')
G_symmetric.add_edge('Abhishek Bachchan','Akshay Kumar')
G_symmetric.add_edge('Abhishek Bachchan','Dev Anand')
G_symmetric.add_edge('Dev Anand','Aamir Khan')
Visualisons maintenant le réseau que nous venons de construire avec nx.draw_networkx(G_symmetric).

Maîtrisez vos compétences en matière de données avec DataCamp
Plus de 10 millions de personnes apprennent Python, R, SQL et d'autres compétences techniques grâce à nos cours pratiques élaborés par des experts du secteur.

Réseaux asymétriques
Si la relation entre nœuds est « enfant de », la relation n’est plus symétrique. Si A est l’enfant de B, alors B n’est pas l’enfant de A. Un réseau où la relation est asymétrique (A est lié à B, sans que B le soit nécessairement à A) est appelé réseau asymétrique. On peut construire un réseau asymétrique dans NetworkX avec la méthode DiGraph, pour Directed Graph. Créons un graphe asymétrique.
G_asymmetric = nx.DiGraph()
G_asymmetric.add_edge('A','B')
G_asymmetric.add_edge('A','D')
G_asymmetric.add_edge('C','A')
G_asymmetric.add_edge('D','E')
Visualisons-le. On peut utiliser la fonction draw_networkx() comme précédemment. Toutefois, il est possible que les nœuds ne soient pas suffisamment espacés et distincts. Pour y remédier, on peut imposer une disposition qui positionne les nœuds de façon plus lisible. On y parvient avec la fonction spring_layout(), suivie de draw_networkx().
nx.spring_layout(G_asymmetric)
nx.draw_networkx(G_asymmetric)
Ci-dessous, le réseau avec et sans commande de disposition. La version avec layout est plus claire.

Réseaux pondérés
Jusqu’ici, nos réseaux n’avaient pas de poids, mais il est possible d’en ajouter. Par exemple, si dans notre réseau initial nous considérons le nombre de films tournés ensemble comme un poids, nous obtenons un réseau pondéré. Recréons le réseau des acteurs en y ajoutant cette fois un poids à chaque arête représentant le nombre de films tournés ensemble.
G_weighted = nx.Graph()
G_weighted.add_edge('Amitabh Bachchan','Abhishek Bachchan', weight=25)
G_weighted.add_edge('Amitabh Bachchan','Aaamir Khan', weight=8)
G_weighted.add_edge('Amitabh Bachchan','Akshay Kumar', weight=11)
G_weighted.add_edge('Amitabh Bachchan','Dev Anand', weight=1)
G_weighted.add_edge('Abhishek Bachchan','Aaamir Khan', weight=4)
G_weighted.add_edge('Abhishek Bachchan','Akshay Kumar',weight=7)
G_weighted.add_edge('Abhishek Bachchan','Dev Anand', weight=1)
G_weighted.add_edge('Dev Anand','Aaamir Khan',weight=1)

La figure ci-dessus montre le réseau pondéré d’acteurs avec une disposition circular. L’épaisseur des arêtes indique le poids entre deux nœuds.
Multigraphe
On peut attribuer différents attributs aux arêtes. Par exemple, on peut définir une relation de voisinage entre deux nœuds « A » et « B » via l’attribut relation. Si, au sein d’un réseau, deux nœuds sont reliés par deux arêtes différentes (relations), on obtient un multigraphe. On peut créer un multigraphe avec la classe MultiGraph.
G = nx.MultiGraph()
G.add_edge('A','B',relation ='neighbor')
G.add_edge('A','B',relation='friend)
G.add_edge('B','C', relation='neighbor')
G.add_edge('D','C',relation='friend')
Ce code construit un graphe avec deux arêtes entre A et B. On peut vérifier les connexions avec G.edges() ; la sortie indiquera :
MultiEdgeDataView([('A', 'B', {'relation': 'neighbor'}), ('A', 'B', {'relation': 'friend'}), ('B', 'C', {'relation': 'neighbor'}), ('B', 'D', {'relation': 'neighbor'}), ('C', 'D', {'relation': 'friend'})])
Connectivité du réseau
Une fois le réseau créé, peut-on en savoir plus sur un nœud en particulier ? Oui, explorons quelques mesures.
Degré
Le degré d’un nœud correspond au nombre de connexions qu’il possède. NetworkX propose la fonction degree pour déterminer le degré d’un nœud.
nx.degree(G_symmetric, 'Dev Anand`)
Cela renverra la valeur 3, car Dev Anand n’a travaillé qu’avec trois acteurs dans le réseau.
Coefficient de clustering
On observe que les personnes partageant des connexions dans un réseau social ont tendance à former des groupes. Autrement dit, un réseau social tend à se structurer en clusters. On peut déterminer, pour un nœud, le coefficient de clustering local, qui est la fraction des paires d’amis (connexions) de ce nœud qui sont eux-mêmes connectés. Pour calculer ce coefficient local, on utilise la fonction nx.clustering(Graph, Node).
Dans le réseau symétrique d’acteurs, Dev Anand a un coefficient de clustering local de 1 et Abhishek Bachchan a un coefficient de 0,67.
Le coefficient de clustering moyen (somme de tous les coefficients locaux divisée par le nombre de nœuds) pour ce réseau symétrique est de 0,867. On l’obtient via :
nx.average_clustering(G_symmetric)
Distance
On peut également déterminer le plus court chemin entre deux nœuds et sa longueur dans NetworkX avec les fonctions nx.shortest_path(Graph, Node1, Node2) et nx.shortest_path_length(Graph, Node1, Node2) respectivement.
En exécutant
nx.shortest_path(G_symmetric, 'Dev Anand', 'Akshay Kumar')
On obtient
['Dev Anand', 'Amitabh Bachchan', 'Akshay Kumar']
On peut trouver la distance d’un nœud à tous les autres en lançant une recherche en largeur (breadth-first search) à partir de ce nœud. NetworkX fournit la fonction bfs_tree pour cela. Si vous exécutez T = nx.bfs_tree(G_symmetric, 'Dev Anand') puis dessinez cet arbre, vous obtiendrez une structure indiquant comment atteindre les autres nœuds du réseau en partant de Dev Anand

Excentricité
L’excentricité d’un nœud A est la plus grande distance entre A et tous les autres nœuds. Elle se calcule avec la fonction nx.eccentricity(). Dans le réseau symétrique d’acteurs, Dev Anand a une excentricité de 2 et Abhishek Bachchan une excentricité de 1 (il est connecté à tous).
Influenceurs du réseau
Nous avons vu des mesures de distance utiles pour comprendre comment l’information circule dans un réseau. Voyons maintenant comment identifier les nœuds (individus) les plus importants. Ces paramètres sont appelés mesures de centralité.
Souvenez-vous de l’élève très populaire de votre lycée ou de la star de l’équipe de baseball. Ces personnes avaient le pouvoir de rendre votre expérience au lycée infernale ou mémorable. Qu’est-ce qui leur donnait ce pouvoir ? Les mesures de centralité aident à identifier la popularité, l’attrait et les plus grands influenceurs au sein d’un réseau.
Centralité de degré
Les personnes les plus populaires sont souvent celles qui ont le plus d’amis. La centralité de degré mesure le nombre de connexions d’un nœud. Elle repose sur l’idée que les nœuds importants ont de nombreuses connexions. NetworkX propose la fonction degree_centrality() pour calculer la centralité de degré de tous les nœuds d’un réseau.
Centralité d’autovecteur
L’importance d’un nœud ne dépend pas seulement du nombre de ses connexions, mais aussi du type de personnes auxquelles il est relié. Sur les routes de Delhi, lorsqu’une personne est arrêtée pour infraction, la première phrase que les agents entendent souvent est : « Savez-vous à qui je suis lié ? »
La centralité d’autovecteur mesure précisément cela : un nœud est d’autant plus important qu’il est connecté à d’autres nœuds importants. On peut utiliser la fonction eigenvector_centrality() de NetworkX pour la calculer pour tous les nœuds d’un réseau.
L’algorithme Pagerank de Google est une variante de la centralité d’autovecteur.
Centralité d’intermédiarité
La centralité d’intermédiarité est liée au contrôle de l’information. Elle représente la fréquence à laquelle un point se situe sur les géodésiques (plus courts chemins) reliant des paires de points. Elle quantifie le nombre de fois où un nœud particulier apparaît sur le plus court chemin choisi entre deux autres nœuds. Les nœuds à forte intermédiarité jouent un rôle clé dans la circulation de l’information au sein du réseau. Ils peuvent exercer un contrôle stratégique et influencer les autres. Placé à une telle position, un individu peut influencer tout le groupe, en retenant ou en orientant l’information transmise.
NetworkX propose la fonction betweenness_centrality() pour mesurer cette grandeur. Elle permet de choisir si l’on souhaite normaliser les valeurs, inclure les poids dans le calcul ou comptabiliser les extrémités des plus courts chemins.
Mettre le tout en pratique
Partons de données Facebook : pour notre analyse, nous utiliserons le jeu de données « Facebook combined ego networks », qui agrège le réseau des listes d’amis de dix personnes. Vous pouvez télécharger le fichier facebook_combined.txt depuis le site de l’université Stanford.
Vous pouvez aussi récupérer vos propres données Facebook/Twitter via les API Facebook/Twitter. Rendez-vous dans le prochain tutoriel où nous verrons comment utiliser ces API pour collecter des données et appliquer les méthodes présentées ici pour les analyser.
Lecture du fichier et construction du graphe :
G_fb = nx.read_edgelist("facebook_combined.txt", create_using = nx.Graph(), nodetype=int)
Le réseau comporte 4 039 nœuds reliés par 88 234 arêtes ! Oui, c’est un grand réseau. Vous obtenez ces informations avec la fonction info().
[In]: print(nx.info(G_fb))
[Out]: Name:
Type: Graph
Number of nodes: 4039
Number of edges: 88234
Average degree: 43.6910
Voici le réseau :

On peut aussi visualiser le réseau de sorte que la couleur des nœuds varie avec le degré et leur taille avec la centralité d’intermédiarité. Voici le code :
pos = nx.spring_layout(G_fb)
betCent = nx.betweenness_centrality(G_fb, normalized=True, endpoints=True)
node_color = [20000.0 * G_fb.degree(v) for v in G_fb]
node_size = [v * 10000 for v in betCent.values()]
plt.figure(figsize=(20,20))
nx.draw_networkx(G_fb, pos=pos, with_labels=False,
node_color=node_color,
node_size=node_size )
plt.axis('off')
Et le graphe obtenu :

Vous pouvez aussi lister les étiquettes des nœuds ayant la plus forte centralité d’intermédiarité avec :
sorted(betCent, key=betCent.get, reverse=True)[:5]
Le tableau ci-dessous répertorie les cinq étiquettes de nœuds avec les plus fortes mesures de centralité.
| Centralité de degré | Centralité d’autovecteur | Centralité d’intermédiarité |
|---|---|---|
| 107 | 1912 | 107 |
| 1684 | 2266 | 1684 |
| 1912 | 2206 | 3437 |
| 3437 | 2233 | 1912 |
| 0 | 2464 | 1085 |
On constate que certains nœuds sont communs entre la centralité de degré, qui mesure le nombre de connexions, et la centralité d’intermédiarité, qui reflète le contrôle du flux d’information. Il est logique que les nœuds très connectés se trouvent souvent sur les plus courts chemins entre d’autres nœuds. Le nœud 1912 est particulièrement important, car il est crucial selon les trois mesures de centralité considérées.
Références
- Les données sur les acteurs proviennent du site IMDB
- La meilleure ressource pour en savoir plus sur NetworkX et ses fonctions est sa documentation
Pour approfondir l’analyse des réseaux sociaux en Python, suivez le cours Analyzing Social Media Data in Python de DataCamp.