2021SC@SDUSC
上一篇博客中,我们完成了对项目中utils.py的分析,在本篇博客中,我们将分析pke中的tfidf.py文件,首先我们将结合论文分析tf-idf指标的计算方法,接着结合实例的使用和tf-idf源码进行分析。
我们知道,关键短语生成问题实际上是为一系列短语提供排名,所以我们需要一些方法去为候选的短语进行排名,我们注意到词汇和语意的相似性对关键短语的排名是非常重要的,因此本项目结合了两种相似性进行排名,以得到sliver labels.
首先是嵌入相似性,我们知道,像类似于WordVec和Doc2Vec技术是可以将提取的关键短语和文档编码在同一空间中的,因为此,语意相似性就可以用空间中的余弦距离来测量,本篇文章中wikipedia英文数据集训练好的Doc2Vec模型将语料库中的文档和候选关键短语都编码成300维度的向量,如果我们将文档和关键短语的嵌入表示为,,那么语意相似性层面可用公式以下公式计算:
而TF-IDF衡量的是词汇级别的相似性,特别地,对于一个预料库,其中一个文档,其含有的单词数为, 对于短语而言,其在文档出现的次数计作,而表示了在语料库中,有多少文章中出现了短语.其在词汇级别的相似度可以如下表示:
当文档很长时,TF-IDF的评分是稳定的,Doc2Vec对短文档和相对较长的文档的编码都很可靠,用几何平均数将语意和词汇相似性结合起来,便可综合考虑两种相似性。其最终计算公式如下:
下面给出关键词提取后用tf-idf评分的一个例子并分析相关代码。
import string import pke # 创建一个TfIdf extractor extractor = pke.unsupervised.TfIdf() # 加载文档内容 extractor.load_document(input='path/to/input', language='en', normalization=None) # 选择不包含标点符号的{1-3}语法作为候选 extractor.candidate_selection(n=3,stoplist=list(string.punctuation)) # 使用' tf ' x ' idf '对候选项进行加权 df = pke.load_document_frequency_file(input_file='path/to/df.tsv.gz') extractor.candidate_weighting(df=df) # 把得分最高的10个候选短语作为关键短语 keyphrases = extractor.get_n_best(n=10)
首先是导入了pke包,然后在pke的unsupervised方法中,创建一个TfIdf对象作为extractor,调用load_document函数加载文档,将stoplist赋值为标点符号的list,即关键短语不含标点符号,ngram特征为3。之后载入文档频率文件,指定其输入路径,得到的结果为candidate_weighting的参数df,最后调用get_n_best方法得到了得分最高的10歌候选关键短语。
tfidf.py的结构如下,主要有两个函数,candidate_selection和candidate_weighting,前一个函数实现了关键词的提取,后一个函数用tf-idf给关键词进行排序。
首先是导入相关的包。
from __future__ import absolute_import from __future__ import division from __future__ import print_function import math import string import logging # 日志模块 from pke.base import LoadFile from pke.utils import load_document_frequency_file # 加载文档频率文件
我们先来看candidate_selection函数:
def candidate_selection(self, n=3, stoplist=None, **kwargs): # 选取1-3gram特征的短语作为keyphrase candidate # 从1-3选择ngram self.ngram_selection(n=n) # 如果没有stopplist,则初始化stopplist为空列表 if stoplist is None: stoplist = list(string.punctuation) # 过滤包含标点符号的候选关键短语 self.candidate_filtering(stoplist=stoplist)
关于该函数的参数:
再看candidate_weighting函数:
def candidate_weighting(self, df=None): #使用文档频率的候选关键词的得分计算函数 # 如果没有提供文档频率计数,则初始化默认文档频率计数 if df is None: logging.warning('LoadFile._df_counts is hard coded to {}'.format(self._df_counts)) df = load_document_frequency_file(self._df_counts, delimiter='\t') # 初始化文档数量为--NB_DOC--+ 1 N = 1 + df.get('--NB_DOC--', 0) # 循环candidates for k, v in self.candidates.items(): # 获取候选文档频率 candidate_df = 1 + df.get(k, 0) # 计算idf得分 idf = math.log(N / candidate_df, 2) # 将idf分数添加到权重容器中 self.weights[k] = len(v.surface_forms) * idf
关于参数df的说明:df为文档的频率,文档的数量使用"--NB_DOC--" 键指定。