知识图谱实战:构建方法与行业应用
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.3 知识抽取实例

接下来将介绍如何使用Deepdive抽取公司实体间的股权交易关系,即关系抽取。

Deepdive是由斯坦福大学InfoLab实验室开发的一个开源知识抽取系统。它通过弱监督学习,从非结构化的文本中抽取结构化的关系数据。在使用Deepdive时需要考虑它是否支持中文,因为我们的数据是中文的。一般来说可以修改自然语言处理的model包,使它支持中文,并提供中文教程;也可以下载浙江大学支持中文的Deepdive版本。当学习了如何替换其中的各个模块后,我们就可以自己定义语言了。我们将参考中文开放知识图谱(OpenKG.CN)网站支持的中文Deepdive资源,给出知识抽取的实例并进行讲解。

2.3.1 Deepdive的安装和配置

我们首先下载并安装Deepdive,进行环境配置之后,进行项目框架搭建。

1.下载

目前网络已经有较多的Deepdive资源,这里使用的数据和工具都来自上面提到的开放资源,链接为http://www.openkg.cn/dataset/cn-deepdive,同时它也提供了有关Deepdive安装以及进行知识抽取的详细介绍。

2.安装

我们以Linux环境下安装Deepdive为例,首先下载.zip格式的压缩文件并将其解压。

1)创建一个deepdive文件夹。

2)将下载好的CNdeepdive.zip移动到deepdive文件夹下,并使用zip解压;解压后可以看到CNdeepdive文件夹,进入该文件夹有一个install.sh文件。

3)打开install.sh文件,修改第193行xzvf为xvf后,在CNdeepdive目录下执行(此过程需要联网)./install.sh。

4)按照提示输入“1”,然后按回车键,Deepdive就会开始安装;安装完成后,我们再安装PostgreSQL,输入“6”然后按回车键执行安装。

5)安装自然语言处理的相关组件,可执行./nlp_setup.sh命令。

3.配置环境

安装完成之后,主目录会创建一个local文件夹,这时要把文件夹中的bin目录添加到环境变量Path中。使用文本方式打开~/.bashrc以配置所需环境,可以在命令行中使用vi或者gedit等文本编辑程序;或者在图形界面打开主目录后,按快捷键Ctrl+H显示隐藏文件后再编辑。例如,在文件的末尾添加下面的内容:

其中,username要替换成你当前登录的用户名。

修改完成后保存并关闭文件。要使我们的修改生效,在终端中输入:

到这里Deepdive就已经安装完成了,打开终端执行deepdive命令,我们就可以看到Deepdive的版本信息和命令参数的帮助页。

4.项目框架搭建

建立自己的项目文件夹transaction,在本地PostgreSQL中为项目建立数据库,之后在项目文件夹下建立数据库配置文件:

接下来,在transaction下分别建立输入数据文件夹input、脚本文件夹udf、用户配置文件app.ddlog、模型配置文件deepdive.conf,可参照给定的transaction文件夹格式。transaction文件夹是已经建好的项目,后面所需的脚本和数据文件都可以直接复制。Deepdive定义了很多自己的语法规则和自动化脚本,导入数据库的过程一般为deepdive do db_name指令,用户通过配置app.ddlog指示数据流。

2.3.2 实验步骤

在实验过程中,我们先导入先验数据,随后导入待抽取文章,然后使用nlp模块进行文本处理,生成实体抽取及候选实体,提取特征以供模型构建用。

1.先验数据导入

我们需要从知识库中获取已知具有交易关系的实体对来作为训练数据。本项目以国泰安数据库(http://www.gtarsc.com)中公司关系-股权交易模块中的数据为例。

1)通过匹配有交易的股票-代码对和代码-公司对,过滤出存在交易关系的公司对,存入transaction_dbdata.csv中,并将CSV文件放在input文件夹下。

2)在DeepdireTest项目文件夹的用户配置文件app.ddlog中定义相应的数据表。

3)用命令行生成PostgreSQL数据表。

4)在执行app.ddlog前,如果有改动,需要先执行deepdive compile命令编译才能生效,对于不依赖于其他表的表格,Deepdive会自动去input文件夹下找到同名CSV文件,在PostgreSQL里建表导入。

5)运行命令时,Deepdive会在当前命令行里生成一个执行计划文件,和vi语法一样,审核后使用:wq保存并执行。

2.待抽取文章导入

接下来,我们导入已准备好的待抽取文章。

1)准备待抽取的文章(示例使用了上市公司的公告),命名为articles.csv,并放在input文件夹下。

2)在app.ddlog中建立对应的articles表。

3)执行以下命令,将文章导入PostgreSQL中。

Deepdive可以直接查询数据库数据,用查询语句或者Deepdive SQL语句进行数据库操作。

4)使用查询id指令,检验导入是否成功(结果可能因数据集更新而变化):

3.用nlp模块进行文本处理

Deepdive默认采用Standford NLP处理包进行文本处理。输入文本数据,nlp模块将以句子为单位,返回每句的分词、命名实体识别、每个词的原词形(Lemma)、词性(Part Of Speech, POS)和句法分析的结果,为后续特征抽取做好准备。其中,原词形为英文单词经过词形还原(Lemmalization)之后的结果,例如表示复数的cars将还原成car,表示过去时的ate将还原成eat,在进行中文处理时不需要再考虑这些。我们将这些结果存入sentences表中。

1)在app.ddlog文件中定义sentences表,用于存放NLP结果:

2)定义NLP处理的函数nlp_markup。

代码说明如下。

❑声明一个ddlog函数,这个函数输入文章的doc_id和content,输出sentences表需要的字段格式。

❑函数udf/nlp_markup.sh调用nlp模块,这里可以自由发挥。

❑nlp_markup.sh的脚本内容见transaction示例代码中的udf/文件夹,它调用了udf/bazzar/parser下的run.sh实现。

注意,此处需要重新编译nlp模块。复制transaction/udf/目录下的bazzar文件夹到项目DeepdiveTest的udf/中。进入bazzar/parser目录下,执行编译命令:

编译完成后会在target中生成可执行文件。

3)使用如下语法调用nlp_markup函数,从articles表中读取输入,并将输出存放在sentences表中。

4)编译并执行deepdive compile和deepdive do sentences两个命令,生成sentences数据表。执行以下命令来查询并返回sentences表前5句的解析结果:

如果articles表有更新,需要重新执行deepdive redo articles命令或者用deepdive mark todo articles命令来将articles表标记为未执行,这样在生成sentences表的过程中就会默认更新articles表了。注意,这一步运行会非常慢,可能需要四五个小时。我们可以减少articles表的行数来缩短时间。

4.实体抽取及候选实体对生成

这一步我们要抽取文本中的候选实体(公司),并生成候选实体对。

1)在app.ddlog中定义实体数据表company_mention:

每个实体都是实体数据表中的一列数据,该表同时存储了实体在句中的起始位置和结束位置。

2)定义实体抽取的函数:

其中,map_company_mention.py脚本会遍历每个数据库中的句子,找出连续的、被命名实体识别环节标记为公司(ORG)的序列,再进行其他过滤处理。map_company_mention.py脚本也是一个生成函数,用yield语句返回输出行。

3)在app.ddlog中调用函数,从sentences表中输入数据,并将结果输出到company_mention中,被调用的函数内容如下。

4)最后编译并执行:

5)下面生成实体对(要预测关系的两个公司)。在这一步我们将实体表进行笛卡儿积运算,同时按自定义脚本过滤一些不符合形成交易条件的公司。

定义数据表如下:

6)统计每个句子的实体数:

7)定义过滤函数:

8)描述函数的调用:

一些简单的过滤操作可以直接通过app.ddlog中的数据库规则执行,比如语句p1_name !=p2_name过滤掉两个相同实体组成的实体对。

9)编译并执行以下命令,以生成实体候选表。

5.特征提取

这一步我们抽取候选实体对的文本特征。

1)定义特征表:

这里的feature列是实体对间一系列文本特征的集合。

2)生成feature表需要的输入为实体对表和文本表,输入和输出属性在app.ddlog中定义如下:

函数调用extract_transaction_features.py来抽取特征。这里调用了Deepdive自带的ddlib库,得到各种POS、NER、词序列的窗口特征。此处也可以自定义特征。

3)对sentences表和mention表进行join操作,将得到的结果输入函数,输出到transaction_feature表中。

4)然后编译生成特征数据库:

执行如下语句,查看生成结果(结果可能因数据集更新而变化):

现在,我们已经有了想要判定关系的实体对和它们的特征集合。

6.样本打标签

这一步,我们希望在候选实体对中标出部分正负样本,主要思路如下。

❑将已知标签的实体对和候选实体对关联,得到候选实体的标签。

❑利用清晰的正负样本区分规则对部分能够清晰区分的数据标记相应的正负标签。

1)首先在app.ddlog里定义transaction_label表,存储标记需要使用的数据:

其中,rule_id代表标记规则的名称。而label为正负标签,正值表示正相关,负值表示负相关。绝对值越大,相关性越大。

2)初始化定义,复制transaction_candidate表,将label预先填充为零。

3)将前文数据库中的数据导入transaction_label表中,将rule_id标记为"from\dbdata"。因为国泰安的数据比较官方,可以设置较高的权重,这里设为3。在app.ddlog中进行如下定义:

4)如果只利用下载的实体对,可能和未知文本中提取的实体对重合度较小,不利于特征参数推导。因此可以通过一些逻辑规则,对未知文本进行预标记。将标记函数supervise()写在udf/supervise_transaction.py脚本中。

说明:

❑输入候选实体对的关联文本,并在app.ddlog中定义标记函数;

❑标记函数调用udf/supervise_transaction.py脚本,规则名称和所占的权重定义在该脚本中。

5)调用标记函数,将规则抽到的数据写入transaction_label表中。

6)不同的规则可能覆盖了相同的实体对,从而给出不同甚至相反的标签,所以需要额外建立一张用于建立实体对标签的表,如transaction_label_resolved表。利用标签求和,在多条规则和知识库标记的结果中,为每对实体进行投票,决定最终标签类别。

7)执行以下命令,得到最终标签,用于构建实体抽取模型。

2.3.3 模型构建

通过之前的步骤,我们已经得到了所有前期需要准备的数据。下面可以构建模型了。

1.变量表定义

1)定义最终存储的表格,可以用“?”表示此表是用户模式下的变量表,即需要推导关系的表。下面代码预测的是公司间是否存在交易关系。

2)将打标签的结果(交易关系)输入到has_transaction表中。

此时变量表中的部分变量的label已知,成了先验变量。

3)最后编译执行transaction表:

2.关系概率模型生成

(1)指定特征

将每一对has_transaction中的实体对和特征表连接起来,通过特征的连接,从全局学习这些特征的权重。在app.ddlog中进行如下定义:

(2)指定变量间的依赖性

我们可以指定两张变量表间遵守的规则,并给予这个规则一定权重。比如c1和c2有交易,可以推出c2和c1也有交易,因此对这条规则可以给予较高权重:

变量表间的依赖性使得Deepdive很好地支持了多关系下的抽取。

(3)编译并生成最终的概率模型

查看我们预测的公司间交易关系概率(结果可能因数据集更新而发生变化):

至此,我们的交易关系抽取就完成了,在http://deepdive.stanford.edu中能够查阅到更详细的内容。