Grafico per collegare le frasi
Ho un elenco di frasi di alcuni argomenti (due) come il seguente:
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.
Come puoi vedere c'è somiglianza nelle frasi.

Sto cercando di mettere in relazione più frasi e visualizzarne le caratteristiche utilizzando un grafico (diretto). Il grafico è costruito da una matrice di somiglianza, applicando l'ordine delle righe delle frasi come mostrato sopra. Ho creato una nuova colonna, Time, per mostrare l'ordine delle frasi, quindi la prima riga (Trump dice che ....) è al tempo 1; la seconda fila (suggerisce il Primo Ministro ...) è al tempo 2, e così via. Qualcosa come questo
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.
...
Vorrei quindi trovare le relazioni in modo da avere una visione chiara dell'argomento. Più percorsi per una frase mostrerebbero che ci sono più informazioni ad essa associate. Per determinare la somiglianza tra due frasi, ho provato a estrarre nomi e verbi come segue:
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'])
in quanto sono parole chiave in qualsiasi frase. Quindi, quando una parola chiave (sostantivo o verbo) appare nella frase x ma non nelle altre frasi, rappresenta una differenza tra queste due frasi. Penso che un approccio migliore, tuttavia, potrebbe essere l'uso di word2vec o gensim (WMD).
Questa somiglianza deve essere calcolata per ogni frase. Vorrei costruire un grafico che mostri il contenuto della frase nel mio esempio sopra. Poiché ci sono due argomenti (Trump e il ministro cinese), per ognuno di essi devo cercare sotto-argomenti. Trump ha sotto-tema le elezioni presidenziali, ad esempio. Un nodo nel mio grafico dovrebbe rappresentare una frase. Le parole in ogni nodo rappresentano le differenze per le frasi, mostrando nuove informazioni nella frase. Ad esempio, la parola states
nella frase al tempo 5 è in frasi adiacenti al tempo 6 e 7. Vorrei solo trovare un modo per ottenere risultati simili come mostrato nell'immagine sotto. Ho provato a usare principalmente l'estrazione di nomi e verbi, ma probabilmente non è il modo giusto di procedere. Quello che ho cercato di fare è stato considerare la frase al tempo 1 e confrontarla con altre frasi, assegnando un punteggio di somiglianza (con estrazione di nomi e verbi ma anche con word2vec), e ripeterla per tutte le altre frasi. Ma il mio problema ora è come estrarre la differenza per creare un grafico che possa avere un senso.
Per la parte del grafico, considererei di utilizzare networkx (DiGraph):
G = nx.DiGraph()
N = Network(directed=True)
per mostrare la direzione delle relazioni.
Ho fornito un esempio diverso per renderlo più chiaro (ma se lavorassi con l'esempio precedente, andrebbe bene pure. Mi scuso per l'inconveniente, ma poiché la mia prima domanda non era così chiara, ho dovuto fornire anche una migliore, probabilmente più facile, esempio).
Risposte
Non ha implementato la PNL per la separazione verbo / nome, ha appena aggiunto un elenco di buone parole. Possono essere estratti e normalizzati con spacy relativamente facile. Si noti che si walk
verifica in 1,2,5 frasi e forma una 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")

Aggiorna
Se vuoi misurare la somiglianza tra frasi diverse, potresti voler calcolare la differenza tra l'incorporamento di frasi.
Questo ti dà l'opportunità di trovare somiglianze semantiche tra frasi con parole diverse come "Una partita di calcio con più maschi che giocano" e "Alcuni uomini stanno praticando uno sport". Quasi l'approccio SoTA che utilizza BERT può essere trovato qui , approcci più semplici sono qui .
Poiché hai la misura di somiglianza, sostituisci semplicemente il blocco add_edge per aggiungere un nuovo bordo solo se la misura di somiglianza è maggiore di una certa soglia. Il codice di aggiunta dei bordi risultante sarà simile a questo:
# 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)
Un modo per gestire questo è tokenizzare, rimuovere le parole di arresto e creare il vocabolario. Quindi disegna il grafico in base a questo vocabolario. Sto mostrando di seguito un esempio sui token basati su unigrammi, ma l'approccio migliore sarà identificare le frasi (ngram) e usarle come vocabolario invece di unigrammi. La frase allo stesso modo sarà rappresentata pittoricamente da nodi (e le frasi corrispondenti) aventi più in e grado.
Campione:
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()
Produzione:
