查看: 4794|回复: 0
打印 上一主题 下一主题

[其他] NLP----关键词提取算法(TextRank,TF/IDF)

[复制链接]

3795

主题

2

听众

5万

积分

版主

Rank: 7Rank: 7Rank: 7

纳金币
53202
精华
32

活跃会员 优秀版主 推广达人 突出贡献 荣誉管理 论坛元老

跳转到指定楼层
楼主
发表于 2018-11-21 14:13:13 |只看该作者 |倒序浏览
参考书目:python自然语言处理实战——核心技术与算法

TF/IDF
基本思想:TF是计算一个词在一篇文档中出现的频率,IDF是一个词在多少篇文档中出现过,显然TF越高证明这个词在这篇文章中的代表性就越强,而INF越低则证明这个词在具有越强的区分能力。因此中和这两个数,就能较好地算出文档的关键词。

关键公式

gif.gif

|D_i|是文档中出现词i的文档数量,|D|是文档数

附上书上抄来的代码
  1. import jieba
  2. import jieba.posseg as psg
  3. import math
  4. import functools

  5. # 停用词表加载方法


  6. def get_stopword_list():
  7.     # 停用词表存储路径,每一行为一个词,按行读取进行加载
  8.     # 进行编码转换确保匹配准确率
  9.     stop_word_path = './data/stopword.txt'
  10.     stopword_list = [sw.replace('\n', '')
  11.                      for sw in open(stop_word_path,encoding = 'utf-8').readlines()]
  12.     return stopword_list

  13. # 分词方法,调用结巴接口


  14. def seg_to_list(sentence, pos=False):
  15.     if not pos:
  16.         # 不进行词性标注的分词方法
  17.         seg_list = jieba.cut(sentence)
  18.     else:
  19.         # 进行词性标注的分词方法
  20.         seg_list = psg.cut(sentence)
  21.     return seg_list

  22. # 去干扰词


  23. def word_filter(seg_list, pos=False):
  24.     stopword_list = get_stopword_list()
  25.     filter_list = []
  26.     # 根据POS参数选择是否词性过滤
  27.     # 不进行词性过滤,则将词性都标记为n,表示全部保留
  28.     for seg in seg_list:
  29.         if not pos:
  30.             word = seg
  31.             flag = 'n'
  32.         else:
  33.             word = seg.word
  34.             flag = seg.flag
  35.         if not flag.startswith('n'):
  36.             continue
  37.         # 过滤高停用词表中的词,以及长度<2的词
  38.         if not word in stopword_list and len(word) > 1:
  39.             filter_list.append(word)

  40.     return filter_list

  41. # 数据加载,pos为是否词性标注的参数,corpus_path为数据集路径


  42. def load_data(pos=False, corpus_path='./data/corpus.txt'):
  43.     # 调用上面方法对数据集进行处理,处理后的每条数据仅保留非干扰词
  44.     doc_list = []
  45.     for line in open(corpus_path, 'r',encoding = 'utf-8'):
  46.         content = line.strip()
  47.         seg_list = seg_to_list(content, pos)
  48.         filter_list = word_filter(seg_list, pos)
  49.         doc_list.append(filter_list)
  50.     return doc_list


  51. def train_idf(doc_list):
  52.     idf_dic = {}
  53.     #总文档数
  54.     tt_count = len(doc_list)
  55.    
  56.     #每个词出现的文档数
  57.     for doc in doc_list:
  58.         for word in set(doc):
  59.             idf_dic[word] = idf_dic.get(word,0.0)+1.0

  60.     #按公示转换为idf值,分母加一进行平滑处理
  61.     for k,v in idf_dic.items():
  62.         idf_dic[k]=math.log(tt_count/(1.0+v))
  63.    
  64.     #对于没有在字典中的词,默认其仅在一个文档中出现,得到默认idf值
  65.     default_idf = math.log(tt_count/1.0)
  66.     return idf_dic,default_idf

  67. def cmp(e1,e2):
  68.     import numpy as np
  69.     res = np.sign(e1[1]-e2[1])
  70.     if res != 0:
  71.         return res
  72.     else:
  73.         a = e1[0]+e2[0]
  74.         b = e2[0]+e1[0]
  75.         if a>b:
  76.             return 1
  77.         elif a == b:
  78.             return 0
  79.         else:
  80.             return -1

  81. class TfIdf(object):
  82.     #统计tf值
  83.     def get_tf_dic(self):
  84.         tf_dic = {}
  85.         for word in self.word_list:
  86.             tf_dic[word] = tf_dic.get(word,0.0)+1.0
  87.         
  88.         tt_count = len(self.word_list)
  89.         for k,v in tf_dic.items():
  90.             tf_dic[k] = float(v)/tt_count

  91.         return tf_dic
  92.    
  93.     #四个参数分别是:训练好的idf字典,默认idf值,处理后的待提取文本,关键词数量
  94.     def __init__(self,idf_dic,default_idf,word_list,keyword_num):
  95.         self.word_list = word_list
  96.         self.idf_dic,self.default_idf = idf_dic,default_idf
  97.         self.tf_dic  = self.get_tf_dic()
  98.         self.keyword_num = keyword_num

  99.     #按公式计算tf_idf
  100.     def get_tfidf(self):
  101.         tfidf_dic = {}
  102.         for word in self.word_list:
  103.             idf = self.idf_dic.get(word,self.default_idf)
  104.             tf = self.tf_dic.get(word,0)

  105.             tfidf  = tf*idf
  106.             tfidf_dic[word] = tfidf

  107.             #根据tf_idf排序,取排名前keyword_num的词作为关键词
  108.         for k ,v in sorted(tfidf_dic.items(),key=functools.cmp_to_key(cmp),reverse=True)[:self.keyword_num]:
  109.             print(k+"/",end='')
  110.         print()

  111. def tfidf_extract(word_list, pos=False, keyword_num=10):
  112.     doc_list = load_data(pos)
  113.     idf_dic, default_idf = train_idf(doc_list)
  114.     tfidf_model = TfIdf(idf_dic, default_idf, word_list, keyword_num)
  115.     tfidf_model.get_tfidf()

  116. if __name__ == '__main__':
  117.     text = '6月19日,《2012年度“中国爱心城市”公益活动新闻发布会》在京举行。' + \
  118.            '中华社会救助基金会理事长许嘉璐到会讲话。基金会高级顾问朱发忠,全国老龄' + \
  119.            '办副主任朱勇,民政部社会救助司助理巡视员周萍,中华社会救助基金会副理事长耿志远,' + \
  120.            '重庆市民政局巡视员谭明政。晋江市人大常委会主任陈健倩,以及10余个省、市、自治区民政局' + \
  121.            '领导及四十多家媒体参加了发布会。中华社会救助基金会秘书长时正新介绍本年度“中国爱心城' + \
  122.            '市”公益活动将以“爱心城市宣传、孤老关爱救助项目及第二届中国爱心城市大会”为主要内容,重庆市' + \
  123.            '、呼和浩特市、长沙市、太原市、蚌埠市、南昌市、汕头市、沧州市、晋江市及遵化市将会积极参加' + \
  124.            '这一公益活动。中国雅虎副总编张银生和凤凰网城市频道总监赵耀分别以各自媒体优势介绍了活动' + \
  125.            '的宣传方案。会上,中华社会救助基金会与“第二届中国爱心城市大会”承办方晋江市签约,许嘉璐理' + \
  126.            '事长接受晋江市参与“百万孤老关爱行动”向国家重点扶贫地区捐赠的价值400万元的款物。晋江市人大' + \
  127.            '常委会主任陈健倩介绍了大会的筹备情况。'

  128.     pos = True
  129.     seg_list = seg_to_list(text, pos)
  130.     filter_list = word_filter(seg_list, pos)

  131.     print('TF-IDF模型结果:')
  132.     tfidf_extract(filter_list)

