กราฟเพื่อเชื่อมประโยค

Aug 20 2020

ฉันมีรายการประโยคจากสองสามหัวข้อ (สอง) ดังต่อไปนี้:

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. 

อย่างที่คุณเห็นมีความคล้ายคลึงกันในประโยค

ฉันพยายามเชื่อมโยงหลาย ๆ ประโยคและเห็นภาพลักษณะของประโยคเหล่านี้โดยใช้กราฟ (กำกับ) กราฟสร้างจากเมทริกซ์ความคล้ายคลึงกันโดยใช้การเรียงแถวของประโยคดังที่แสดงด้านบน ฉันสร้างคอลัมน์ใหม่ Time เพื่อแสดงลำดับของประโยคดังนั้นแถวแรก (ทรัมป์บอกว่า .... ) คือเวลา 1; แถวที่สอง (นายกฯ แนะ ... ) คือเวลา 2 เป็นต้นไป อะไรทำนองนี้

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. 

...

ฉันต้องการค้นหาความสัมพันธ์เพื่อให้มีภาพรวมที่ชัดเจนของหัวข้อ หลายเส้นทางสำหรับประโยคจะแสดงว่ามีข้อมูลหลายอย่างที่เกี่ยวข้อง เพื่อตรวจสอบความคล้ายคลึงกันระหว่างสองประโยคฉันพยายามแยกคำนามและคำกริยาดังนี้:

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'])

เนื่องจากเป็นคำหลักในประโยคใด ๆ ดังนั้นเมื่อคีย์เวิร์ด (นามหรือกริยา) ปรากฏในประโยค x แต่ไม่ปรากฏในประโยคอื่นแสดงถึงความแตกต่างระหว่างสองประโยคนี้ ฉันคิดว่าวิธีการที่ดีกว่าอาจใช้ word2vec หรือ gensim (WMD)

ความคล้ายคลึงกันนี้จะต้องถูกคำนวณสำหรับแต่ละประโยค ฉันต้องการสร้างกราฟที่แสดงเนื้อหาของประโยคในตัวอย่างด้านบน เนื่องจากมีสองหัวข้อ (ทรัมป์และรัฐมนตรีจีน) สำหรับแต่ละหัวข้อฉันจึงต้องหาหัวข้อย่อย ตัวอย่างเช่นทรัมป์มีหัวข้อย่อยเกี่ยวกับการเลือกตั้งประธานาธิบดี โหนดในกราฟของฉันควรเป็นตัวแทนของประโยค คำในแต่ละโหนดแสดงถึงความแตกต่างของประโยคโดยแสดงข้อมูลใหม่ในประโยค ตัวอย่างเช่นคำstatesในประโยคที่เวลา 5 อยู่ในประโยคที่อยู่ติดกันในเวลา 6 และ 7 ฉันต้องการเพียงแค่หาวิธีที่จะได้ผลลัพธ์ที่คล้ายกันดังแสดงในภาพด้านล่าง ฉันได้ลองใช้การแยกคำนามและคำกริยาเป็นหลัก แต่อาจไม่ใช่วิธีที่ถูกต้องในการดำเนินการ สิ่งที่ฉันพยายามทำคือพิจารณาประโยคในตอนที่ 1 และเปรียบเทียบกับประโยคอื่นโดยกำหนดคะแนนความคล้ายคลึงกัน (ด้วยการแยกคำนามและคำกริยา แต่ใช้ word2vec ด้วย) และทำซ้ำสำหรับประโยคอื่น ๆ ทั้งหมด แต่ปัญหาของฉันตอนนี้คือวิธีดึงความแตกต่างเพื่อสร้างกราฟที่สมเหตุสมผล

สำหรับส่วนของกราฟฉันจะพิจารณาใช้ networkx (DiGraph):

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

เพื่อแสดงทิศทางของความสัมพันธ์

ฉันให้ตัวอย่างอื่นเพื่อให้ชัดเจนขึ้น (แต่ถ้าคุณทำงานกับตัวอย่างก่อนหน้านี้ก็คงดีเช่นกันขออภัยในความไม่สะดวก แต่เนื่องจากคำถามแรกของฉันไม่ชัดเจนฉันจึงต้องให้คำตอบที่ดีกว่านี้ด้วย อาจจะง่ายกว่าเช่น)

คำตอบ

4 ilia Oct 10 2020 at 17:42

ไม่ได้ใช้ NLP สำหรับการแยกคำกริยา / คำนามเพียงแค่เพิ่มรายการคำที่ดี สามารถแยกและทำให้เป็นมาตรฐานได้ด้วยspacyค่อนข้างง่าย โปรดทราบว่าwalkเกิดขึ้นใน 1,2,5 ประโยคและเป็นสามกลุ่ม

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")

อัปเดต
หากคุณต้องการวัดความเหมือนระหว่างประโยคต่างๆคุณอาจต้องการคำนวณความแตกต่างระหว่างการฝังประโยค
วิธีนี้ช่วยให้คุณสามารถค้นหาความคล้ายคลึงทางความหมายระหว่างประโยคที่มีคำต่างกันเช่น "เกมฟุตบอลที่มีผู้ชายเล่นหลายคน" และ "ผู้ชายบางคนกำลังเล่นกีฬา" เกือบวิธี SOTA ใช้ BERT สามารถพบได้ที่นี่วิธีที่ง่ายมากขึ้นที่นี่
เนื่องจากคุณมีการวัดความคล้ายคลึงกันให้แทนที่ add_edge block เพื่อเพิ่ม edge ใหม่เฉพาะในกรณีที่การวัดความคล้ายคลึงกันมากกว่าเกณฑ์บางส่วน รหัสเพิ่มขอบผลลัพธ์จะมีลักษณะดังนี้:

# 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

วิธีหนึ่งในการจัดการกับปัญหานี้คือโทเค็นลบคำหยุดและสร้างคำศัพท์ จากนั้นวาดกราฟตามคำศัพท์นี้ ฉันกำลังแสดงด้านล่างและตัวอย่างเกี่ยวกับโทเค็นที่ใช้ unigram แต่แนวทางที่ดีกว่ามากคือการระบุวลี (ngrams) และใช้เป็นคำศัพท์แทน unigrams ประโยคในทำนองเดียวกันจะแสดงเป็นภาพโดยโหนด (และประโยคที่เกี่ยวข้อง) ที่มีระดับและระดับมากขึ้น

ตัวอย่าง:

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()

เอาท์พุต: