前言:
之前看了云朵dalao的一篇关于关键词提取的文章,其中介绍的 Yake 模型采用了大写词、词位置、全文词频、上下文关系、句间词频等 5 个指标,计算候选词得分。感觉设计上较直观、易解释,但原 yake 库不支持中文,于是笔者便抄公式劣改了一番。
一、对中文复刻版 iyake_cn
原 yake 库的核心公式不多赘述,可浏览原文了解。由于中文没有像英文单词大写这样的特征,笔者只采用了后 4 个指标,我们来逐个实现一下。
1、前置准备
中文文本中也可能含有英语单词,可以先准备好两份停用词列表,读入成集合,这样在过滤停用词时可以大幅提高效率。可先行过滤掉数字,以及单个字的分词。
def get_stopwords(txt_file):
return set([line.strip() for line in open(txt_file, 'r', encoding='utf-8').readlines()])
stopwords = get_stopwords('english.txt').union(get_stopwords('chinese.txt'))
clean_str = re.sub(r'[0-9]', '', content) # content 为传入的原始文本
jb_lst = [w for w in jieba.lcut(clean_str) if len(w) > 1]
jb_lst = [w for w in jb_lst if w not in stop]
再准备好唯一词,即候选词列表,以便对每个候选词进行独立评分。
uni_lst = list(set(jb_lst))
uni_lst.sort(key=jb_lst.index) # 固定顺序唯一词
2、词位置指标 T_pos
依照越靠前的句子越重要的理念,词出现的位置也体现其重要程度。原 yake 库设计的是分析候选词所在的句子,用该句子在全文中的位置中位数来计算。笔者考虑既可以用词所在的句子
,也可以用词本身
在全文中的位置。也就是说 get_pos_lst()
可以传入分词列表(前文的 jb_lst
),也可以传入分句列表(见下文)。之后获取单个候选词在分词或分句列表中出现的所有位置,再计算位置中位数。在计算 T_pos 指标时,用的是二次 log 对数做归一化,为避免开头的词必然成为关键词的情形,将全文词位置(索引)从 1 开始计算。
def get_pos_lst(words_lst): # 分词的位置列表
return list(zip(words_lst, range(1, len(words_lst)+1)))
def get_T_pos(pos_lst, word): # 单个词的T_pos指标
_lst = [i[1] for i in pos_lst if word in i[0]]
_lst.sort()
half = len(_lst) // 2
median = (_lst[half] + _lst[~half]) / 2
return log2(log2(median+2))
绘制 y = log2(log2(2+x))
的图像,可见词位置越靠前,T_pos 分越低(Yake 模型中候选词最终得分越低,则越重要,T_pos 作为分子)。
from matplotlib import pyplot as plt
fro