【传知代码】上下位关系自动检测方法(论文复现)

前言:在信息爆炸的时代,我们每天都沉浸在海量的数据和信息中。随着互联网技术的飞速发展,如何从这些信息中准确、高效地提取出有用的知识,成为了当下研究的热点。其中,上下位关系(也称为层级关系或种属关系)是知识图谱、自然语言处理和语义网等领域中的一个核心概念。它描述的是实体之间的层级关系,比如“狗是动物的一种”,“橡树是树的一种”等。这种关系不仅有助于我们更好地理解和组织信息,还能为智能问答、推荐系统、语义搜索等应用提供强大的支持。

本文所涉及所有资源均在传知代码平台可获取

目录

概述

演示效果

核心代码

写在最后


概述

        在自然语言的处理过程中,上下位关系(Is-a Relationship)是用来描述概念(也被称为术语)间的语义涵盖关系。在这里,上位词(Hypernym)代表了下位词(Hyponym)的抽象和泛化,而下位词则是对上位词的具体化和特定性。以“水果”为例,它与“苹果”、“香蕉”、“橙子”等词是同义的,而“汽车”、“电动车”、“自行车”等词则与“交通工具”相对应。在处理自然语言的任务时,深入理解概念间的层级关系对于执行如词义消歧、信息检索、自动问答和语义推理等任务都是至关重要的:

本文复现 论文,提出的文本中上位词检测方法,具体如下:

文本中上位词检测方法,即从文本中提取出互为上下位关系的概念。现有的无监督上位词检测方法大致可以分为两类——基于模式的方法和基于分布模型的方法:

1)基于模式的方法

其主要思想是利用特定的词汇-句法模式来检测文本中的上下位关系。例如,我们可以通过检测文本中是否存在句式“【词汇1】是一种【词汇2】”或“【词汇1】,例如【词汇2】”来判断【词汇1】和【词汇2】间是否存在上下位关系。这些模式可以是预定义的,也可以是通过机器学习得到的。然而,基于模式的方法存在一个众所周知的问题——极端稀疏性,即词汇必须在有限的模式中共同出现,其上下位关系才能被检测到。

2)基于分布模型的方法

基于大型文本语料库,词汇可以被学习并表示成向量的形式。利用特定的相似度度量,我们可以区分词汇间的不同关系。

在该论文中,作者研究了基于模式的方法和基于分布模型的方法在几个上下位关系检测任务中的表现,并发现简单的基于模式的方法在常见的数据集上始终优于基于分布模型的方法。作者认为这种差异产生的原因是:基于模式的方法提供了尚不能被分布模型准确捕捉到的重要上下文约束。

作者使用如下Hearst模式来捕捉文本中的上下位关系,通过对大型语料库使用模式捕捉候选上下位词对并统计频次,可以计算任意两个词汇之间存在上下位关系的概率:

模板例子
XX which is a (example|class|kind…) of YYCoffee, which is a beverage, is enjoyed worldwide.
XX (and|or) (any|some) other YYCoffee and some other hot beverages are popular in the morning.
XX which is called YYCoffee, which is called “java”.
XX is JJS (most)? YYCoffee is the most consumed beverage worldwide.
XX is a special case of YYEspresso is a special case of coffee.
XX is an YY thatA latte is a coffee that includes steamed milk.
XX is a !(member|part|given) YYA robot is a machine.
!(features|properties) YY such as X1X1​, X2X2​, …Beverages such as coffee, tea, and soda have various properties such as caffeine content and flavor.
(Unlike|like) (most|all|any|other) YY, XXUnlike most beverages, coffee is often consumed hot.
YY including X1X1​, X2X2​, …Beverages including coffee, tea, and hot chocolate are served at the café.

设 p(x,y)p(x,y)是词汇 xx 和 yy 分别作为下位词和上位词出现在预定义模式集合 PP 中的频率,p−(x)p−(x)是 xx 作为任意词汇的下位词出现在预定义模式中的频率,p+(y)p+(y)是 yy 作为任意词汇的上位词出现在预定义模式中的频率。作者定义正逐点互信息(Positive Point-wise Mutual Information)作为词汇间上下位关系得分的依据:

由于模式的稀疏性,部分存在上下位关系的词对并不会出现在特定的模式中。为了解决这一问题,作者利用PPMI得分矩阵的稀疏表示来预测任意未知词对的上下位关系得分。PPMI得分矩阵定义如下:

其中 m=|\{x|(x,y)\in P\or(y,x)\in P\}|,对矩阵 MM 做奇异值分解可得 M=UΣVTM=UΣVT,然后我们可以通过下式计算出上下位关系 spmi 得分,其中 uxux​ 和 vyvy​ 分别是矩阵 UU 和 VV 的第 xx 行和第 yy 行,ΣrΣr​是对 ΣΣ 的 rr 截断(即除了最大的 rr 个元素其余全部置零):

演示效果

拿到代码解压附件压缩包并进入工作目录。如果是Linux系统,请使用如下命令:

unzip Revisit-Hearst-Pattern.zip
cd Revisit-Hearst-Pattern

代码的运行环境可通过如下命令进行配置:

pip install -r requirements.txt
python -m spacy download en_core_web_sm# 如果希望在本地运行程序,请运行如下命令:
python main.py# 如果希望在线部署,请运行如下命令:
python main-flask.py

如果希望添加新的模板,请修改文件data/patterns.json,

"_HYPONYM_"表示下位词占位符;    

"_HYPERNYM_"表示上位词占位符;

其余格式请遵照 python.re 模块的正则表达式要求。

如果希望使用自己的文件路径或改动其他实验设置,请在文件config.json中修改对应参数。以下是参数含义对照表:

参数名含义
corpus_path文本语料库文件路径,默认为“data/corpus.txt”。
patterns_path预定义模式库的路径。默认为“data/patterns.json”。
pairs_path利用模式筛选出的上下位关系词对路径,默认为“data/pairs.json”。
spmi_path上下位关系词对及其spmi得分路径,默认为“data/spmi.json”。
clip用于对 ΣΣ 进行截断的参数 rr ,默认为10。
thresholdspmi得分小于该值的词对将被舍去。默认为1。
max_bytes输入文件大小上限(用于在线演示),默认为200kB。

运行脚本main.py,程序会自动检测语料库中存在的上下位关系。运行结果如下所示:

核心代码

下面这段代码实现了一个术语上下位关系提取的流程,包括文本清理、句子划分、术语抽取、共现关系抽取、SPMI 计算等步骤。

        代码中的 clear_text 函数用于清理文本,例如删除交叉引用标识。split_sentences 函数用于将文本划分为句子。extract_noun_phrases 函数用于从句子中抽取名词性短语,作为候选术语。term_lemma 函数用于将术语中的名词还原为单数。find_co_occurrence 函数用于找出共现于模板的术语对。count_unique_tuple 函数用于统计列表中独特元组出现次数。find_rth_largest 函数用于找到数组中第 r 大的元素。find_pairs 函数用于读取文件并找出共现于模板的上下位关系术语对。spmi_calculate 函数用于基于对共现频率的统计,计算任意两个术语间的 spmi 得分。

在主函数中,代码首先读取配置文件和模板,然后读取语料库中共现于模板的术语对,并统计上下位关系的出现频次。接下来,代码计算任意两个术语间的 spmi 得分,并将结果输出到文件中:

import spacy
import json
from tqdm import tqdm
import re
from collections import Counter
import numpy as np
import mathnlp = spacy.load("en_core_web_sm")def clear_text(text):"""对文本进行清理"""# 这里可以添加自己的清理步骤# 删去交叉引用标识,例如"[1]"pattern = r'\[\d+\]'result = re.sub(pattern, '', text)return resultdef split_sentences(text):"""将文本划分为句子"""doc = nlp(text)sentences = [sent.text.strip() for sent in doc.sents]return sentencesdef extract_noun_phrases(text):"""从文本中抽取出术语"""doc = nlp(text)terms = []# 遍历句子中的名词性短语(例如a type of robot)for chunk in doc.noun_chunks:term_parts = []for token in list(chunk)[-1::]:# 以非名词且非形容词,或是代词的词语为界,保留右半部分(例如robot)if token.pos_ in ['NOUN', 'ADJ'] and token.dep_ != 'PRON':term_parts.append(token.text)else:breakif term_parts != []:term = ' '.join(term_parts)terms.append(term)return termsdef term_lemma(term):"""将术语中的名词还原为单数"""lemma = []doc = nlp(term)for token in doc:if token.pos_ == 'NOUN':lemma.append(token.lemma_)else:lemma.append(token.text)return ' '.join(lemma)def find_co_occurrence(sentence, terms, patterns):"""找出共现于模板的术语对"""pairs = []# 两两之间匹配for hyponym in terms:for hypernym in terms:if hyponym == hypernym:continuefor pattern in patterns:# 将模板中的占位符替换成候选上下位词pattern = pattern.replace('__HYPONYM__', re.escape(hyponym))pattern = pattern.replace('__HYPERNYM__', re.escape(hypernym))# 在句子中匹配if re.search(pattern, sentence) != None:# 将名词复数还原为单数pairs.append((term_lemma(hyponym), term_lemma(hypernym)))return pairsdef count_unique_tuple(tuple_list):"""统计列表中独特元组出现次数"""counter = Counter(tuple_list)result = [{"tuple": unique, "count": count} for unique, count in counter.items()]return resultdef find_rth_largest(arr, r):"""找到第r大的元素"""rth_largest_index = np.argpartition(arr, -r)[-r]return arr[rth_largest_index]def find_pairs(corpus_file, patterns, disable_tqdm=False):"""读取文件并找出共现于模板的上下位关系术语对"""pairs = []# 按行读取语料库lines = corpus_file.readlines()for line in tqdm(lines, desc="Finding pairs", ascii=" 123456789#", disable=disable_tqdm):# 删去首尾部分的空白字符line = line.strip()# 忽略空白行if line == '':continue# 清理文本line = clear_text(line)# 按句处理sentences = split_sentences(line)for sentence in sentences:# 抽取出句子中的名词性短语并分割成术语candidates_terms = extract_noun_phrases(sentence)# 找出共现于模板的术语对pairs = pairs + find_co_occurrence(sentence, candidates_terms, patterns)return pairsdef spmi_calculate(configs, unique_pairs):"""基于对共现频率的统计,计算任意两个术语间的spmi得分"""# 计算每个术语分别作为上下位词的出现频次terms = list(set([pair["tuple"][0] for pair in unique_pairs] + [pair["tuple"][1] for pair in unique_pairs]))term_count = {term: {'hyponym_count': 0, 'hypernym_count': 0} for term in terms}all_count = 0for pair in unique_pairs:term_count[pair["tuple"][0]]['hyponym_count'] += pair["count"]term_count[pair["tuple"][1]]['hypernym_count'] += pair["count"]all_count += pair["count"]# 计算PPMI矩阵 ppmi_matrix = np.zeros((len(terms), len(terms)), dtype=np.float32)for pair in unique_pairs:hyponym = pair["tuple"][0]hyponym_id = terms.index(hyponym)hypernym = pair["tuple"][1]hypernym_id = terms.index(hypernym)ppmi = (pair["count"] * all_count) / (term_count[hyponym]['hyponym_count'] * term_count[hypernym]['hypernym_count'])ppmi = max(0, math.log(ppmi))ppmi_matrix[hyponym_id, hypernym_id] = ppmi# 对PPMI进行奇异值分解并截断r = configs['clip']U, S, Vt = np.linalg.svd(ppmi_matrix)S[S < find_rth_largest(S, r)] = 0S_r = np.diag(S)# 计算任意两个术语间的spmiparis2spmi = []for hyponym_id in range(len(terms)):for hypernym_id in range(len(terms)):# 同一个术语间不计算得分if hyponym_id == hypernym_id:continuespmi = np.dot(np.dot(U[hyponym_id , :], S_r), Vt[:, hypernym_id]).item()# 保留得分大于阈值的术语对if spmi > configs["threshold"]:hyponym = terms[hyponym_id]hypernym = terms[hypernym_id]paris2spmi.append({"hyponym": hyponym, "hypernym": hypernym, "spmi": spmi})# 按spmi从大到小排序paris2spmi = sorted(paris2spmi, key=lambda x: x["spmi"], reverse=True)return paris2spmiif __name__ == "__main__":# 读取配置文件with open('config.json', 'r') as config_file:configs = json.load(config_file)# 读取模板with open(configs['patterns_path'], 'r') as patterns_file:patterns = json.load(patterns_file)# 语料库中共现于模板的术语对with open(configs['corpus_path'], 'r', encoding='utf-8') as corpus_file:pairs = find_pairs(corpus_file, patterns)# 统计上下位关系的出现频次unique_pairs = count_unique_tuple(pairs)with open(configs["pairs_path"], 'w') as pairs_file:json.dump(unique_pairs, pairs_file, indent=6, ensure_ascii=True)# 计算任意两个术语间的spmi得分paris2spmi = spmi_calculate(configs, unique_pairs)with open(configs['spmi_path'], 'w') as spmi_file:json.dump(paris2spmi, spmi_file, indent=6, ensure_ascii=True)

