返回小栈
关于自然语言处理系列-关键词提取
bq_wang2020-03-03 09:07:15


自然语言处理包括中文分词、词性标注、关键词抽取、依存句法分析、文本分类接口情感分析、词义相似度计算、实体标识、文本摘要等等,慢慢来吧,看看一步步能到什么程度。本文实现的是关键词提取。

在jiaba中,关键词提取包括了TF-IDF关键词提取、PageRank关键词提取方式,同时还可以自定义语料库、停用词库,在此基础上再进行TF-IDF关键词提取,本文略作尝试。

代码示例

  1. #!/usr/bin/python

  2. # -*- coding: utf-8 -*-


  3. import os

  4. import math

  5. import re

  6. import datetime

  7. import sys

  8. import jieba

  9. import jieba.analyse

  10. import codecs

  11. from collections import Counter


  12. #对文件进行分词处理

  13. def segment(sentence, cut_all=False):

  14. sentence = sentence.replace('\n', '').replace('\u3000', '').replace('\u00A0', '')

  15. sentence = ' '.join(jieba.cut(sentence, cut_all=cut_all))

  16. return re.sub('[a-zA-Z0-9.。::,,))((!!??”“\"]', '', sentence).split()


  17. #将文件从gb2312格式转码为utf-8格式

  18. def EncodingtoUTF(filename):

  19. try:

  20. with codecs.open(filename, 'rb', 'mbcs') as f:

  21. text=f.read().encode("utf-8")

  22. with open(filename, 'wb') as e:

  23. e.write(text)

  24. except:

  25. return


  26. # 对指定目录的文件进行分词

  27. class DocumentsSegment(object):

  28. def __init__(self, dirname):

  29. self.dirname = dirname


  30. if not os.path.isdir(dirname):

  31. print(dirname, '- not a directory!')

  32. sys.exit()


  33. def __iter__(self):

  34. for dirfile in os.walk(self.dirname):

  35. for fname in dirfile[2]:

  36. # 对文件进行utf-8转码

  37. EncodingtoUTF(os.path.join(dirfile[], fname))

  38. text = open(os.path.join(dirfile[], fname),

  39. 'r', encoding='utf-8', errors='ignore').read()

  40. # 对文件进行迭代并进行分词

  41. yield segment(text) # time consuming


  42. class IDFGen():

  43. def __init__(self,inputdir,outputfile):

  44. self.inputdir=inputdir

  45. self.outputfile=outputfile

  46. self.documents=DocumentsSegment(inputdir)


  47. def gen_idf(self):

  48. ignored = {'', ' ', '', '。', ':', ',', ')', '(', '!', '?', '”', '“'} #忽略词

  49. id_freq = {} #词频字典

  50. i =

  51. for doc in self.documents:

  52. doc = set(x for x in doc if x not in ignored) #剔除忽略词

  53. for x in doc: #遍历文档

  54. id_freq[x] = id_freq.get(x, ) + 1 #更新词频

  55. if i % 1000 == : #每1000篇文章提示进度

  56. print('Documents processed: ', i, ', time: ',

  57. datetime.datetime.now())

  58. i += 1


  59. # 词频排序

  60. sortdata = dict(sorted(id_freq.items(), key=lambda x: x[1]))

  61. # 将词频转换后写入词频语料库

  62. with open(self.outputfile, 'w', encoding='utf-8') as f: #将词频取对数后,写入idf文件

  63. for key, value in sortdata.items():

  64. f.write(key + ' ' + str(math.log(i / value, 2)) + '\n')


  65. # 词频文件加载

  66. class IDFLoader(object):

  67. def __init__(self, idf_path):

  68. self.idf_path = idf_path

  69. self.idf_freq = {} # idf

  70. self.mean_idf = 0.0 # 均值

  71. self.load_idf()


  72. # 加载词频文件

  73. def load_idf(self): # 从文件中载入idf

  74. cnt =

  75. with open(self.idf_path, 'r', encoding='utf-8') as f:

  76. for line in f:

  77. try:

  78. word, freq = line.strip().split(' ')

  79. cnt += 1

  80. except Exception as e:

  81. pass

  82. self.idf_freq[word] = float(freq)

  83. print(self.idf_freq)

  84. print('Vocabularies loaded: %d' % cnt)

  85. # 获取idf均值

  86. self.mean_idf = sum(self.idf_freq.values()) / cnt


  87. if __name__ == "__main__":

  88. inputdir = 'C:\Python\Pycharm\langprocess\\train'

  89. idffile = 'C:\Python\Pycharm\langprocess\\udfidf.txt'

  90. stopwordfile= 'C:\Python\Pycharm\langprocess\\stopwords.txt'

  91. filename = 'C:\Python\Pycharm\langprocess\\train\C4-Literature\C4-Literature02.txt'


  92. str = '''《三国演义》描写了从东汉末年到西晋初年之间近百年的历史风云,以描写战争为主,诉说了东汉末年的群雄割据混战和魏、蜀、吴三国之间的政治和军事斗争,最终司马炎一统三国,建立晋朝的故事。反映了三国时代各类社会斗争与矛盾的转化,并概括了这一时代的历史巨变,塑造了一群叱咤风云的三国英雄人物。全书可大致分为黄巾起义、董卓之乱、群雄逐鹿、三国鼎立、三国归晋五大部分。在广阔的历史舞台上,上演了一幕幕气势磅礴的战争场面。作者罗贯中将兵法三十六计融于字里行间,既有情节,也有兵法韬略。《三国演义》是中国文学史上第一部章回小说,是历史演义小说的开山之作,也是第一部文人长篇小说,中国古典四大名著之一。'''

  93. seg_list = jieba.cut(str) #分词

  94. # 《|三国演义|》|描写|了|从|东汉|末年|到|西晋|初年|之间|近|百年|的|历史风云|,|以|描写|战争|为主|,|诉说|了|东汉|末年|的|群雄割据|混战|和|魏|、|蜀|、|吴三国|之间|的|政治|和|军事|斗争

  95. data = Counter(seg_list) #用Counter函数构造字典

  96. # Counter({',': 12, '的': 10, '了': 6, '、': 6, '。': 6, '三国': 4, '是': 3, '《': 2, '三国演义': 2, '》': 2

  97. # Counter输出的时候有顺序,但其实内部是无顺序的,建议排序一下

  98. top10= data.most_common(10) #通过Counter函数的most_common获取前10

  99. #[(',', 12), ('的', 10), ('了', 6), ('、', 6), ('。', 6), ('三国', 4), ('是', 3), ('《', 2), ('三国演义', 2), ('》', 2)]

  100. sortdata=sorted(data.items(), key=lambda x: x[1], reverse=True)

  101. # [(',', 12), ('的', 10), ('了', 6), ('、', 6), ('。', 6), ('三国', 4), ('是', 3), ('《', 2), ('三国演义', 2), ('》', 2)

  102. # AttributeError: 'Counter' object has no attribute 'sort'

  103. # 所以只能转换为list再通过list进行排序

  104. items = list(data.items())

  105. items.sort(key=lambda x: x[1], reverse=True)

  106. # [(',', 12), ('的', 10), ('了', 6), ('、', 6), ('。', 6), ('三国', 4), ('是', 3), ('《', 2), ('三国演义', 2), ('》', 2), ('描写', 2), ('东汉', 2),


  107. # ----------------------------------------关键词提取-------------------------------------------

  108. # 基于TF-IDF算法的关键词抽取

  109. # 第一个参数:待提取关键词的文本

  110. # 第二个参数:返回关键词的数量,重要性从高到低排序

  111. # 第三个参数:是否同时返回每个关键词的权重

  112. # 第四个参数:词性过滤,为空表示不过滤,若提供则仅返回包括指定词性的词,默认值为空,即不筛选

  113. keywords = jieba.analyse.extract_tags(str, topK=5, withWeight=True, allowPOS=('ns', 'n', 'vn', 'v'))

  114. # [('三国', 0.5706667621368), ('兵法', 0.3433023063252), ('描写', 0.2863118806472), ('历史风云', 0.256041307266), ('群雄逐鹿', 0.242178363654)]


  115. # 基于 TF-IDF 算法的关键词抽取,使用停用词词典,使用逆向文件频率文本语料库

  116. tfidf = jieba.analyse.TFIDF()

  117. tfidf.set_stop_words('stopwords.txt') # 使用停用词词典

  118. tfidf.set_idf_path('idf.txt') # 使用默认的逆向文件频率(IDF)文本语料库

  119. keywords=tfidf.extract_tags(str,topK=5, withWeight=True, allowPOS=('ns', 'n', 'vn', 'v')) # 再进行

  120. # [('三国', 0.5706667621368), ('兵法', 0.3433023063252), ('描写', 0.2863118806472), ('历史风云', 0.256041307266), ('群雄逐鹿', 0.242178363654)]


  121. # 基于 TextRank 算法的关键词抽取

  122. # 第一个参数:待提取关键词的文本

  123. # 第二个参数:返回关键词的数量,重要性从高到低排序

  124. # 第三个参数:是否同时返回每个关键词的权重

  125. # 第四个参数:词性过滤,为空表示不过滤,若提供则仅返回符合词性要求的关键词,默认过滤词性是('ns', 'n', 'vn', 'v')

  126. keywords = jieba.analyse.textrank(str, topK=5, withWeight=True, allowPOS=('ns', 'n', 'vn', 'v'))

  127. # [('三国', 1.0), ('斗争', 0.7784764171715404), ('兵法', 0.6974027914816684), ('历史', 0.6748143587652791), ('时代', 0.6480813515953463)]


  128. # 利用jieba进行关键字提取时,有两种接口。

  129. # 一个基于TF-IDF算法,一个基于TextRank算法。

  130. # TF-IDF算法,完全基于词频统计来计算词的权重,然后排序,在返回TopK个词作为关键字。

  131. # TextRank相对于TF-IDF,基本思路一致,也是基于统计的思想,只不过其计算词的权重时,还考虑了词的上下文(通过窗口滑动来实现),

  132. # 而且计算词的权重时,也考虑了相关联系词的影响。可以说,TextRank实际上是依据位置与词频来计算词的权重的。

  133. # TF-IDF计算简单,运行性能更好。


  134. # ----------------------------------------自定义预料库后关键词提取-------------------------------------------

  135. #content = open(filename, 'rb').read()

  136. content = open(filename, 'r', encoding='utf-8', errors='ignore').read()


  137. jieba.analyse.set_stop_words(stopwordfile)

  138. keywords = jieba.analyse.extract_tags(content, topK=10) #, withWeight=True, allowPOS=('ns', 'n', 'vn', 'v')) # 再进行

  139. print('未使用自定义预料,输出关键词:',keywords)

  140. # 未使用自定义预料,输出关键词: ['岭南文化', '文化', '爱国主义', '学者', '近代', '研讨会', '侨乡', '传统', '研究', '炎黄']


  141. # 基于原始语料,生成自定义的词频库

  142. myidffile=IDFGen(inputdir,idffile)

  143. myidffile.gen_idf()

  144. jieba.analyse.set_stop_words(stopwordfile)

  145. jieba.analyse.set_idf_path(idffile);

  146. keywords = jieba.analyse.extract_tags(content, topK=10)

  147. print('使用自定义预料后,输出关键词:', keywords)

  148. # 使用自定义预料后,输出关键词: ['岭南文化', '爱国主义', '广东', '侨乡', '岭南', '中原', '与会', '商品经济', '学者', '近代']



4
0