문장을 연결하는 그래프
다음과 같은 몇 가지 주제 (2 개)의 문장 목록이 있습니다.
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)
관계의 방향을 보여줍니다.
좀 더 명확하게하기 위해 다른 예제를 제공했습니다 (하지만 이전 예제로 작업했다면 괜찮을 것입니다. 불편을 끼쳐 드려 죄송하지만 첫 번째 질문이 명확하지 않았기 때문에 더 나은 것도 제공해야했습니다. 아마도 더 쉬울 것입니다.
답변
동사 / 명사 분리를 위해 NLP를 구현하지 않았고, 좋은 단어 목록을 추가했습니다. 비교적 쉽게 간격을두고 추출하고 정규화 할 수 있습니다 . 1 walk
, 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")

업데이트
서로 다른 문장 간의 유사성을 측정하려는 경우 문장 삽입 간의 차이를 계산할 수 있습니다.
이렇게하면 "여러 남성이 플레이하는 축구 게임"및 "일부 남성이 스포츠를하고 있습니다"와 같이 서로 다른 단어가 포함 된 문장 간의 의미 적 유사성을 찾을 수 있습니다. BERT를 사용하여 거의 SOTA 방법을 찾을 수 있습니다 여기에 , 더 간단한 방법은 여기 .
유사성 측정 값이 있으므로 유사성 측정 값이 일부 임계 값보다 큰 경우에만 add_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)
이를 처리하는 한 가지 방법은 토큰 화하고 불용어를 제거하고 어휘를 만드는 것입니다. 그런 다음이 어휘를 기반으로 그래프를 그립니다. 나는 아래에 유니 그램 기반 토큰에 대한 예제를 보여주고 있지만 훨씬 더 나은 접근 방식은 구문 (ngram)을 식별하고 유니 그램 대신 어휘로 사용하는 것입니다. 유사하게 문장은 더 많은 in과 학위를 가진 노드 (및 해당 문장)에 의해 그림으로 묘사됩니다.
견본:
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()
산출:
