zoukankan      html  css  js  c++  java
  • SnowNLP——获取关键词(keywords(1))

    一、SnowNLP的获取文本关键词

    前面介绍了SnowNLP的获取关键词的方法,这里再重现一下

    1 from snownlp import SnowNLP
    2 # 提取文本关键词,总结3个关键词
    3 text = '随着顶层设计完成,全国政协按下信息化建设快进键:建设开通全国政协委员移动履职平台,开设主题议政群、全国政协书院等栏目,建设委员履职数据库,拓展网上委员履职综合服务功能;建成网络议政远程协商视频会议系统,开展视频调研、远程讨论活动,增强网络议政远程协商实效;建立修订多项信息化规章制度,优化电子政务网络。'
    4 s = SnowNLP(text)
    5 print(s.keywords(3))
    6 
    7 --->['全国', '政协', '远程']

    二、源码分析

    我们进入SnowNLP的源码看一下

    1、SnowNLP(text)

     这里我们记住self.doc是我们传入的文本

    2、keywords(self, limit=5, merge=False)

     这是SnowNLP源码中keywords方法的源码,我们一行一行的看下具体流程:

    70 def keywords(self, limit=5, merge=False):

    limit参数:这个参数对应的是调用 keywords(3)方法时传入的形参,默认为5,即默认会返回五个关键词。

    71 doc = []
    72 sents = self.sentences

        这是做了一个赋值,我看看下源码:

        self.sentences是对输入文本的整理,对文本分句、分词

        

         

         上图参数中的doc是我们传入的文本,这个方法主要功能是将我们传入的文本进行整理

        33行、34行:定义了两个正则表达式,分别是筛选换行符、部分中文标点

        36行:是根据换行符对文本进行切割后进行遍历。

        40行:再上一次循环中,又将文本根据中文标点符号进行分割。

        44行:将得到的句子放到一个list中,即sentences。

      

    我们再回到keywords方法中:

    72 sents = self.sentences

    由此得到一个sents,里面存储的是我们输入文本分割成的句子的list

    73  for sent in sents: #对sents进行遍历,得到每个句子
    74      words = seg.seg(sent) #对句子进行分词
    75      words = normal.filter_stop(words) #去除停用词
    76      doc.append(words) #将得到的每个句子的分词加到doc中
    77 rank = textrank.KeywordTextRank(doc) #得到一个KeywordTextRank对象
    78 rank.solve() #计算词语的关键度,并进行关键排序

    这里我们看一下KeywordTextRank()类以及rank.solve()方法:

    rank.solve()是计算关键度的方法,是获取关键词的核心!!

     1 class KeywordTextRank(object):
     2 
     3     def __init__(self, docs):
     4         self.docs = docs
     5         self.words = {}
     6         self.vertex = {}
     7         self.d = 0.85
     8         self.max_iter = 200
     9         self.min_diff = 0.001
    10         self.top = []
    11 
    12     def solve(self):
    13         for doc in self.docs: # self.docs是我们传入的文本被分词后的词语list:[['a','b','c'],['d','e'],['f','g']]
    14             que = []
    15             for word in doc: # 遍历每个句子的词语,得到该句的词
    16                 if word not in self.words: # 如果该词不存在self.words中,则添加进去
    17                     self.words[word] = set() # 一个字典集合:{'word':set()}
    18                     self.vertex[word] = 1.0 # 一个字典集合:{'word':1.0}
    19                 que.append(word) #将词加到que中:['word']
    20                 if len(que) > 5:
    21                     que.pop(0) # 如果que的长度大于5则移除第一个词
    22                 for w1 in que: # 遍历que
    23                     for w2 in que: # 遍历que
    24                         if w1 == w2:
    25                             continue # 如果w1与w2相等则结束这一轮循环,继续下一轮循环
    26                         self.words[w1].add(w2) # 将词加到自己字典中
    27                         self.words[w2].add(w1) #
    28         for _ in range(self.max_iter): # 循环200次
    29             m = {}
    30             max_diff = 0
    31             tmp = filter(lambda x: len(self.words[x[0]]) > 0,
    32                          self.vertex.items()) # 过滤每个词,判断值位的set中是否有值,有的话保留,返回:[('a', 1), ('b', 1), ('c', 1)]
    33             tmp = sorted(tmp, key=lambda x: x[1] / len(self.words[x[0]])) # 根据值位的set的长度排序,返回:[('a', 1), ('b', 1), ('c', 1)]
    34             for k, v in tmp: # k为词,v为相关度
    35                 for j in self.words[k]: # 遍历每个词对应的set集合(相关词)
    36                     if k == j:
    37                         continue
    38                     if j not in m:
    39                         m[j] = 1 - self.d
    40                     m[j] += (self.d / len(self.words[k]) * self.vertex[k]) # m值 = 0.85 / set的长度 * 1
    41             for k in self.vertex: # {词1:相关度1,词2:相关度2}
    42                 if k in m and k in self.vertex:
    43                     if abs(m[k] - self.vertex[k]) > max_diff: # 计算本次相关度与上一次相关度之差的绝对值是否符合设定的阈值
    44                         max_diff = abs(m[k] - self.vertex[k]) # 改变阈值
    45             self.vertex = m # 获取到本次相关度集合
    46             if max_diff <= self.min_diff: # 设定退出条件
    47                 break
    48         self.top = list(self.vertex.items()) # 将字典转成集合
    49         self.top = sorted(self.top, key=lambda x: x[1], reverse=True) # 根据相似度进行排序 [('a', 1), ('b', 2), ('c', 3)]
    50 
    51     def top_index(self, limit):
    52         return list(map(lambda x: x[0], self.top))[:limit] # 获取list的值的key,并截取list,[0-limit)
    53 
    54     def top(self, limit):
    55         return list(map(lambda x: self.docs[x[0]], self.top)) # 获取字典中top字段对应值的value

    我们再回到keywords方法中:

    79 ret = []
    80 for w in rank.top_index(limit): # 获取按词语关键度排序后并截取长度的list
    81   ret.append(w)
    82  if merge:
    83     wm = words_merge.SimpleMerge(self.doc, ret)
    84     return wm.merge()
    85  return ret

    merge默认为False,如果手动设定为True的话将走SimpleMerge类对结果重新处理

    看下SimpleMerge源码:

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    
    
    class SimpleMerge(object):
    
        def __init__(self, doc, words):
            self.doc = doc
            self.words = words
    
        def merge(self):
            trans = {}
            for w in self.words:
                trans[w] = ''
            for w1 in self.words:
                cw = 0
                lw = len(w1)
                for i in range(len(self.doc)-lw+1):
                    if w1 == self.doc[i: i+lw]:
                        cw += 1
                for w2 in self.words:
                    cnt = 0
                    l2 = len(w1)+len(w2)
                    for i in range(len(self.doc)-l2+1):
                        if w1+w2 == self.doc[i: i+l2]:
                            cnt += 1
                    if cw < cnt*2:
                        trans[w1] = w2
                        break
            ret = []
            for w in self.words:
                if w not in trans:
                    continue
                s = ''
                now = trans[w]
                while now:
                    s += now
                    if now not in trans:
                        break
                    tmp = trans[now]
                    del trans[now]
                    now = tmp
                trans[w] = s
            for w in self.words:
                if w in trans:
                    ret.append(w+trans[w])
            return ret

     三、总结

     SnowNLP获取关键词的流程可以总结如下:

    1、输入文段

    2、按换行符和中文符号(,。?!;)划分成句子:list[句子]

    3、对每个句子分词:list[[词]]

    4、统计该词的关联词,去重并排序(关联词:该词所在句的其他词都为关联词)

    5、计算每个词的关键度(与该词的关联词的数量相关):
      m[i] += 0.85 / len(list[关联词]) * m[i](old)。默认计算200次,期间前后两次m[i]相减绝对值小于等于0.001退出计算

    6、排序,截取

    如果对于单句文本来说,关键词的选取与词频无关;如果对多个句子来说,关键词的选取与词频、关联词数都有关系,即一个词出现在多个句子中,那他就越可能成为关键词。

     

       

    分享所感,如有侵权,请联系删除,可扫码关注微信公众号获取更多福利噢。
    (您的“打赏”将是我最大的写作动力!转载请注明出处.)

    关注微信公众号

  • 相关阅读:
    0713学期末了
    Oracle Redo日志的状态
    crontab调用shell访问sqlplus失败原因
    Solaris下批量杀进程
    oracle用户管理的完全恢复4:在ARCHIVELOG 模式(恢复打开的数据库)
    oracle用户管理的完全恢复3:在ARCHIVELOG 模式(恢复关闭的数据库)
    shell删除所有空行(忽略编码格式)
    oracle用户管理的完全恢复1:在NOARCHIVELOG 模式下执行恢复
    查看oracle用户权限
    OLTP与OLAP介绍
  • 原文地址:https://www.cnblogs.com/pengpengdeyuan/p/14481915.html
Copyright © 2011-2022 走看看