【毕业设计】基于LTP的需求文本分析研究-2021.4.21
说明
本文作为个人向记录,内容为毕业设计期间学习的技术总结。
LTP内容均来源于官网:https://ltp.readthedocs.io/zh_CN/latest/appendix.html
技术版本
LTP模型:3.4.0
pyltp:0.2.1
LTP工具集
分句
对比之后,LTP分句效果比nltk更好
分词
分词部分使用能够调整词频的jieba分词代替
词性标注
LTP 使用的是863词性标注集,其各个词性含义如下表。
Tag | Description | Example | Tag | Description | Example |
---|---|---|---|---|---|
a | adjective | 美丽 | ni | organization name | 保险公司 |
b | other noun-modifier | 大型, 西式 | nl | location noun | 城郊 |
c | conjunction | 和, 虽然 | ns | geographical name | 北京 |
d | adverb | 很 | nt | temporal noun | 近日, 明代 |
e | exclamation | 哎 | nz | other proper noun | 诺贝尔奖 |
g | morpheme | 茨, 甥 | o | onomatopoeia | 哗啦 |
h | prefix | 阿, 伪 | p | preposition | 在, 把 |
i | idiom | 百花齐放 | q | quantity | 个 |
j | abbreviation | 公检法 | r | pronoun | 我们 |
k | suffix | 界, 率 | u | auxiliary | 的, 地 |
m | number | 一, 第一 | v | verb | 跑, 学习 |
n | general noun | 苹果 | wp | punctuation | ,。! |
nd | direction noun | 右侧 | ws | foreign words | CPU |
nh | person name | 杜甫, 汤姆 | x | non-lexeme | 萄, 翱 |
z | descriptive words | 瑟瑟,匆匆 |
命名实体识别
其中,words
和 postags
分别为分词和词性标注的结果。同样支持Python原生的list类型。
LTP 采用 BIESO 标注体系。B 表示实体开始词,I表示实体中间词,E表示实体结束词,S表示单独成实体,O表示不构成命名实体。
LTP 提供的命名实体类型为:人名(Nh)、地名(Ns)、机构名(Ni)。
B、I、E、S位置标签和实体类型标签之间用一个横线 -
相连;O标签后没有类型标签。
LTP中的NE 模块识别三种NE,分别如下:
标记 | 含义 |
---|---|
Nh | 人名 |
Ni | 机构名 |
Ns | 地名 |
依存句法分析
arc.head
表示依存弧的父节点词的索引。ROOT节点的索引是0,第一个词开始的索引依次为1、2、3…
arc.relation
表示依存弧的关系。
arc.head
表示依存弧的父节点词的索引,arc.relation
表示依存弧的关系。
依存句法关系标注集:
关系类型 | Tag | Description | Example |
---|---|---|---|
主谓关系 | SBV | subject-verb | 我送她一束花 (我 <– 送) |
动宾关系 | VOB | 直接宾语,verb-object | 我送她一束花 (送 –> 花) |
间宾关系 | IOB | 间接宾语,indirect-object | 我送她一束花 (送 –> 她) |
前置宾语 | FOB | 前置宾语,fronting-object | 他什么书都读 (书 <– 读) |
兼语 | DBL | double | 他请我吃饭 (请 –> 我) |
定中关系 | ATT | attribute | 红苹果 (红 <– 苹果) |
状中结构 | ADV | adverbial | 非常美丽 (非常 <– 美丽) |
动补结构 | CMP | complement | 做完了作业 (做 –> 完) |
并列关系 | COO | coordinate | 大山和大海 (大山 –> 大海) |
介宾关系 | POB | preposition-object | 在贸易区内 (在 –> 内) |
左附加关系 | LAD | left adjunct | 大山和大海 (和 <– 大海) |
右附加关系 | RAD | right adjunct | 孩子们 (孩子 –> 们) |
独立结构 | IS | independent structure | 两个单句在结构上彼此独立 |
核心关系 | HED | head | 指整个句子的核心 |
语义角色标注
第一个词开始的索引依次为0、1、2…
返回结果 roles
是关于多个谓词的语义角色分析的结果。由于一句话中可能不含有语义角色,所以结果可能为空。
role.index
代表谓词的索引, role.arguments
代表关于该谓词的若干语义角色。
arg.name
表示语义角色类型,arg.range.start
表示该语义角色起始词位置的索引,arg.range.end
表示该语义角色结束词位置的索引。
例如上面的例子,由于结果输出一行,所以“元芳你怎么看”有一组语义角色。 其谓词索引为3,即“看”。这个谓词有三个语义角色,范围分别是(0,0)即“元芳”,(1,1)即“你”,(2,2)即“怎么”,类型分别是A0、A0、ADV。
arg.name
表示语义角色关系,arg.range.start
表示起始词位置,arg.range.end
表示结束位置。
关系类型 | Tag | Description | Example |
---|---|---|---|
ARG0 | causers or experiencers | 施事者、主体、触发者 | [政府 ARG0]鼓励个人投资服务业。 |
ARG1 | patient | 受事者 | 政府鼓励[个人 ARG1]投资服务业。 |
ARG2 | range | 语义角色2 | 政府鼓励个人[投资服务业 ARG2]。 |
ARG3 | starting point | 语义角色3 | 巴基斯坦[对谈判前景 ARG3]表示悲观。 |
ARG4 | end point | 语义角色4 | 产检部门将产检时间缩短到[一至三天 ARG4]。 |
ADV | adverbial | 状语 | 我们[即将 ADV]迎来新年。 |
BNF | beneficiary | 受益人 | 义务[为学童及老师 BNF]做超音波检查 。 |
CND | condition | 条件 | [如果早期发现 CND],便能提醒当事人注意血压的变化。 |
CRD | coordinated arguments | 并列 | 跟南韩、[跟美国 CRD]谋求和平关系的举动也更加积极。 |
DGR | degree | 程度 | 贫铀弹含有放射性比铀强[20万倍 DGR]。 |
DIR | direction | 方向 | [从此处 DIR] 我们可以发现寇克斯报告的精髓。 |
DIS | discourse marker | 会话标记 | 警方上午针对目击者做笔录,[而 DIS]李士东仍然不见踪影。 |
EXT | extent | 范围 | 回归3年多[来 EXT] ,香港成为台商对大陆贸易的财务运作及资金调度中心。 |
FRQ | frequency | 频率 | 这类听证会在赖昌兴拘押期间每30天举行[一次 FRQ]。 |
LOC | locative | 地点 | 请听美国之音特邀记者康妮[在加拿大温哥华 LOC]发来的报道。 |
MNR | manner | 方式 | 以便他能继续[作为俄罗斯官员 MNR]从事他在一个特殊机构中的工作。 |
PRP | purpose or reason | 目的 | 执政党和在野党[为了应付这场攻守战 PRP]都发出了紧急动员令。 |
QTY | quantity | 数量 | 每年创汇[100万 QTY]美元。 |
TMP | temporal | 时间 | [下星期 TMP]布什将提出一项周密计划。 |
TPC | topic | 话题 | [这么大的事情 TPC],你怎么不和我说? |
PRD | predicate | 谓语动词 | |
PSR | possessor | 持有者 | |
PSE | possessee | 被持有 |
运行记录
代码
LTP工具:
# 代码参考:https://www.itdaan.com/blog/2018/03/15/c324a4cfaf408bfcc5a98c6145f269eb.html
class LtpLanguageAnalysis(object):
def __init__(self, model_dir=os.path.abspath("resource/ltp_data_v3.4.0")):
self.segmentor = Segmentor()
self.segmentor.load(os.path.join(model_dir, "cws.model"))
self.postagger = Postagger()
self.postagger.load(os.path.join(model_dir, "pos.model"))
self.parser = Parser()
self.parser.load(os.path.join(model_dir, "parser.model"))
self.recognizer = NamedEntityRecognizer()
self.recognizer.load(os.path.join(model_dir, "ner.model"))
self.labeller = SementicRoleLabeller()
self.labeller.load(os.path.join(model_dir, "pisrl_win.model"))
def load_model(self, model_dir=os.path.abspath("resource/ltp_data_v3.4.0")):
self.segmentor.load(os.path.join(model_dir, "cws.model"))
self.postagger.load(os.path.join(model_dir, "pos.model"))
self.parser.load(os.path.join(model_dir, "parser.model"))
self.recognizer.load(os.path.join(model_dir, "ner.model"))
self.labeller.load(os.path.join(model_dir, "pisrl_win.model"))
def analyze(self, txt):
# 分词
words = self.segmentor.segment(txt)
print('\t'.join(words))
# 词性标注
postags = self.postagger.postag(words)
print('\t'.join(postags))
# 命名实体识别
netags = self.ner(words, postags)
print("\t".join(netags))
# 依存句法分析
arcs = self.parse(words, postags)
print("\t".join("%d:%s" % (arc.head, arc.relation) for arc in arcs))
# 语义角色标注
roles = self.srl(words, postags, arcs)
for role in roles:
print([
role.index,
"".join(["%s:(%d,%d)" % (arg.name, arg.range.start, arg.range.end) for arg in role.arguments])
])
def parse(self, words, postags):
# 依存句法分析
arcs = self.parser.parse(words, postags)
return arcs
def ner(self, words, postags):
# 命名实体识别
netags = self.recognizer.recognize(words, postags)
return netags
def srl(self, words, postags, arcs):
# 语义角色标注
roles = self.labeller.label(words, postags, arcs)
return roles
def release_model(self):
# 释放模型
self.segmentor.release()
self.postagger.release()
self.parser.release()
self.recognizer.release()
self.labeller.release()
测试内容:
import jieba_nlp_util as jnu
from ltp_util import LtpLanguageAnalysis
def test_pyltp(txt):
print("-----LTP分析:-----")
# 导入ltp模型
ltp = LtpLanguageAnalysis(os.path.abspath("../resource/ltp_data_v3.4.0"))
# 文本分析
# 分段
paragraphs = txt.split('\n')
for paragraph in paragraphs:
# 使用nltk分句
# sentences = nu.txt_split(paragraph)
# 使用ltp分句
sentences = lu.ltp_split(paragraph)
for sentence in sentences:
# 使用jieba分词
signed_words = jnu.default_cut(sentence)
words = []
flags = []
for word, flag in signed_words:
if flag == 'x':
# 删去标点符号
continue
words.append(word)
flags.append(flag)
print_words_and_flags(words, flags)
arcs = ltp.parse(words, flags)
netags = ltp.ner(words, flags)
roles = ltp.srl(words, flags, arcs)
print("\t".join(netags))
print("\t".join("%d:%s" % (arc.head, arc.relation) for arc in arcs))
for role in roles:
print([
role.index,
" ".join(["%s:(%d,%d)" % (arg.name, arg.range.start, arg.range.end) for arg in role.arguments])
])
print()
# 释放模型
ltp.release_model()
内容
未删去'x'标注词:
删去'x'标注词:
结论
- 通过进行LTP语义角色标注,以是否删去'x'标注(包括标点符号等)为变量:
- 不删去:语义标注可能会遗漏","等后面的受事者(A1)
- 删去:如果一个标点前的受事者与这个标点后的施事者相同,可能导致两者被分到一个角色里面
- 考虑:
- 可根据标点后(尤其是",")是否存在连词,来判断标点后的子句是否与标点前的有较强的内容联系,这种标点可以删去
- 可以根据标点后主语与标点前宾语是否相同,来决定这个逗号是不是应该当成句号处理(分句)
- 更多规则...