Graphique pour relier des phrases

Aug 20 2020

J'ai une liste de phrases de quelques sujets (deux) comme ci-dessous:

Sentences
Trump says that it is useful to win the next presidential election. 
The Prime Minister suggests the name of the winner of the next presidential election.
In yesterday's conference, the Prime Minister said that it is very important to win the next presidential election. 
The Chinese Minister is in London to discuss about climate change.
The president Donald Trump states that he wants to win the presidential election. This will require a strong media engagement.
The president Donald Trump states that he wants to win the presidential election. The UK has proposed collaboration. 
The president Donald Trump states that he wants to win the presidential election. He has the support of his electors. 

Comme vous pouvez le voir, les phrases sont similaires.

J'essaie de relier plusieurs phrases et d'en visualiser les caractéristiques en utilisant un graphique (dirigé). Le graphique est construit à partir d'une matrice de similarité, en appliquant l'ordre des lignes des phrases comme indiqué ci-dessus. J'ai créé une nouvelle colonne, Time, pour montrer l'ordre des phrases, donc la première ligne (Trump dit que ....) est au temps 1; la deuxième rangée (le premier ministre suggère ...) est au temps 2, et ainsi de suite. Quelque chose comme ça

Time    Sentences
1           Trump said that it is useful to win the next presidential election. 
2           The Prime Minister suggests the name of the winner of the next presidential election.

3           In today's conference, the Prime Minister said that it is very important to win the next presidential election. 

...

Je voudrais ensuite trouver les relations afin d'avoir une vision claire du sujet. Plusieurs chemins pour une phrase montreraient qu'il y a plusieurs informations qui lui sont associées. Pour déterminer la similitude entre deux phrases, j'ai essayé d'extraire les noms et les verbes comme suit:

noun=[]
verb=[]
for  index, row in df.iterrows():
      nouns.append([word for word,pos in pos_tag(row[0]) if pos == 'NN'])
      verb.append([word for word,pos in pos_tag(row[0]) if pos == 'VB'])

car ce sont des mots-clés dans n'importe quelle phrase. Ainsi, lorsqu'un mot-clé (nom ou verbe) apparaît dans la phrase x mais pas dans les autres phrases, il représente une différence entre ces deux phrases. Je pense qu'une meilleure approche, cependant, pourrait être d'utiliser word2vec ou gensim (WMD).

Cette similitude doit être calculée pour chaque phrase. Je voudrais créer un graphique qui montre le contenu de la phrase dans mon exemple ci-dessus. Puisqu'il y a deux sujets (Trump et le ministre chinois), pour chacun d'eux, je dois rechercher des sous-sujets. Trump a des élections présidentielles sous-thèmes, par exemple. Un nœud dans mon graphique devrait représenter une phrase. Les mots dans chaque nœud représentent les différences pour les phrases, montrant de nouvelles informations dans la phrase. Par exemple, le mot statesdans la phrase au temps 5 est dans des phrases adjacentes aux temps 6 et 7. Je voudrais juste trouver un moyen d'obtenir des résultats similaires comme le montre l'image ci-dessous. J'ai essayé d'utiliser principalement l'extraction de noms et de verbes, mais ce n'est probablement pas la bonne façon de procéder. Ce que j'ai essayé de faire a été de considérer la phrase au temps 1 et de la comparer avec d'autres phrases, d'attribuer un score de similitude (avec extraction de noms et de verbes mais aussi avec word2vec) et de la répéter pour toutes les autres phrases. Mais mon problème est maintenant de savoir comment extraire la différence pour créer un graphique qui puisse avoir du sens.

Pour la partie du graphique, j'envisagerais d'utiliser networkx (DiGraph):

G = nx.DiGraph()
N = Network(directed=True) 

pour montrer la direction des relations.

J'ai fourni un exemple différent pour que ce soit plus clair (mais si vous travailliez avec l'exemple précédent, ce serait bien aussi. Toutes mes excuses pour le désagrément, mais comme ma première question n'était pas si claire, je devais également fournir une meilleure, probablement plus facile, par exemple).

Réponses

4 ilia Oct 10 2020 at 17:42

N'a pas implémenté la PNL pour la séparation verbe / nom, juste ajouté une liste de bons mots. Ils peuvent être extraits et normalisés avec spacy relativement facilement. Veuillez noter que cela walkse produit dans 1,2,5 phrases et forme une triade.

import re
import networkx as nx
import matplotlib.pyplot as plt

plt.style.use("ggplot")

sentences = [
    "I went out for a walk or walking.",
    "When I was walking, I saw a cat. ",
    "The cat was injured. ",
    "My mum's name is Marylin.",
    "While I was walking, I met John. ",
    "Nothing has happened.",
]

