Remplissage d’un graphique réseau avec des entités nommées
Exécutez le bloc de code suivant dans une cellule pour obtenir toutes les importations nécessaires dans notre environnement Python.
import pandas as pd
import numpy as np
import pickle
from operator import itemgetter
from fuzzywuzzy import process, fuzz# for natural language processing
import spacy
import en_core_web_sm# for visualizations
%matplotlib inline
from matplotlib.pyplot import figureimport networkx as nx
Si vous souhaitez suivre, vous pouvez télécharger l’exemple de jeu de données ici. Le fichier a été créé à l’aide de journal d’importer des articles de presse npr.org. Si vous vous sentez aventureux, utilisez l’extrait de code ci-dessous pour créer votre propre ensemble de données.
Obtenons nos données.
with open('npr_coronavirus.txt', 'rb') as fp: # Unpickling
corpus = pickle.load(fp)
Ensuite, nous allons commencer par charger le modèle anglais de spaCy:
nlp = en_core_web_sm.load()
Ensuite, nous allons extraire les entités:
entities = []for article in corpus[:50]:
tokens = nlp(''.join(article))
gpe_list = []
for ent in tokens.ents:
if ent.label_ == 'GPE':
gpe_list.append(ent.text)
entities.append(gpe_list)
Dans le bloc de code ci-dessus, nous avons créé une liste vide appelée entities
pour stocker une liste de listes qui contient les entités extraites de chacun des articles. Dans la boucle for, nous avons parcouru les 50 premiers articles du corpus. Pour chaque itération, nous avons converti chaque article en jetons (mots), puis nous avons parcouru tous ces mots pour obtenir les entités étiquetées comme GPE
pour les pays, les états et les villes. Nous avons utilisé ent.text
pour extraire l’entité réelle et les a ajoutés un par un pour entities
.
Voici le résultat:
Notez que la Caroline du Nord a plusieurs variantes de son nom et certains ont «le» préfixé dans leurs noms. Débarrassons-nous d’eux.
articles = []for entity_list in entities:
cleaned_entity_list = []
for entity in entity_list:
cleaned_entity_list.append(entity.lstrip('the ').replace("'s", "").replace("’s",""))
articles.append(cleaned_entity_list)
Dans le bloc de code ci-dessus, nous parcourons simplement la liste des listes articles
et nettoyer les entités une par une. À chaque itération, nous supprimons le préfixe «le» et nous nous débarrassons de 's.
En regardant les entités, j’ai remarqué qu’il existe également des variations aux États-Unis. Il existe des «États-Unis d’Amérique» alors que certains ne sont que des «États-Unis». Nous pouvons les réduire en une convention de dénomination plus standard.
FuzzyWuzzy peut vous y aider.
Décrit par pypi.org comme «correspondance de chaîne comme un patron», FiuzzyWuzzy utilise la distance de Levenshtein pour calculer les similitudes entre les mots.¹ Pour un très bon tutoriel sur la façon d’utiliser FuzzyWuzzy, consultez l’article de Thanh Huynh.
Voici le code facultatif pour utiliser FuzzyWuzzy:
Pour la dernière étape avant de créer le graphique de réseau, débarrassons-nous des listes vides dans notre liste de listes qui ont été générées par des articles qui n’avaient pas de GPE
types d’entités.
articles = [article for article in articles if article != []]
Pour l’étape suivante, nous allons créer le monde dans lequel le graphique existera.
G = nx.Graph()
Ensuite, nous ajouterons manuellement les nœuds avec G.add_nodes_from()
.
for entities in articles:
G.add_nodes_from(entities)
Voyons à quoi ressemble le graphique avec:
figure(figsize=(10, 8))
nx.draw(G, node_size=15)
Ensuite, ajoutons les bords qui relieront les nœuds.
for entities in articles:
if len(entities) > 1:
for i in range(len(entities)-1):
G.add_edges_from([(str(entities[i]),str(entities[i+1]))])
Pour chaque itération du code ci-dessus, nous avons utilisé un conditionnel qui n’entretiendra qu’une liste d’entités qui a deux ou plusieurs entités. Ensuite, nous connectons manuellement chacune des entités avec G.add_edges_from()
.
Voyons maintenant à quoi ressemble le graphique:
figure(figsize=(10, 8))
nx.draw(G, node_size=10)
Ce graphique me rappelle les araignées! LOL.
Pour l’organiser un peu, j’ai décidé d’utiliser la version shell du graphe réseau:
figure(figsize=(10, 8))
nx.draw_shell(G, node_size=15)
On peut dire que certains nœuds sont plus lourds sur les connexions que d’autres. Pour voir quels nœuds ont le plus de connexions, utilisons G.degree()
.
G.degree()
Cela donne la vue de degré suivante:
Voyons quel nœud ou entité a le plus de connexions.
max(dict(G.degree()).items(), key = lambda x : x[1])
Pour savoir quels autres nœuds ont le plus de connexions, regardons le top 5:
degree_dict = dict(G.degree(G.nodes()))
nx.set_node_attributes(G, degree_dict, 'degree')sorted_degree = sorted(degree_dict.items(), key=itemgetter(1), reverse=True)
Au dessus de, sorted_degrees
est une liste qui contient tous les nœuds et leurs valeurs de degré. Nous voulions seulement le top 5 comme ça:
print("Top 5 nodes by degree:")
for d in sorted_degree[:5]:
print(d)
Gephi est une application de bureau open source et gratuite qui nous permet de visualiser, d’explorer et d’analyser toutes sortes de graphiques et de réseaux².
Exportons nos données graphiques dans un fichier afin de pouvoir les importer dans Gephi.
nx.write_gexf(G, "npr_coronavirus_GPE_50.gexf")
Fèves fraîches!
Cette fois, nous n’avons traité que 50 articles de npr.org. Que se passerait-il si nous traitions les 300 articles de notre ensemble de données? Que verrons-nous si nous changeons le type d’entité de GPE
à PERSON
? Sinon, comment pouvons-nous utiliser des graphiques de réseau pour visualiser les résultats du traitement en langage naturel?
Il y a toujours plus à faire. Les possibilités sont infinies!