写在最后

        回顾我们所探讨的上下位关系自动检测方法,我们不难发现,这一领域的研究正逐步走向成熟。从最初的基于规则的方法,到如今的深度学习和神经网络模型,我们见证了技术的飞速进步和无限可能。这些方法不仅提高了检测的准确性和效率,更拓宽了我们的知识视野,让我们能够更加深入地理解世界的复杂性和多样性。

        然而,正如所有科学探索一样,上下位关系自动检测也面临着诸多挑战和机遇。随着数据量的不断增长和模型复杂度的提高,我们需要更加高效和准确的算法来处理这些海量的信息。同时,我们也需要关注模型的泛化能力和鲁棒性,确保它们能够在不同的场景和领域中都能发挥出优秀的性能,随着技术的不断发展和应用场景的不断拓展,我们有理由相信,上下位关系自动检测将会迎来更加广阔的发展前景。它将不仅仅局限于自然语言处理和知识图谱等领域,更将深入到智能问答、推荐系统、语义搜索等更多领域,为我们的生活带来更加便捷和智能的体验。

详细复现过程的项目源码、数据和预训练好的模型可从该文章下方附件获取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/851247.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vscode 中 eslint 无效?npm init 是什么?

vscode 中 eslint 无效 我想要给一个项目添加 eslint&#xff0c;按照 eslint 官方指南操作&#xff1a; npm init eslint/configlatest自动安装了相关依赖并创建配置文件 eslint.config.mjs。 按理说&#xff0c;此刻项目应该已经配置好 eslint 了。但是我的编辑器 vscode …

《python程序语言设计》2018版第5章第36题改造4.17 石头 剪刀 布某一方超过2次就结束。

代码编写记录 2024.05.04 05.36.01version 换一个什么数代替剪子 我先建立一个函数judgement condition 石头3 剪子2 布1 如何构建一个循环进行的架构&#xff0c;是我们最需要的想法 循环以什么条件开始呢 是小于2个还是大于2个。 guess_num random.randint(1, 3) computer…

Python 和 Java 实现云计算的最终年项目

1、问题背景 目前&#xff0c;我正在进行我的最终年项目&#xff0c;计划用 Python 编写一个云计算系统&#xff0c;而云客户端将由我的团队成员使用 Java 来编写。这个云客户端将具有一个带有标签的界面&#xff0c;并提供文本编辑器、媒体播放器、几个基于 Java 的小游戏以及…

按键精灵在Win11中弹窗出现乱码并且自带的部分系统插件不能使用的解决方法

按键精灵中出现以下问题&#xff1a; 提示信息的弹窗出现乱码&#xff1a; 系统自带的部分像 plugin. 开头的插件不能使用&#xff0c;如下&#xff1a;s Plugin.Sys.GetDateTime() screenX Plugin.GetSysInfo.GetScreenResolutionX screenY Plugin.GetSysInfo.GetScreenRe…

⌈ 传知代码 ⌋ 记忆大师

&#x1f49b;前情提要&#x1f49b; 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间&#xff0c;对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

IDEA去除代码和XML中的波浪线(黄色警告线)

通常情况下&#xff0c;IDE自带的侦测功能会帮我们提示一些错误、警告等。但这对于强迫症患者来说并不友好。以下是去除IDE代码和XML文件中的波浪线&#xff08;黄色警告线&#xff09;、拯救强迫症患者的有效方案 1、去除XML中的波浪线 2、去除代码中的波浪线 关爱强迫症患者…

VUE2.7项目配置webpack打包-详细操作步骤

一、Webpack简介 Webpack是一个打包工具&#xff0c;可以把JS、CSS、Node Module、Coffeescrip、SCSS/LESS、图片等都打包在一起&#xff0c;因此&#xff0c;现在几乎所有的SPA项目、JS项目都会用到Webpack。 官网&#xff1a;https://webpack.js.org GitHub为https://git…

error 12154 received logging on to the standby报错处理

错误 处理方法 该参数不是主库的servicename &#xff08;低级错误&#xff09; SQL> alter system set log_archive_dest_2 SERVICEstandby ASYNC VALID_FOR(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAMEstandby; System altered. 观察主库日志: 备库日志: 该问题会影…

vue2自定义指令

本节目标 快速入门v-loading 快速入门 指令对比 基本语法 使用: v-指令名"指令值"定义: 通过 directives 局部定义或者全局定义通过事件对象 el 可以拿到指令所在元素通过形参 binding 可以拿到指令的传值通过update钩子, 可以监听指令值的变化,进行更新操作 局部…