G = nx.Graph()
# set of possible good words
good_words = {"went", "walk", "cat", "walking"}

# remove punctuation and keep only good words inside sentences
words = list(
    map(
        lambda x: set(re.sub(r"[^\w\s]", "", x).lower().split()).intersection(
            good_words
        ),
        sentences,
    )
)

# convert sentences to dict for furtehr labeling
sentences = {k: v for k, v in enumerate(sentences)}

# add nodes
for i, sentence in sentences.items():
    G.add_node(i)

# add edges if two nodes have the same word inside
for i in range(len(words)):
    for j in range(i + 1, len(words)):
        for edge_label in words[i].intersection(words[j]):
            G.add_edge(i, j, r=edge_label)

# compute layout coords
coord = nx.spring_layout(G)

plt.figure(figsize=(20, 14))

# set label coords a bit upper the nodes
node_label_coords = {}
for node, coords in coord.items():
    node_label_coords[node] = (coords[0], coords[1] + 0.04)

# draw the network
nodes = nx.draw_networkx_nodes(G, pos=coord)
edges = nx.draw_networkx_edges(G, pos=coord)
edge_labels = nx.draw_networkx_edge_labels(G, pos=coord)
node_labels = nx.draw_networkx_labels(G, pos=node_label_coords, labels=sentences)
plt.title("Sentences network")
plt.axis("off")

Mise à jour
Si vous souhaitez mesurer la similitude entre différentes phrases, vous souhaiterez peut-être calculer la différence entre l'incorporation de phrases.
Cela vous donne l'occasion de trouver une similitude sémantique entre des phrases avec des mots différents comme "Un match de football avec plusieurs hommes jouant" et "Certains hommes pratiquent un sport". Presque l'approche SoTA utilisant BERT peut être trouvée ici , des approches plus simples sont ici .
Puisque vous avez une mesure de similarité, remplacez simplement le bloc add_edge pour ajouter un nouveau bord uniquement si la mesure de similarité est supérieure à un certain seuil. Le code d'ajout d'arêtes résultant ressemblera à ceci:

# add edges if two nodes have the same word inside
tresold = 0.90
for i in range(len(words)):
    for j in range(i + 1, len(words)):
        # suppose you have some similarity function using BERT or PCA
        similarity = check_similarity(sentences[i], sentences[j])
        if similarity > tresold:
            G.add_edge(i, j, r=similarity)
1 mujjiga Oct 10 2020 at 20:09

Une façon de gérer cela est de tokeniser, de supprimer les mots vides et de créer le vocabulaire. Dessinez ensuite le graphique en vous basant sur ce vocabulaire. Je montre ci-dessous un exemple sur des jetons basés sur unigramme, mais une bien meilleure approche sera d'identifier des phrases (ngrams) et de les utiliser comme vocabulaire au lieu d'unigrammes. De même, la phrase sera illustrée par des nœuds (et les phrases correspondantes) ayant plus de degré et de degré.

Échantillon:

from sklearn.feature_extraction.text import CountVectorizer
import networkx as nx
import matplotlib.pyplot as plt


corpus = [
  "Trump says that it is useful to win the next presidential election",
  "The Prime Minister suggests the name of the winner of the next presidential election",
  "In yesterday conference, the Prime Minister said that it is very important to win the next presidential election",
  "The Chinese Minister is in London to discuss about climate change",
  "The president Donald Trump states that he wants to win the presidential election. This will require a strong media engagement",
  "The president Donald Trump states that he wants to win the presidential election. The UK has proposed collaboration",
  "The president Donald Trump states that he wants to win the presidential election. He has the support of his electors",
]

vectorizer = CountVectorizer(analyzer='word', ngram_range=(1, 1), stop_words="english")
vectorizer.fit_transform(corpus)


G = nx.DiGraph()
G.add_nodes_from(vectorizer.get_feature_names())

all_edges = []
for s in corpus:
  edges = []
  previous = None
  for w in s.split():
    w = w.lower()
    if w in vectorizer.get_feature_names():
      if previous:
        edges.append((previous, w))
        #print (previous, w)
      previous = w   

  all_edges.append(edges)


plt.figure(figsize=(20,20))
pos = nx.shell_layout(G)
nx.draw_networkx_nodes(G, pos, node_size = 500)
nx.draw_networkx_labels(G, pos)
colors = ['r', 'g', 'b', 'y', 'm', 'c', 'k']
for i, edges in enumerate(all_edges):
  nx.draw_networkx_edges(G, pos, edgelist=edges, edge_color=colors[i], arrows=True)
#nx.draw_networkx_edges(G, pos, edgelist=black_edges, arrows=False)
plt.show()

Production: