基于Brat标注数据集的python包network网络构建和搜索

一、前言

  在知识图谱的文本标注任务中,需要将数据按照事先决定的标注规则进行人工标注。Brat是一种比较著名的标注工具,但是目前不支持Windows系统,你可以安装虚拟机使用该工具。本文已经完成了一项基于Windows、Python3.7的标注软件制作工作,你可以点击 实体关系文本标注工具 进行查看。

  倘若你是使用的Brat标注工具, 并且对于Neo4j图数据库不是很熟悉,那你可以考虑使用Python中的network第三方库,在初步学习阶段实现demo,在下一篇文章中,将会介绍Neo4j的使用案例。

  本文将使用Brat工具标注的数据集,利用network第三方库构建图网络,并且实现对节点的多级检索。

二、数据准备

  本文从知网下载了一些关于医学文章的摘要,提前设置了标注规则,例如实体类别、关系等。通过Brat工具标注该文本数据并得到输出标注好的结果文件,该文件共有1314行,以T开头表示实体,以R开头表示关系,该文件是对网络图结构的文本表述。

在这里插入图片描述

三、网络构建

1、准备好一些必备的包,本文使用的是python3.7版本。

import re
import networkx as nx
import matplotlib.pyplot as plt
from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei'] #显示中文

2、读取数据

txtfile = open(r'E:\数据\1-70.ann', 'r', encoding='utf-8').readlines()
# print(txtfile[:3])

3、将文件中的实体、关系区分开

#将实体与关系数据分开
entity = []
relation = []
for i in txtfile:
    if i[0] == 'T':
        entity.append(i)
    else:
        relation.append(i)

# print(relation)

#将实体名称、类别与编号提取出来
entity = [i.strip('\n').split('\t') for i in entity]
entity = [[i[0],i[1].split(' ')[0], i[-1]] for i in entity]
# print(entity[:5])
#在实体表中插入数据
# #提取实体名,去重;需要提前查看数据库已有的实体名称 需要表名称
entitymin = [i[-1] for i in entity]
entitymin = list(set(entitymin))
# print(entitymin[:5])

4、利用区分开的实体、关系,将三元组提取出来,构建三元组。

#将三元组提取出来
relation = [re.split("[\tA:' ']",i) for i in relation]
relation = [[i[1],i[4],i[7]] for i in relation]
# print(relation[:5])

dicen = dict([('病症',1),('病名',2),('诊断方案',3),('治疗方案',4),('药名',5),('其它',6)])
dicre =  dict([('包含',1),('治疗',2),('危险因素',3),('辅助诊断',4),('特征',5),('并发',6),('别名',7),('作用',8),('条件',9)])
# print(dicre['包含'])

# #将三元组中的实体编号替换成实体名称
for r in relation:
    # r[0] = dicre[r[0]]
    for e in entity:
        if r[1] == e[0]:
            r[1] = e[-1]
            # r.insert(0,e[1])
        if r[-1] == e[0]:
            r[-1] = e[-1]
            # r.append(e[1])
    r.append(r[0])
# print(relation[:5])
relation = [tuple(r[1:]) for r in relation]
# print(relation[:5])
lista = []
for i in relation:
    if i[-1] == '别名':
        lista.append([i[1], i[0], i[-1]])
relation += lista
# print(lista)
# print(relation[:5])

5、利用network绘制图网络,并且将图网络保存到本地。

plt.figure(3, figsize=(48, 27)) # 这里控制画布的大小,可以说改变整张图的布局
plt.subplot(111)
M = nx.DiGraph()
M.add_weighted_edges_from(relation) 
    #传入数据,格式[('甲状腺疾病', '甲状腺功能亢进症', '包含'), ('甲状腺疾病', '甲状腺功能减退', '包含')]
edge_labels = nx.get_edge_attributes(M, 'weight') #取出实体之间的关系
pos =  nx.random_layout(M)
# pos = nx.spring_layout(G, iterations=30) #设置画图的样式
nx.draw(M, pos,edge_color="grey", node_size=80) #设置点的位置
nx.draw_networkx_edge_labels(M,pos, edge_labels=edge_labels, font_size=10) #边的格式设置
nx.draw(M,pos, node_size=120, with_labels=True,font_size = 10) #节点设置
plt.savefig("imag.png")
plt.show()

生成结果,自动保存在本地,需要放大观看:
在这里插入图片描述

四、多级节点搜索

基于上面第5步绘制的网络,接下来本文需要从这个网络中,对感兴趣的节点和邻近节点,以及邻近节点的邻近节点到任意深度的节点进行检索。

1、定义查找函数

def get_neigbors(g, node, depth=1):
    output = {}
    output1 = []
    layers = dict(nx.bfs_successors(g, source=node, depth_limit=depth))
    nodes = [node]
    for i in range(1,depth+1):
        output[i] = []
        for x in nodes:
            output[i].extend(layers.get(x,[]))
            output1.extend(layers.get(x,[]))
        nodes = output[i]
    print('这是节点:',output)
    return output1##print(get_neigbors(M, '990', depth = 4))#[23,12,14,23,45,65,78]
def newlist(M, a, alist):
    alist.insert(0,a)
    newlistcon = list()
    for index, name in enumerate(alist[:-1]):
        for name1 in alist[index+1:]:
            if M.get_edge_data(name,name1) != None:
                relation = M.get_edge_data(name,name1)['weight']
                newlistcon.append([name, name1, relation])
    lista = []
    for i in newlistcon:
        if i[-1] == '别名':
            lista.append([i[1], i[0], i[-1]])
    newlistcon += lista
    return newlistcon#print('这是新数据',newlist(M, '990', get_neigbors(M, '990', depth = 4)))

2、设置查找参数,例如:查找以“甲状腺疾病”节点,并且设置深度为2,返回所有与甲状腺疾病为邻近节点的节点,以及该邻近节点的邻近节点。

node,depth = '甲状腺疾病',2

3、绘图展示和结果输出

liststrnewcon = newlist(M, node, get_neigbors(M, node, depth = depth))
G = nx.DiGraph()
plt.figure(3, figsize=(32,18)) # 这里控制画布的大小,可以说改变整张图的布局
plt.subplot(111)
G.add_weighted_edges_from(liststrnewcon) #传入数据
edge_labels = nx.get_edge_attributes(G, 'weight') #取出实体之间的关系
# pos = nx.spring_layout(G, iterations=30) #设置画图的样式
pos =  nx.random_layout(G)
# pos = nx.spectral_layout(G)

nx.draw(G, pos,edge_color="grey", node_size=80) #设置点的位置
nx.draw_networkx_edge_labels(G,pos, edge_labels=edge_labels, font_size=15) #边的格式设置
nx.draw(G,pos, node_size=1500,node_color = 'skyblue',node_shape = 's', with_labels=True,font_size = 15,edge_color = 'red') #节点设置
plt.savefig("imag_jia1.png")
plt.show()

对检索结果生成网络图,自动保存本地,方便放大观看:
在这里插入图片描述

输出结果:

这是节点: {1: [‘甲状腺功能亢进症’, ‘甲状腺功能减退’, ‘甲状腺炎’, ‘咽异常感觉’, ‘脏器’, ‘Graves病’, ‘桥本甲状腺炎’, ‘甲状腺功能减退症’, ‘自身免疫性甲状腺疾病’, ‘许特莱细胞瘤’, ‘甲状腺腺瘤’, ‘结节性甲状腺肿’, ‘甲状腺囊性变病’, ‘甲状腺功能’, ‘甲状腺过氧化物酶抗体’, ‘TPOAb’, ‘甲状腺球蛋白抗体’, ‘TGAb’, ‘甲状腺瘤’, ‘原发性甲状腺机能亢进症’, ‘甲状腺癌’, ‘甲状腺良性疾病’, ‘咽异感症’, ‘TRAb’, ‘TMAb’, ‘桥本病’, ‘甲亢’, ‘桥本’, ‘甲减’, ‘晚期妇女’, ‘妊娠中’, ‘孕中晚期’, ‘桥本氏甲状腺炎’, ‘单纯性甲状腺肿’, ‘甲状腺乳头状癌’, ‘甲状腺恶性肿瘤’, ‘重症肌无力’, ‘MG’], 2: [‘急性化脓性甲状腺炎’, ‘亚急性甲状腺炎’, ‘慢性淋巴细胞性甲状腺炎’, ‘甲状腺上皮细胞’, ‘AITD’, ‘钙化’, ‘砂粒体’, ‘肿瘤样病变’, ‘甲状腺功能异常’, ‘TPO-Ab’, ‘原发性甲减’, ‘甲状腺结节’, ‘多灶性癌’, ‘乳头状腺癌’, ‘滤泡癌’, ‘未分化和癌髓样癌’, ‘乳头状癌’, ‘TSH受体抗体’, ‘甲状腺微粒体抗体’, ‘特异性抗体’, ‘病率较高’, ‘TSH’, ‘FT3’, ‘FT4’, ‘LP(a)’, ‘血脂’, ‘CHO’, ‘LDL’, ‘ApoB’, ‘亚临床甲亢’, ‘甲状腺功能亢进’, ‘亚临床甲减’, ‘腺瘤’, ‘微小乳头状癌’]}

五、完整项目数据和代码

以下方式均可:
1、私信留言、文末评论你的邮箱,博主定期回复。
2、点击: GitHub-network 进行下载(或者访问:https://github.com/chenyiadam/network.git )

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
brat标注的ann文件转换为BIO格式可以分为以下几个步骤: 1. 读取ann文件,获取标注的实体和其对应的位置信息。 2. 将实体按照位置信息在原始文本中标记出来。 3. 将标记好的文本按照BIO格式进行标注。 下面是一个简单的Python代码示例,用于将brat标注的ann文件转换为BIO格式: ```python def ann_to_bio(ann_file, txt_file): # 读取ann文件,获取标注的实体和其对应的位置信息 entities = [] with open(ann_file, 'r', encoding='utf-8') as f: for line in f: if line.startswith('T'): fields = line.strip().split('\t') entity_id = fields[0] entity_type, start, end = fields[1].split() start = int(start) end = int(end) entity_text = fields[2] entities.append((entity_id, entity_type, start, end, entity_text)) # 读取txt文件,获取文本内容 with open(txt_file, 'r', encoding='utf-8') as f: text = f.read() # 将实体按照位置信息在原始文本中标记出来 entity_positions = [] for entity in entities: entity_id, entity_type, start, end, entity_text = entity entity_position = (start, end, entity_type) entity_positions.append(entity_position) entity_positions.sort(key=lambda x: x[0]) last_end = 0 annotated_text = [] for start, end, entity_type in entity_positions: annotated_text.append(text[last_end:start]) annotated_text.append('[{}]'.format(entity_type)) annotated_text.append(text[start:end]) annotated_text.append('[/{}]'.format(entity_type)) last_end = end annotated_text.append(text[last_end:]) # 将标记好的文本按照BIO格式进行标注 bio_tags = [] for token in annotated_text: if token.startswith('['): bio_tags.append('B-' + token[1:-1]) elif token.startswith('[/'): bio_tags.append('I-' + token[2:-1]) else: bio_tags.append('O') # 输出BIO格式标注结果 for token, bio_tag in zip(annotated_text, bio_tags): print('{}\t{}'.format(token, bio_tag)) ``` 使用时只需调用`ann_to_bio`函数,将`ann_file`和`txt_file`参数分别替换为实际的ann文件和txt文件路径即可。函数将输出BIO格式的标注结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高山莫衣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值