C++进阶:继承

文章目录 继承的概念继承的定义方式继承关系和访问限定符基类和派生类对象的赋值转换继承中的作用域派生类中的默认成员函数构造函数拷贝构造函数赋值拷贝函数析构函数 总结 继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允…

一个开源的Office软件,很离谱的办公神器

你们平时用的办公软件是哪一个&#xff1f;今天给大家分享的是一个“进阶版”office工具ONLY OFFICE&#xff0c;不仅支持Windows、Mac、ios, 安卓等全平台满足你的日常所需&#xff0c;更是提供了大量开挂般的功能。 1、打工人省金币 你们平时使用办公软件最头疼的问题是什么…

第1章Hello world 3/5:Cargo.lock:确保构建稳定可靠:运行第一个程序

讲动人的故事,写懂人的代码 1.6 Cargo.lock:确保构建稳定可靠 “看!”席双嘉一边指着屏幕一边说,“终端窗口提示符的颜色,从绿变黄了。这就意味着代码在上次提交后有点变化。” 赵可菲:“但是我们只是运行了程序,代码应该没动呀。” 席双嘉敲了下git status -uall,这…

PawSQL优化 | 分页查询太慢?别忘了投影下推

​在进行数据库应用开发中&#xff0c;分页查询是一项非常常见而又至关重要的任务。但你是否曾因为需要获取总记录数的性能而感到头疼&#xff1f;现在&#xff0c;让PawSQL的投影下推优化来帮你轻松解决这一问题&#xff01;本文以TPCH的Q12为案例进行验证&#xff0c;经过Paw…

高考志愿填报的技巧和方法

高考过后&#xff0c;最让家长和学生需要重视的就是怎样填报志愿。高考完和出成绩之前有一段很长的时间&#xff0c;而成绩出来之后往往报考的时间非常的紧张。在很短的时间内&#xff0c;高考的学生和他的家长要综合高考的成绩&#xff0c;考虑院校&#xff0c;专业&#xff0…

PHP实现一个简单的接口签名方法以及思路分析

文章目录 签名生成说明签名生成示例代码签名校验示例代码 签名生成说明 B项目需要调用A项目的接口&#xff0c;由A项目为B项目分配 AccessKey 和 SecretKey&#xff0c;用于接口加密&#xff0c;确保不易被穷举&#xff0c;生成算法不易被猜测。 最终需要确保包含签名的参数只…

32-读取Excel数据(xlrd)

本篇介绍如何使在python中读取excel数据。 一、环境准备 先安装xlrd模块&#xff0c;打开cmd&#xff0c;输入 pip install xlrd 在线安装。 二、基本操作 import xlrd# 打开excel表格 data xlrd.open_workbook(test.xlsx)# 2.获取sheet表格 # 方式一&#xff1a;通过索引顺…

RocketMq详解:二、SpringBoot集成RocketMq

在上一章中我们对Rocket的基础知识、特性以及四大核心组件进行了详细的介绍&#xff0c;本章带着大家一起去在项目中具体的进行应用&#xff0c;并设计将其作为一个工具包只提供消息的分发服务和业务模块进行解耦 在进行本章的学习之前&#xff0c;需要确保你的可以正常启动和…

MySQL中的数据库约束

目录 导读&#xff1a; 约束类型 1、not null&#xff08;不能为空&#xff09; 2、unique(唯一) 3、default(默认值约束) 4、primary key(唯一)与unique 相同点&#xff1a; 不同点&#xff1a; auto_increment&#xff1a; 5、foreign key(外键) 语法形式&#xff…

康姿百德集团公司官网床垫价格透明,品质睡眠触手可及

选择康姿百德床垫&#xff0c;价格透明品质靠谱&#xff0c;让你拥有美梦连连 在当今社会&#xff0c;良好的睡眠质量被越来越多的人所重视。睡眠不仅关系到我们第二天的精力状态&#xff0c;更长远地影响着我们的身体健康。因此&#xff0c;选择一款合适的床垫对于获得优质睡…

antdv 穿梭框

antd的穿梭框的数据貌似只接收key和title&#xff0c;而且必须是字符串&#xff08;我测试不是字符串的不行&#xff09;&#xff0c; 所以要把后端返回的数据再处理一下得到我们想要的数据 除了实现简单的穿梭框功能&#xff0c;还想要重写搜索事件&#xff0c;想达到的效果是…