关键字抽取算法
TF-IDF
TF-IDF称为词频逆文本,结果严重依赖文本分词之后的效果。其公式又可以分成词频(Term Frequency,TF)的计算和逆文档概率(IDF)的计算。
TF的计算较为简单,统计每个词出现的频次。计算公式如式1所示:
这里需要注意的是,该词的词频仅仅是计算在单一文档的词频,而不是所有文档出现的词频。也就是说每个词在不同的文档中出现的词频可能是不一样的。
IDF的计算稍显复杂,统计该词在所有文档出现的次数。也就是说如果该词仅在少数领域文档中出现,那么该词就在该领域更具有代表性,更可能是关键词。计算公式如式2所示:
TF-IDF的计算也就是两者的乘积,具体如下式3所示:
jieba中竟然实现了TF-IDF关键字抽取,使用如下:
import sys import jieba import jieba.analyse import argparse def parser_args(): parser = argparse.ArgumentParser(description='parse input information') parser.add_argument('--filename', default='./data/files.txt', type=str) parser.add_argument('--top_k', default=5, type=int) args = parser.parse_args() return args args = parser_args() content = open(args.filename, 'rb').read() jieba.analyse.set_idf_path("./data/idf.txt.big.txt") tags = jieba.analyse.extract_tags(content, topK=args.top_k) print(",".join(tags))
另外自己实现了一份源码,
import jieba import math def read_file(filepath): with open(filepath, 'r', encoding='utf-8') as file: lines = file.readlines() return lines def load_stop_word(filepath): with open(filepath, 'r', encoding='utf-8') as file: data = file.readlines() stop_words = set() for word in data: stop_words.add(word.strip()) return list(stop_words) def segment_line(line, stop_words): # start paddle segment jieba.enable_paddle() words_list = jieba.cut(line.strip(), use_paddle=True) results = [] for word in words_list: if word not in stop_words: results.append(word) return results def cal_term_frequency(lines_results): lines_tf = [] for line_result in lines_results: temp_tf = {} for word in line_result: if word in temp_tf.keys(): temp_tf[word] += 1 else: temp_tf[word] = 1 lines_tf.append(temp_tf) return lines_tf def cal_idf(lines_tf): idf = {} for line_tf in lines_tf: for word in line_tf.keys(): if word not in idf.keys(): idf[word] = 1 else: idf[word] += 1 return idf def cal_tf_idf(lines_tf, idf): lines_tf_idf = [] for line_tf in lines_tf: temp_tf_idf = {} for word, tf in line_tf.items(): temp_tf_idf[word] = tf * math.log(len(lines_tf) / (idf[word] + 1)) lines_tf_idf.append(temp_tf_idf) return lines_tf_idf
TextRank
TextRank是一种基于图的排序算法,其思想来自于PageRank算法。TextRank算法有一篇较为经典的老论文( TextRank: Bringing Order into Texts),值得一读。
PageRank算法
PageRank最重要的也就是考虑了网络节点的出度(在有向图上),相对于其他的Rank算法。当然,PageRank也可以用于无向图,这就导致节点的出度等于入度,效果可能会稍微差点。其计算公式如下式4所示。
其中各个参数含义如下:
S ( V i ) :网页V i 的重要度(权重),初始值默认为1。
d:阻尼系数,一般为0.85,也就是看当前节点改变的自身的状态权重。
I n ( V i ):能跳转到网页V i 的页面,在图中对应入度对应的点。
O u t ( V j ):网页V j 能够跳转到的页面,在图中对应的出度的点。
TextRank关键字提取
提取关键词也可以采取和“网页中选哪个网页比较重要”类似的方法,只需要想办法把图构建出来。图的结点是“词”。把文章拆成句子,每个句子再拆成词,以词为结点。那么边如何定义呢?这里就可以利用n-gram的思路,简单来说,某个词,只与它附近的n个词有关,即与它附近的n个词对应的结点连一条无向边(两个有向边)。另外,还可以做一些操作,比如把某类词性的词删掉,一些自定义词删掉,只保留一部分单词,只有这些词之间能够连边。也就是TextRank的计算方法如下式5所示。
TextRank文章摘要提取
TextRank也可以用来提取文章摘要,以句子为节点,利用两个句子之间的相似度来计算边。两个句子的相似度如式5所示:
这个相似度也可以使用其他的计算方法,如word embedding来表示句子,来计算余弦相似度等。
python中已经实现TextRank实现的封装:
import codecs from textrank4zh import TextRank4Keyword, TextRank4Sentence text = codecs.open('./text/01.txt', 'r', 'utf-8').read() tr4w = TextRank4Keyword(stop_words_file='./stopword.data') # 导入停止词 # 使用词性过滤,文本小写,窗口为2 tr4w.train(text=text, speech_tag_filter=True, lower=True, window=2) print('关键词:') # 20个关键词且每个的长度最小为1 print('/'.join(tr4w.get_keywords(20, word_min_len=1)) ) print('关键短语:') # 20个关键词去构造短语,短语在原文本中出现次数最少为2 print('/'.join(tr4w.get_keyphrases(keywords_num=20, min_occur_num= 2))) tr4s = TextRank4Sentence(stop_words_file='./stopword.data') # 使用词性过滤,文本小写,使用words_all_filters生成句子之间的相似性 tr4s.train(text=text, speech_tag_filter=True, lower=True, source = 'all_filters') print('摘要:') print('\n'.join(tr4s.get_key_sentences(num=3))) # 重要性最高的三个句子
甚至在jieba中提供TextRank的接口,可以实现关键字抽取。
import jieba.analyse import argparse def parser_args(): parser = argparse.ArgumentParser(description='parse input information') parser.add_argument('--filename', default='./data/files.txt', type=str) parser.add_argument('--top_k', default=5, type=int) args = parser.parse_args() return args args = parser_args() content = open(args.filename, 'rb').read() tags = jieba.analyse.textrank(content, topK=args.top_k, allowPOS=('n', 'nz', 'v', 'vd', 'vn', 'l', 'a', 'd')) print(",".join(tags))
总结
这是常用的一些无监督的关键字抽取算法,主要可以用在推荐系统中,给用户按照关键字信息进行推荐,目前可能也有一些基于Transformer的关键字抽取,抽取的效果可能更佳准确,下周将对其进行扩展。
Reference
[1] TextRank系列之关键词提取算法_北木.的博客-CSDN博客_textrank英文关键词提取
[2] TextRank_coco_1998_2的博客-CSDN博客_textrank
[3] NLP中关键字提取方法总结和概述 - 知乎 (zhihu.com)
[4] Mihalcea R , Tarau P . TextRank: Bringing Order into Texts[J]. 2004.