实体消歧应用¶
学习目标¶
- 理解实体消歧的思想和原理
- 掌握实现实体消歧的代码
1 实体消岐¶
- 实体消歧的本质在于一个单词很可能有多个意思,也就是在不同的上下文中所表达的含义可能不太一样。
-
举例说明:
- 首先我们需要准备一个类似于下面的这种实体库:
id 实体名称 实体描述 1001 苹果 苹果公司没几年 1002 苹果 水果的一种,一般产自于。。。 -
当我们拿到text时,比如“今天苹果发布了新的手机”,我们可以将实体库中的实体描述,全部转换为向量。
[今天,发布了新的手机] ⇒ 向量(tf-idf) ;水果中的一种,一般产自于 ⇒ 向量(tf-idf);美国一家高科技公司,经典的产品有iphone 手机 ⇒ 向量(tf-idf)
基于上述向量做相似度的计算,如果S1>S2 分类成Fruit, 反之分类成苹果公司
2 案例介绍¶
- 将句中识别的实体与知识库中实体进行匹配,解决实体歧义问题。
-
数据介绍
- 在data/entity_disambiguation目录中,有两个csv文件,其中entity_list.csv是已经存在的真实实体信息,valid_data.csv是需要消歧的语句。
- entity_list.csv数据格式
entity_id,entity_name,desc 1001,小米|小米公司|小米科技有限责任公司|XIAOMI,"北京小米科技有限责任公司成立于2010年3月3日 [1] ,是一家专注于智能硬件和电子产品研发的移动互联网公司,同时也是一家专注于高端智能手机、互联网电视以及智能家居生态链建设的创新型科技企业。 [2] 为发烧而生”是小米的产品概念。小米公司创造了用互联网模式开发手机操作系统、发烧友参与开发改进的模式。小米还是继苹果、三星、华为之后第四家拥有手机芯片自研能力的科技公司。" 1002,小米,小米,原名:粟,也称作粱、狗尾草、黄粟、粟米,拉丁文名:Setaria italica (L.) Beauv. var. germanica (Mill.) Schrad. 禾本科、狗尾草属一年生草本,须根粗大,秆粗壮,粟是谷子去皮后的结果,谷子是谷类植物,禾木本的一种,粟的营养价值很高,含丰富的蛋白质和脂肪和维生素,它不仅供食用,入药有清热、清渴,滋阴,补脾肾和肠胃,利小便、治水泻等功效,又可酿酒。其茎叶又是牲畜的优等饲料,它含粗蛋白质5-7%,超过一般牧草的含量1.5-2倍,而且纤维素少,质地较柔软,为骡、马所喜食;其谷糠又是猪、鸡的良好饲料。 1003,小米,小米是在电视剧《武林外传》中登场的次要人物,同福客栈门口的乞丐,丐帮四袋弟子。他是一个有休息日的乞丐,每逢初一十五,小米自己给自己放假,如果你把铜板扔到他的破碗里,他会毫不犹豫还给你。不过你可别以为他就这么不要了,哈哈,当休息日一过,小米又开工时,他可是会抢回本属于自己的铜板的哦! 1004,苹果|apple,"苹果是水果中的一种,是蔷薇科苹果亚科苹果属植物,其树为落叶乔木。苹果的果实富含矿物质和维生素,是人们经常食用的水果之一。entity_list.csv格式分为三列,第一列entity_id代表实体的编号;第二列entity_name为实体名称,第三列desc为实体的描述信息,不同列之间用","分隔开。
- valid_data.csv数据格式
id,sentence 1,"一说到华盛顿特区(Washington, D.C.),大家心中浮现的一定是气势恢宏的美国总统官邸─白宫(White House),这个掌控美国、牵动全球政经活动的白色建筑,不仅在历史上占有举足轻重的地位,更是每个人来到华盛顿特区非去不可的景点之一。到这里除了跟白宫合照,留下到此一游的证据外,还有许多重要地标与藏品丰富的博物馆,错过这些景点,虽不至于遗憾终身,但可能不算到过华盛顿喔!" 2,"很多的网友都会有这样的一个问题,明明华盛顿和乾隆死在了同一年,为何却给人的感觉不是一个时代的人呢?" 3,"1799年12月14日,美利坚合众国的开国元勋华盛顿溘然长逝。然后,美国人对当年华盛顿的死因,仍然心存疑虑,事隔200多年后,人们对他的死因又有新的发现。"valid_data.csv格式分为两列,第一列id代表要消岐的实体编码id;第二列sentence描述实体的原始句子,不同列之间用","分割开。
- 实现步骤:
- 读取数据:首先读取包含实体列表的
entity_list.csv和包含待处理句子的valid_data.csv。 - 处理实体名称:将
entity_list.csv中的实体名称添加到分词词典中,确保可以在后续分词和匹配过程中识别这些实体。 - 计算TF-IDF特征矩阵:将每个实体的描述通过分词处理后生成TF-IDF特征矩阵,用于后续的相似度计算。
- 匹配句子中的实体:在
valid_data.csv中的句子中找到关键词,并通过TF-IDF相似度计算找到与关键词匹配的实体ID。 - 输出结果:将句子中匹配到的实体及其位置与对应的实体ID存储为新的CSV文件。
- 读取数据:首先读取包含实体列表的
-
代码实现
import pandas as pd import numpy as np import os import collections import jieba from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity # 获取当前工作目录路径 bast_path = os.getcwd() # TODO:将entity_list.csv中已知实体的名称导入分词词典 # 读取实体列表文件(entity_list.csv),包含实体名称和描述信息 entity_data = pd.read_csv(os.path.join(bast_path, 'data/entity_disambiguation/entity_list.csv'), encoding='utf-8') print(f'entity_data--》{entity_data.head()}') # TODO:对每句句子识别并匹配实体 # 读取包含待处理句子的文件(valid_data.csv) valid_data = pd.read_csv(os.path.join(bast_path, 'data/entity_disambiguation/valid_data.csv'), encoding='gb18030') print(f'valid_data--》{valid_data.head()}') # 将实体名称拼接成一个长字符串,并用'|'分隔,用于统计实体名称的出现次数 s = '' keyword_list = [] for i in entity_data['entity_name'].values.tolist(): s += i + '|' # 统计实体名称在字符串中的出现次数,如果某个名称出现次数超过一次,则将其加入keyword_list(关键词列表) for k, v in collections.Counter(s.split('|')).items(): if v > 1: keyword_list.append(k) # 生成TF-IDF矩阵 # 对实体的描述信息进行分词,将每个实体描述分词后的结果存入train_sentence列表中 train_sentence = [] for i in entity_data['desc'].values: train_sentence.append(' '.join(jieba.cut(i))) print(len(train_sentence)) # 初始化TF-IDF向量化工具 vectorizer = TfidfVectorizer() # 将实体描述信息转换为TF-IDF特征矩阵 X = vectorizer.fit_transform(train_sentence) print(X) print(X.toarray().shape) # 定义获取实体ID的函数,根据给定的句子计算其与实体描述的TF-IDF余弦相似度,返回最相似的实体ID def get_entityid(sentence): id_start = 1001 # 假设实体ID从1001开始 a_list = [' '.join(jieba.cut(sentence))] # 对输入句子分词 print(f'a_list--》{a_list}') print(vectorizer.transform(a_list)) # 将句子转换为TF-IDF特征 print(cosine_similarity(vectorizer.transform(a_list), X)) # 计算句子与所有实体描述的余弦相似度 res = cosine_similarity(vectorizer.transform(a_list), X)[0] # 获取相似度结果 top_idx = np.argsort(res)[-1] # 获取最相似的实体在TF-IDF矩阵中的索引 print(f'np.argsort(res)==>{np.argsort(res)}') return id_start + top_idx # 返回实体ID # TODO:将计算结果存入文件 print(f'keyword_list--》{keyword_list}') # 初始化行计数器和结果列表 row = 0 result_data = [] neighbor_sentence = '' # 遍历valid_data中的每一个句子,处理其中的关键词 for sentence in valid_data['sentence']: print(f'sentence--》{sentence}') res = [row] # 初始化结果列表,首先添加当前行号 for keyword in keyword_list: if keyword in sentence: # 如果句子中包含关键词 print(f'keyword--》{keyword}') k_len = len(keyword) # 计算关键词的长度 print(f'k_len--》{k_len}') ss = '' for i in range(len(sentence) - k_len + 1): if sentence[i:i+k_len] == keyword: # 如果在句子中找到关键词 s = str(i) + '-' + str(i + k_len) + ':' # 获取关键词在句子中的位置(如"0-5") print(f's-->{s}') # 获取包含关键词的邻近句子,用于计算实体相似度 if i > 10 and i + k_len < len(sentence) - 9: neighbor_sentence = sentence[i-10:i+k_len+9] elif i < 10: neighbor_sentence = sentence[:20] elif i + k_len > len(sentence) - 9: neighbor_sentence = sentence[-20:] # 调用get_entityid函数,获取与邻近句子最相似的实体ID s += str(get_entityid(neighbor_sentence)) ss += s + '|' # 将位置和实体ID拼接成字符串 res.append(ss[:-1]) # 将处理结果加入到当前行的结果中 break result_data.append(res) # 将当前句子的处理结果加入结果列表 row += 1 # 行计数器加1 # 将结果保存为CSV文件,文件路径为'entity_disambiguation_submit.csv' pd.DataFrame(result_data).to_csv('entity_disambiguation_submit.csv', index=False)
小节总结¶
本小节主要介绍了实体消岐的原理,以及如何通过代码实现实体消岐任务。