资源技术动态自然语言关键词提取

自然语言关键词提取

2019-10-31 | |  117 |   0

原标题:自然语言处理(一) 关键词提取   

来源:CSDN          接:https://blog.csdn.net/seeing_Liu/article/details/89040442


1.TF-IDF

TF-IDF(term frequency-inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术。TF-IDF是一种统计方法,用来评估一个字词对于一个文件集或语料库中的一份文件的重要程度。


首先解释一下TF-IDF的意思:

TF(term frequency):词语在一篇文章中出现的频率

IDF(inverse document frequency):反文档频率,与词语在其他文档中出现的频率负相关

TF-IDF的主要思想是:如果某个词或短语在一篇文章中出现的频率高,即TF值高;并且在其他文章中很少出现,即IDF值高,那么认为这个词或短语具有很好的类别区分能力,适合作为该文章的关键词。

TF-IDF的具体计算公式为:

01.png

文档中词的tfidf值越高,便认为该词越可以代表该文档的主题。TF-IDF算法的python实现如下,同时jieba库中也实现了TF-IDF,有兴趣的话也可以去了解一下。

————————————————————————————————

# TF-IDf算法python实现

import re

import math

# 获取一个文档中每个词的TF值,doc参数保存文档中的句子列表,返回单词与其tf值的字典

# 首先对文档中的单词进行切分,然后统计每个词的词频

def GetWordTF(doc):

    words_count = 0   # 单词总数

    words_map = {} # 单词与单词数的映射

    tf_map = {}  # tf值映射词典,格式: tf_map[word] = tf_word

    for sentence in doc:  # 遍历文档中的每个句子

        # 单词的切分方式可以根据所给的数据格式进行修改

        # 我将提取英文句子中的每个单词,使用正则表达式提取并去除空字符串

        words_arr = [word for word in re.split(r'W+',sentence) if word]

        words_count += len(words_arr)   # 统计有效词的总长度

        for word in words_arr:   # 遍历每一个词并进行统计单词数

            words_map[word] = words_map.get(word,0) + 1

    for key,val in words_map.items():   # 计算每个单词的tf值

        tf_map[key] = val / words_count

    return tf_map


# 获取文档每个单词在文档集docSet中的IDF值映射

def GetWordIDF(tfMap,docSet):

    docs_num = len(docSet)   # 文档集中文档的总数

    word_doc_num = {}   # 包含word的文档数,格式为word_doc_num[word] = num of doc that contains word

    idf_map = {}  # idf值映射字典,格式idf_map[word] = idf_word

    for key,val in tfMap.items():    # 遍历文档中出现的单词

        for doc in docSet:        # 遍历每个文档,检查该文档中是否出现了单词key

            for sentence in doc:    # 遍历文档中的每个句子

                words_arr = [word for word in re.split(r'W+', sentence) if word]   # 提取句子中的每个单词

                if key in words_arr:   # 如果该文档中有该词,则统计

                    word_doc_num[key] = word_doc_num.get(key,0) + 1

                    break

    for key,val in word_doc_num.items():   # 计算每个单词的idf值

        idf_map[key] = math.log(docs_num / val)

    return idf_map


# 使用TFIDF算法获取文档的前topNum个关键词,其中每个文档是以列表表示的,列表项为文档的一个句子

def GetKeywordsByTFIDF(entityDescriptionList,docSet,topNum):

    tf_map = GetWordTF(entityDescriptionList)    # 获取每个单词的tf值

    idf_map = GetWordIDF(tf_map,docSet)    # 获取每个单词的idf值

    tfidf_map = {}

    for key,val in tf_map.items():   # 计算每个词的tfidf值

        tfidf_map[key] = tf_map[key] * idf_map[key]

    tfidf_sorted_list = sorted(tfidf_map.items(),key = lambda x:x[1],reverse=True)  # 将字典按值从大到小排序

    if topNum > len(tfidf_sorted_list):   # 保证topNum不大于文档中词的总数

        topNum = len(tfidf_sorted_list)

    keywords = []   # 保存文档的前topNum个关键字

    for i in range(topNum):

        keywords.append(tfidf_sorted_list[i][0])   # 关键字保存在元组的第0个元素中

    return keywords

————————————————————————————————


2.TextRank

TF-IDF算法对于有多段文本的关键词提取非常有效,但是对于单篇或文档集较少的文本则表现得不很好。对于单篇文档,可以使用TextRank算法实现关键词提取。


TextRank是一种基于图排序的算法,思想源于谷歌的PageRank算法,通过把文本分割为若干组成单元(单词、句子)并建立图模型,利用投票机制对文本中的重要成分进行排序,仅利用单篇文档本身的信息即可实现关键词提取。


TextRank利用投票的原理,让每一个单词给它的邻居投赞成票,票的权重取决于自己的票数。假设每一个词是一个顶点(Vertex),那么所有的词就构成了一个网络,这个网络里面每个顶点会有指向其他顶点的边,也会有其他顶点指向自己的边。通过计算每个顶点所连接的指向自己的顶点的权重和,最终得到该顶点的权重值。


TextRank存在的主要问题是初始值的确定,为了后续计算的简便性,这里会给初值赋为一个非0值。同时,引入了一个阻尼系数的概念,该参数表示从某一个指定的顶点,到任意一个其他顶点的概率。TextRank的具体公式如下:

————————————————————————————————

# 使用TextRank算法实现关键词提取,返回关键词列表,参数含义如下:

# sentence 保存待提取关键字的句子

# windowLength 保存滑动窗口的大小

# topNum 表示需要返回排名前topNum的关键词

# d 表示textrank算法的阻尼系数,默认为0.85

# maxIter 表示算法最大迭代次数

# minDiff 迭代后变化值小于minDiff时也停止迭代

def GetKeywordsByTextRank(sentence,windowLength,topNum=3,d=0.85,maxIter=10000,minDiff=0.0001):

    # 单词的切分方式可以根据所给的数据格式进行修改

    # 我将提取英文句子中的每个单词,使用正则表达式提取并去除空字符串

    words_arr = [word for word in re.split(r'W+', sentence) if word]

    words_num = len(words_arr)   # 句子的长度

    word_graph = {}   # 保存每个单词的连接状态,格式为word_graph[word] = [与该词存在边的单词的集合]

    textrank_map = {}   # 保存每个textrank值的字典,格式为textrank_map[word] = textrank value of the word

    textrank_map_t = {}  # 用于保存前一次迭代的tankrank结果

    for words_index in range(words_num):    # 遍历句子中的每个单词,开始根据给定的窗口值构图

        textrank_map[words_arr[words_index]] = 1 - d   # 为每个词初始化一个textrank值

        window_lower = max(0, words_index - windowLength)   # 滑动窗口的下边界

        window_upper = min(words_num, words_index + windowLength)   # 滑动窗口的上边界

        for window_index in range(window_lower,window_upper):  # 遍历窗口中的单词,构建单词的连接关系

            if window_index == words_index:   # 自己与自己认为没有边

                continue

            if not words_arr[window_index] in word_graph.get(words_arr[words_index],[]):  # 检查两词节点之间是否有边

                if word_graph.get(words_arr[words_index],0) == 0:   # 检查该词的边集是否为空

                    word_graph[words_arr[words_index]] = [words_arr[window_index]]   # 为空则生成包含该点的边集

                else:

                    word_graph[words_arr[words_index]].append(words_arr[window_index])  # 将该边添加到边集中

    for iter_i in range(maxIter):   # 利用textrank计算公式迭代计算

        max_diff = 0  # 表示迭代前后两次的变化

        for word,neibor_list in word_graph.items():  # 遍历每个单词

            for con_word in neibor_list:  # 遍历与每个单词存在相邻关系的单词

                con_word_out_len = len(word_graph[con_word])  # 计算当前节点连接的节点个数

                if word == con_word or con_word_out_len == 0:

                    continue  # 如果是该节点本身或无连出节点则不更新

                # 使用公式对textrank值进行更新

                textrank_map[word] = 1 - d + d * textrank_map_t.get(con_word, 0) /con_word_out_len

            max_diff = max(max_diff,abs(textrank_map[word]-textrank_map_t.get(word,0)))

        for word,val in textrank_map.items():

            textrank_map_t[word] = val

        if(max_diff < minDiff):   # 各个单词节点的textrank值如果均无明显变化,则可结束迭代

            break

    textrank_sorted_list = sorted(textrank_map.items(),key=lambda x:x[1],reverse=True)  # 按照textrank值从大到小排序

    if topNum > len(textrank_sorted_list): # 保证topNum不大于文档中词的总数

        topNum = len(textrank_sorted_list)

    if topNum < 1:  # 保证topNum大于0

        topNum = 1

    keywords = []   # 保存将要返回的关键词

    for i in range(topNum):

        keywords.append(textrank_sorted_list[i][0])

    return keywords

————————————————————————————————

可以看出TextRank算法对于一段文本中多次出现的词,会赋予更大的权重,因为它连出的节点更多,所以当各个节点初始权重一致时,则最终出现次数最多的词权重就会更大。这也会使该算法对类似于“的”、“你、我、他”等常用词,会出现比较大的误差。对于这种情况,可以在最开始构建边时进行处理,去掉一些停用词或者选择自己需要的词性的词,从而得出实际有用的词语。

————————————————————————————————

版权声明:本文为CSDN博主「seeing_Liu」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/seeing_Liu/article/details/89040442

THE END

免责声明:本文来自互联网新闻客户端自媒体,不代表本网的观点和立场。

合作及投稿邮箱:E-mail:editor@tusaishared.com

上一篇:Python自然语言处理实战(5):关键词提取算法

下一篇:遗忘算法系列(四):关键词提取

用户评价
全部评价

热门资源

  • 应用笔画宽度变换...

    应用背景:是盲人辅助系统,城市环境中的机器导航...

  • GAN之根据文本描述...

    一些比较好玩的任务也就应运而生,比如图像修复、...

  • 端到端语音识别时...

    从上世纪 50 年代诞生到 2012 年引入 DNN 后识别效...

  • 人体姿态估计的过...

    人体姿态估计是计算机视觉中一个很基础的问题。从...

  • 谷歌发布TyDi QA语...

    为了鼓励对多语言问答技术的研究,谷歌发布了 TyDi...