前面我们已经介绍了关键词提取算法的一些理论知识,这里我们主要看一些简单的示例。我们用到的库包括Jieba和Gensim。
除了TextRank,其他的算法都需要一个已知的数据集才能正常工作。
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).readlines()] #获取其中的停用词
return stopword_list
######定义分词方法######
###pos为是否只保留名词的依据
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
######加载数据集######
def load_data(pos=False,corpus_path='./corpus.txt'):
#对数据进行预处理
doc_list=[]
for line in open(corpus_path,'r'):
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
######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
######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))
#对没有出现的次,默认出现1次
default_idf=math.log(tt_count/(1.0))
return idf_dic,default_idf
######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() #TF数据
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
#根据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):
###参数:处理后的数据集、关键词数量、具体模型(LSI、LDA)、主题数量
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)
###训练LSI
def train_lsi(self):
lsi=models.LsiModel(self.corpus_tfidf,id2word=self.dictionary,num_topics=self.num_topics)
return lsi
###训练LDA
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)]
worktopic=self.model[wordcorpus]
wordtopic_dic[word]=wordtopic
return wordtopic_dic
#计算词的分布与文本的相似度,取最高的几个作为关键词
def get_simword(self,word_list):
sentcorpus=self.tfidf_model[self.dictionary.doc2bow(word_list)]
sentcorpus=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()
# 词空间构建方法和向量化方法,在没有gensim接口时的一般处理方法
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 = '6月19日,《2012年度“中国爱心城市”公益活动新闻发布会》在京举行。' + \
'中华社会救助基金会理事长许嘉璐到会讲话。基金会高级顾问朱发忠,全国老龄' + \
'办副主任朱勇,民政部社会救助司助理巡视员周萍,中华社会救助基金会副理事长耿志远,' + \
'重庆市民政局巡视员谭明政。晋江市人大常委会主任陈健倩,以及10余个省、市、自治区民政局' + \
'领导及四十多家媒体参加了发布会。中华社会救助基金会秘书长时正新介绍本年度“中国爱心城' + \
'市”公益活动将以“爱心城市宣传、孤老关爱救助项目及第二届中国爱心城市大会”为主要内容,重庆市' + \
'、呼和浩特市、长沙市、太原市、蚌埠市、南昌市、汕头市、沧州市、晋江市及遵化市将会积极参加' + \
'这一公益活动。中国雅虎副总编张银生和凤凰网城市频道总监赵耀分别以各自媒体优势介绍了活动' + \
'的宣传方案。会上,中华社会救助基金会与“第二届中国爱心城市大会”承办方晋江市签约,许嘉璐理' + \
'事长接受晋江市参与“百万孤老关爱行动”向国家重点扶贫地区捐赠的价值400万元的款物。晋江市人大' + \
'常委会主任陈健倩介绍了大会的筹备情况。'
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模型结果:
晋江市/ 老龄/ 频道/ 公益活动/ 大会/ 人大常委会/ 许嘉璐/ 巡视员/ 重庆市/ 陈健倩/
https://github.com/canshang/python-nlk/blob/master/关键词提取.zip
《Python与自然语言处理》