查看原文
其他

心法利器[33] | 快速的关键词抽取baseline

机智的叉烧 CS的陋室 2022-08-24

心法利器


本栏目主要和大家一起讨论近期自己学习的心得和体会,与大家一起成长。具体介绍:仓颉专项:飞机大炮我都会,利器心法我还有


往期回顾

关键词抽取是一个很特殊的任务,这个任务的难点却非常鲜明:

  • 通常没什么训练数据,有监督方法可能哑火。
  • 场景依赖很大,通用性很难做到。
  • 只是辅助工作,所以重型武器很难进入,而且最好要快速有一个可靠的方案。

今天我来给大家快速地整一个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[0not 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[0for 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] | 词权重问题


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存