Python|知识图谱——用Python代码从文本中挖掘信息的强大数据科学技术( 三 )


是时候进行代码操作了!打开Jupyter Notebooks(或者任何你喜欢的集成开发环境-IDE) 。
使用一组从维基百科中找到的电影中的文本 , 从头开始构建一个知识图谱 。 我已经从500多篇维基百科文章中摘录了大约4300句话 。 每个句子都包含两个实体——一个主语和一个宾语 。 你可以点击这里下载这些句子 。
推荐使用Google Colab , 能加快计算的运行速度 。
导入库
import re
import pandas as pd
import bs4
import requests
import spacy
from spacy import displacy
nlp = spacy.load('en_core_web_sm')
from spacy.matcher import Matcher
from spacy.tokens import Span
import networkx as nx
import matplotlib.pyplot as plt
from tqdm import tqdm
pd.set_option('display.max_colwidth', 200)
%matplotlib inline
读取数据
阅读包含维基百科句子的CSV文件:
# import wikipedia sentences
candidate_sentences = pd.read_csv("wiki_sentences_v2.csv")
candidate_sentences.shape
输出:(4318, 1)
来看几个例句:
candidate_sentences['sentence'].sample(5)
输出:
Python|知识图谱——用Python代码从文本中挖掘信息的强大数据科学技术文章插图
检查其中一个句子的主语和宾语 。 理想情况下 , 句子中应该有一个主语和一个宾语:
doc = nlp("the drawdown process is governed by astm standard d823")
for tok in doc:
print(tok.text, "...", tok.dep_)
输出:
Python|知识图谱——用Python代码从文本中挖掘信息的强大数据科学技术文章插图
很好!只有一个主语“过程”(process)和一个宾语“标准”(standard) 。 你可以用类似的方式检查其他句子 。
实体对抽取
想要构架出一个知识图谱 , 最重要的是节点和它们之间的边 。
这些节点是出现在维基百科语句中的实体 。 边是连接各个实体之间的关系 。 我们将以无监督的方式提取这些要素 , 也就是说 , 我们将依靠句子的语法 。
其主要思想就是在浏览一个句子时 , 把遇到的主语和宾语提取出来 。 然而 , 还有其他挑战存在——实体可能不止一个单词 , 如“红酒(red wine)” , 依存关系解析器只会将单个单词标记为主语或宾语 。
因此 , 下面创建了一个函数来从一个句子中提取主语和宾语(也就是实体) , 同时解决了上面提到的挑战 。 方便起见 , 将代码分成了多个板块:
defget_entities(sent):
## chunk 1
ent1 =""
ent2 =""
prv_tok_dep ="" # dependency tag of previous token in the sentence
prv_tok_text ="" # previous token in the sentence
prefix =""
modifier =""
#############################################################
for tok in nlp(sent):
## chunk 2
# if token is a punctuation mark then move on to the next token
if tok.dep_ !="punct":
# check: token is a compound word or not
if tok.dep_ =="compound":
prefix = tok.text
# if the previous word was also a 'compound' then add the current word to it
if prv_tok_dep =="compound":
prefix = prv_tok_text +""+ tok.text
# check: token is a modifier or not
if tok.dep_.endswith("mod") ==True:
modifier = tok.text
# if the previous word was also a 'compound' then add the current word to it
if prv_tok_dep =="compound":
modifier = prv_tok_text +""+ tok.text
## chunk 3
if tok.dep_.find("subj") ==True:
ent1 = modifier +""+ prefix +""+ tok.text
prefix =""
modifier =""
prv_tok_dep =""
prv_tok_text =""
## chunk 4
if tok.dep_.find("obj") ==True:
ent2 = modifier +""+ prefix +""+ tok.text
## chunk 5
# update variables
prv_tok_dep = tok.dep_
prv_tok_text = tok.text
#############################################################
return [ent1.strip(), ent2.strip()]
我来解释一下上面函数中的代码板块:
板块1
我已经在这个板块中定义了一些空变量 。 prv_tok_dep 和 prv_tok_text将分别保存句子中前一个单词和它本身的依存标记 。 prefix和modifier将保存与主语或宾语有关联的文本 。
板块2
接下来 , 循环浏览句子中的所有标记 。 首先要检查标记是不是标点符号 。 如果是 , 那么我们将忽略它看下一标记(token) 。 如果标记是复合词(依存标记=“compound”)中的一部分 , 将把它保存在“前缀”变量中 。 一个复合词是多个词的组合 , 它们联系在一起形成一个有新意义的词 , 例如“足球场”(“FootballStadium”) , “动物爱人”(“animallover”) 。
当我们在句子中遇到主语或宾语时 , 会给它加上这个前缀 。 修饰语同样 , 比如“漂亮的衬衫”、“大房子”等等 。
板块3
在这里 , 如果标记是主语的话 , 它将被捕获为ent1变量中的第一个实体 。 诸如prefix, modifier, prv_tok_dep,和 prv_tok_text 这些变量将被重置 。