心法利器[33] | 快速的关键词抽取baseline
心法利器
本栏目主要和大家一起讨论近期自己学习的心得和体会,与大家一起成长。具体介绍:仓颉专项:飞机大炮我都会,利器心法我还有。
往期回顾
关键词抽取是一个很特殊的任务,这个任务的难点却非常鲜明:
通常没什么训练数据,有监督方法可能哑火。 场景依赖很大,通用性很难做到。 只是辅助工作,所以重型武器很难进入,而且最好要快速有一个可靠的方案。
今天我来给大家快速地整一个baseline,这个baseline的效果不见得非常优秀,但胜在无监督、开发成本低、灵活性高、速度快,能跑起来就是好的嘛。
方案思路
整个思路的核心其实非常简单,当NLP还处于统计时代,最关键的一个指标就是这个tf-idf,tf句子中的词频,idf对应出现在给定海量数据下的文章或者句子的个数,tf越高越重要,出现在文章的文章量越多,这个词越不重要,那么,很简单的,tf-idf就是一个非常简单评价词汇重要性的指标,甚至,在短文本场景,甚至tf都不需要考虑了,idf成了唯一的,简单的标准。
换言之,一个句子中,idf最高的几个词,就可以被认为是关键词。
上代码
idf这个指标是需要大量数据去训的。当然,我们也可以去拿一些用开放域数据训的来直接用,最为直接而可靠的,也是我自己比较喜欢的是jieba内的idf.txt,大家可以直接去jieba的源码里找,没记错应该是人民日报数据来训的,我自己的经验上来看,足够支撑常用的一些场景了。当然如果不够,可以自己找语料训一个,这里就不写这个脚本了,做一个数据统计然后求个log对各位大佬来说并不困难。
来看看预测代码怎么弄吧。
首先我们先确定一下这块代码需要的东西以及需要分的模块:
初始化,我们需要的加载是idf词典,同时我们也需要一个默认值,对未登录词给一个默认值。 预测模块。
这么看内容其实不会很多,我直接把代码放上来。
import jieba
import numpy as np
import heapq
class keywordExtractor():
def __init__(self):
idf_dict = {}
data_list = []
with open("./data/idf.txt") as f:
for line in f:
ll = line.strip().split(" ")
if len(ll) != 2:
continue
if ll[0] not in idf_dict:
idf_dict[ll[0]] = float(ll[1])
data_list.append(float(ll[1]))
self.__idf_dict = idf_dict
self.median = np.median(data_list)
def get_idf(self,word):
return self.__idf_dict.get(word, self.median)
def predict(self, query, top_n = 1):
if len(query) <= 2:
return [query]
# 切词
word_list = list(jieba.cut(query))
if len(word_list) < top_n:
return word_list
# 默认赋值
idf_list = []
for word in word_list:
idf_list.append(self.get_idf(word))
# 可以进行一些藏经相关的业务调整
# 归一化
weight_list = [i / max(idf_list) for i in idf_list]
zip_list = zip(range(len(weight_list)), weight_list)
n_large_idx = [i[0] for i in heapq.nlargest(top_n, zip_list, key=lambda x:x[1])]
return [word_list[i] for i in n_large_idx], weight_list
if __name__ == "__main__":
keyword_extractor = keywordExtractor()
print(keyword_extractor.predict("看最近的日程"))
print(keyword_extractor.predict("看最近的日程", 2))
加载:
加载这块直接走加载脚本就好了,这个应该不是很难,基本的读取操作了。 这里的默认值我使用的是中位数,属于经验值吧。 另外这里有一个细节,这个idf的词典我用的还是比较简单的
预测模块:
切词,然后根据词典查idf作为权重。 有一个模块我空了出来,这里可以根据自己的业务做一些权重的调整,例如基于位置的调权。 权重归一化,求一个相对的大小,为了避免长度导致的相对大小波动,所以归一化我这里除以的不是和,而是最大值。 另外这里求TOPN的方法也可以记录一下。
小结
这是一个无比简单但是还相对可靠的方案,大家要是想做可以用这个方式来试一下,甚至以可以用这个来做预标注来训练也行。
关键词抽取的方案网上说的真的少,我之前写过一篇词权重的文章,有兴趣大家可以看看其他的拓展方法,NLP.TM[20] | 词权重问题。