2021SC@SDUSC
简介
在上一篇博客中提到,程序正常运行后得到的评分矩阵元素均为0,为了对中文打分需要对原程序的打分模块进行修改。
由于程序可以正常运行,因此可以对程序进行debug分析处理流程。
这里将可以得到评分矩阵的原程序(PositionRank)和针对中文修改算法后的新程序(PositionRank2)进行逐步debug对比:
当二者都执行完词列表过滤算法后结果如下:
PositionRank:
PositionRank2
即positionrank2的候选词被清空了!
因此可以确定词列表过滤算法不适用于对中文的处理。
词列表过滤算法
该算法分析如下:
def filter_candidates(self, stopwords_file=None, max_phrase_length=4, min_word_length=3, valid_punctuation='-.'):
"""
基于多重保证进行词项过滤
:param stopwords_file: 停用词列表文件
:param max_phrase_length: 最长短语长度
:param min_word_length: 最短词长度
:param valid_punctuation: 特殊符号
:return:
"""
# 如果停用词没有提供
stopwords_list = []
if stopwords_file is None:
from nltk.corpus import stopwords
stopwords_list = set(stopwords.words('english'))
else:
with codecs.open(stopwords_file, 'rb', encoding='utf-8') as f:
f.readlines()
f.close()
for line in f:
stopwords_list.append(line)
indices = []
for i, c in enumerate(self.candidates):
tokens = c.surface_form.split()
pos = c.pos_pattern.split()
# 去除含有停用词的部分
if set(tokens).intersection(stopwords_list):
indices.append(i)
# 去除过长的短语
elif len(tokens) > max_phrase_length:
indices.append(i)
# 去除太短的词
elif min([len(t) for t in tokens]) < min_word_length:
indices.append(i)
# 去除形容词和以形容词结尾的短语
elif pos[-1] == 'JJ':
indices.append(i)
elif set(tokens).intersection(set(['-lrb-', '-rrb-', '-lcb-', '-rcb-', '-lsb-', '-rsb-'])):
indices.append(i)
else:
# 去除包含特殊字符的短语
for word in tokens:
letters_set = set([u for u in word])
if letters_set.issubset(punctuation):
indices.append(i)
break
elif re.match(r'^[a-zA-Z0-9%s]*$' % valid_punctuation, word):
continue
else:
indices.append(i)
break
dels = 0
for index in indices:
offset = index - dels
dels += 1
del self.candidates[offset]
算法修改
去除对于单个词长度的限制
原程序中会限制word的长度,例如“a”、“an”长度为1和2会被去除,而中文的单个词长度始终为1。
正则表达式加入对中文的匹配
if re.match(r'^[\u4e00-\u9fa5_a-zA-Z0-9]+$' % valid_punctuation, word):
continue
再次运行程序,
得到了正常的weights列表
指标计算算法
currentP, currentR, currentF1 = \
evaluation.PRF_range(system.get_best_k(args.topK), gold_stemmed, k=args.topK)
关键词是“自然语言处理”
而预测的结果是“自然 语言 处理”
二者取交集,结果为空集。这是因为之前该程序是针对英文的处理程序,每个词之间需要空格,而中文无需空格。回溯predicted的生成,定位到如下代码:
# 选择一个单词,遍历该句中本单词后的所有内容,如果词性满足我们的要求并且之间的距离小于n(或单词长度-1)
for j in range(0, len(tokens)):
for k in range(j, len(tokens)):
# 将满住要求的n-grams加入候选列表candidates
if pos_tags[k] in good_pos and k - j < max_length and k < (len(tokens) - 1):
self.candidates.append(Candidate(' '.join(tokens[j:k + 1]), ' '.join(pos_tags[j:k + 1]),
' '.join(stems[j:k + 1]), j + jump, i))
else:
break
可见词之间通过空格连接,将连接方式改为:
''.join(tokens[j:k + 1])
再次运行,得到了正确的结果:
运行程序果不其然得到了评估矩阵