一.原理部分
1.TF/IDF原理
https://blog.csdn.net/asialee_bird/article/details/81486700
2.TextRank原理
https://blog.csdn.net/qq_41664845/article/details/82869596
3.LSI原理
https://blog.csdn.net/qq_16633405/article/details/80577851
4.LDA原理
https://blog.csdn.net/u011808673/article/details/82497195
https://blog.csdn.net/btujack/article/details/98477061
二.对2019年12.14日贸易战新闻进行提取关键词,训练corpus为人民日报新闻
# -*- coding: utf-8 -*-
import math
import jieba
import jieba.posseg as psg
from gensim import corpora, models
from jieba import analyse
import functools
# 停用词表加载方法
def get_stopword_list():
# 停用词表存储路径,每一行为一个词,按行读取进行加载
# 进行编码转换确保匹配准确率
stop_word_path = 'stopword.txt'
stopword_list = [sw.replace('\n', '') for sw in open(stop_word_path,encoding='utf-8').readlines()]
return stopword_list
# 分词方法,调用结巴接口
def seg_to_list(sentence, pos=False):
if not pos:
# 不进行词性标注的分词方法
seg_list = jieba.cut(sentence)
else:
# 进行词性标注的分词方法
seg_list = psg.cut(sentence)
return seg_list
# 去除干扰词
def word_filter(seg_list, pos=False):
stopword_list = get_stopword_list()
filter_list = []
# 根据POS参数选择是否词性过滤
## 不进行词性过滤,则将词性都标记为n,表示全部保留
for seg in seg_list:
if not pos:
word = seg
flag = 'n'
else:
word = seg.word
flag = seg.flag
if not flag.startswith('n'):
continue
# 过滤停用词表中的词,以及长度为<2的词
if not word in stopword_list and len(word) > 1:
filter_list.append(word)
return filter_list
# 数据加载,pos为是否词性标注的参数,corpus_path为数据集路径
def load_data(pos=False, corpus_path='./corpus.txt'):
# 调用上面方式对数据集进行处理,处理后的每条数据仅保留非干扰词
doc_list = []
for line in open(corpus_path, 'r',encoding='utf-8'):
content = line.strip()
seg_list = seg_to_list(content, pos)
filter_list = word_filter(seg_list, pos)
doc_list.append(filter_list)
return doc_list
# idf值统计方法
def train_idf(doc_list):
idf_dic = {}
# 总文档数
tt_count = len(doc_list)
# 每个词出现的文档数
for doc in doc_list:
for word in set(doc):
idf_dic[word] = idf_dic.get(word, 0.0) + 1.0
# 按公式转换为idf值,分母加1进行平滑处理
for k, v in idf_dic.items():
idf_dic[k] = math.log(tt_count / (1.0 + v))
# 对于没有在字典中的词,默认其仅在一个文档出现,得到默认idf值
default_idf = math.log(tt_count / (1.0))
return idf_dic, default_idf
# 排序函数,用于topK关键词的按值排序
def cmp(e1, e2):
import numpy as np
res = np.sign(e1[1] - e2[1])
if res != 0:
return res
else:
a = e1[0] + e2[0]
b = e2[0] + e1[0]
if a > b:
return 1
elif a == b:
return 0
else:
return -1
# TF-IDF类
class TfIdf(object):
# 四个参数分别是:训练好的idf字典,默认idf值,处理后的待提取文本,关键词数量
def __init__(self, idf_dic, default_idf, word_list, keyword_num):
self.word_list = word_list
self.idf_dic, self.default_idf = idf_dic, default_idf
self.tf_dic = self.get_tf_dic()
self.keyword_num = keyword_num
# 统计tf值
def get_tf_dic(self):
tf_dic = {}
for word in self.word_list:
tf_dic[word] = tf_dic.get(word, 0.0) + 1.0
tt_count = len(self.word_list)
for k, v in tf_dic.items():
tf_dic[k] = float(v) / tt_count
return tf_dic
# 按公式计算tf-idf
def get_tfidf(self):
tfidf_dic = {}
for word in self.word_list:
idf = self.idf_dic.get(word, self.default_idf)
tf = self.tf_dic.get(word, 0)
tfidf = tf * idf
tfidf_dic[word] = tfidf
tfidf_dic.items()
# 根据tf-idf排序,去排名前keyword_num的词作为关键词
for k, v in sorted(tfidf_dic.items(), key=functools.cmp_to_key(cmp), reverse=True)[:self.keyword_num]:
print(k + "/ ", end ='')
print()
# 主题模型
class TopicModel(object):
def __init__(self, doc_list, keyword_num, model='LSI', num_topics=4):
# 使用gensim的接口,将文本转为向量化表示 先构建词空间
self.dictionary = corpora.Dictionary(doc_list)
# BOW模型向量化
corpus = [self.dictionary.doc2bow(doc) for doc in doc_list]
# 对每个词,根据tf-idf进行加权,得到加权后的向量表示
self.tfidf_model = models.TfidfModel(corpus)
self.corpus_tfidf = self.tfidf_model[corpus]
self.keyword_num = keyword_num
self.num_topics = num_topics
# 选择模型
if model == 'LSI':
self.model = self.train_lsi()
else:
self.model = self.train_lda()
# 得到数据集的主题-词分布
word_dic = self.word_dictionary(doc_list)
self.wordtopic_dic = self.get_wordtopic(word_dic)
def train_lsi(self):
lsi = models.LsiModel(self.corpus_tfidf, id2word=self.dictionary, num_topics=self.num_topics)
return lsi
def train_lda(self):
lda = models.LdaModel(self.corpus_tfidf, id2word=self.dictionary, num_topics=self.num_topics)
return lda
def get_wordtopic(self, word_dic):
wordtopic_dic = {}
for word in word_dic:
single_list = [word]
wordcorpus = self.tfidf_model[self.dictionary.doc2bow(single_list)]
wordtopic = self.model[wordcorpus]
wordtopic_dic[word] = wordtopic
return wordtopic_dic
# 计算词的分布和文档的分布的相似度,取相似度最高的keyword_num个词作为关键词
def get_simword(self, word_list):
sentcorpus = self.tfidf_model[self.dictionary.doc2bow(word_list)]
senttopic = self.model[sentcorpus]
# 余弦相似度
def calsim(l1, l2):
a, b, c = 0.0, 0.0, 0.0
for t1, t2 in zip(l1, l2):
x1 = t1[1]
x2 = t2[1]
a += x1 * x1
b += x1 * x1
c += x2 * x2
sim = a / math.sqrt(b * c) if not (b * c) == 0.0 else 0.0
return sim
# 计算输入文本和每个词的主题分布相似度
sim_dic = {}
for k, v in self.wordtopic_dic.items():
if k not in word_list:
continue
sim = calsim(v, senttopic)
sim_dic[k] = sim
for k, v in sorted(sim_dic.items(), key=functools.cmp_to_key(cmp), reverse=True)[:self.keyword_num]:
print(k + "/ ", end='')
print()
# 词空间构建方法和向量化方法
def word_dictionary(self, doc_list):
dictionary = []
for doc in doc_list:
dictionary.extend(doc)
dictionary = list(set(dictionary))
return dictionary
def doc2bowvec(self, word_list):
vec_list = [1 if word in word_list else 0 for word in self.dictionary]
return vec_list
def tfidf_extract(word_list, pos=False, keyword_num=10):
doc_list = load_data(pos)
idf_dic, default_idf = train_idf(doc_list)
tfidf_model = TfIdf(idf_dic, default_idf, word_list, keyword_num)
tfidf_model.get_tfidf()
def textrank_extract(text, pos=False, keyword_num=10):
textrank = analyse.textrank
keywords = textrank(text, keyword_num)
# 输出关键词
for keyword in keywords:
print(keyword + "/ ", end='')
print()
def topic_extract(word_list, model, pos=False, keyword_num=10):
doc_list = load_data(pos)
topic_model = TopicModel(doc_list, keyword_num, model=model)
topic_model.get_simword(word_list)
if __name__ == '__main__':
text = '经过中美两国经贸团队的共同努力,双方在平等和相互尊重原则的基础上,已就中美第'+\
'一阶段经贸协议文本达成一致。协议文本包括序言、知识产权、技术转让、食品和农产品、金融服务、'+\
'汇率和透明度、扩大贸易、双边评估和争端解决、最终条款九个章节。同时,双方达成一致,美方将履行'+\
'分阶段取消对华产品加征关税的相关承诺,实现加征关税由升到降的转变。中方认为,中美两国作为全球'+\
'最大经济体,处理两国经贸关系必须从大局出发,达成经贸协议有利于中美两国人民和世界人民的根本利益,'+\
'将在经贸、投资、金融市场等方面产生积极效应。本协议总体上符合中国深化改革开放的大方向,以及自身'+\
'推动经济高质量发展的内在需要。协议相关内容的落实,将有助于强化知识产权保护,改善营商环境,扩大市场准入,'+\
'更好维护包括外国企业在内的各类企业在华合法权益,也有利于保护中方企业在对美经贸活动中的合法权益。随着'+\
'中国国内市场的扩大,中方企业按照世贸组织规则和市场化、商业化原则,增加从包括美国在内的各国进口优质、'+\
'有竞争力的产品和服务,有助于顺应国内消费升级的趋势,满足人民日益增长的美好生活需要。本协议有利于中美两国'+\
'加强经贸领域的合作,有效管控和解决经贸领域的分歧,促进中美经贸关系稳定发展。在当前全球经济面临下行压力'+\
'的背景下,本协议有利于增强全球市场信心,稳定市场预期,为正常的经贸和投资活动创造良好环境。'+\
'双方约定,下一步双方将各自尽快完成法律审核、翻译校对等必要的程序,并就正式签署协议的具体安排进行协商。'+\
'协议签署后,希望双方能够遵守协议约定,努力落实好第一阶段协议相关内容,多做有利于双边经贸关系发展和全球经济'+\
'金融稳定的事情,维护世界和平与繁荣。'
pos = True
seg_list = seg_to_list(text, pos)
filter_list = word_filter(seg_list, pos)
print('TF-IDF模型结果:')
tfidf_extract(filter_list)
print('TextRank模型结果:')
textrank_extract(text)
print('LSI模型结果:')
topic_extract(filter_list, 'LSI', pos)
print('LDA模型结果:')
topic_extract(filter_list, 'LDA', pos)
三.运行结果
TF-IDF模型结果:
协议/ 经贸/ 双方/ 中美/ 两国/ 全球/ 知识产权/ 文本/ 合法权益/ 双边/
TextRank模型结果:
协议/ 经贸/ 有利于/ 全球/ 扩大/ 双方/ 包括/ 两国/ 中美/ 加征/
LSI模型结果:
中国/ 世界/ 全球/ 团队/ 产品/ 企业/ 环境/ 经济/ 食品/ 方面/
LDA模型结果:
法律/ 基础/ 市场/ 总体/ 企业/ 产生/ 人民/ 美国/ 领域/ 趋势
四.分析
TF-IDF模型、TextRank模型实际效果比LSI和LDA效果好