复制代码
TextRank

基本思路:每个词将自己的分数平均投给附近的词,迭代至收敛或指定次数即可,初始分可以打1

附上代码

  1. def get_stopword_list():
  2.     path = './data/stop_words.utf8'
  3.     stopword_list = [sw.replace('\n','') for sw in open(path,'r',encoding='utf8').readlines()]
  4.     return stopword_list

  5. def seg2list(text):
  6.     import jieba
  7.     return jieba.cut(text)

  8. def word_filter(seg_list):
  9.     stopword_list = get_stopword_list()
  10.     filter_list = []
  11.     for w in seg_list:
  12.         if not w in stopword_list and len(w)>1:
  13.             filter_list.append(w)
  14.     return filter_list


  15. str = '6月19日,《2012年度“中国爱心城市”公益活动新闻发布会》在京举行。' + \
  16.            '中华社会救助基金会理事长许嘉璐到会讲话。基金会高级顾问朱发忠,全国老龄' + \
  17.            '办副主任朱勇,民政部社会救助司助理巡视员周萍,中华社会救助基金会副理事长耿志远,' + \
  18.            '重庆市民政局巡视员谭明政。晋江市人大常委会主任陈健倩,以及10余个省、市、自治区民政局' + \
  19.            '领导及四十多家媒体参加了发布会。中华社会救助基金会秘书长时正新介绍本年度“中国爱心城' + \
  20.            '市”公益活动将以“爱心城市宣传、孤老关爱救助项目及第二届中国爱心城市大会”为主要内容,重庆市' + \
  21.            '、呼和浩特市、长沙市、太原市、蚌埠市、南昌市、汕头市、沧州市、晋江市及遵化市将会积极参加' + \
  22.            '这一公益活动。中国雅虎副总编张银生和凤凰网城市频道总监赵耀分别以各自媒体优势介绍了活动' + \
  23.            '的宣传方案。会上,中华社会救助基金会与“第二届中国爱心城市大会”承办方晋江市签约,许嘉璐理' + \
  24.            '事长接受晋江市参与“百万孤老关爱行动”向国家重点扶贫地区捐赠的价值400万元的款物。晋江市人大' + \
  25.            '常委会主任陈健倩介绍了大会的筹备情况。'
  26. win={}
  27. seg_list = seg2list(str)
  28. filter_list = word_filter(seg_list)
  29. #构建投分表,根据窗口
  30. for i in range(len(filter_list)):
  31.     if filter_list[i] not in win.keys():
  32.         win[filter_list[i]]=set()
  33.     if i-5 < 0:
  34.         lindex = 0
  35.     else:
  36.         lindex = i-5
  37.     for j in filter_list[lindex:i+5]:
  38.         win[filter_list[i]].add(j)

  39. # 投票
  40. time = 0
  41. score = {w:1.0 for w in filter_list}
  42. while(time<50):
  43.     for k,v in win.items():
  44.         s = score[k]/len(v)
  45.         score[k] = 0
  46.         for i in v:
  47.             score[i]+=s
  48.     time+=1

  49. l = sorted(score.items(), key=lambda score:score[1],reverse=True)
  50. print(l)


复制代码
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2024-11-23 11:33 , Processed in 0.097948 second(s), 32 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部