关于自然语言处理系列-关键词提取

2022-03-11 14:39:23 浏览数 (1)

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

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

代码示例

代码语言:javascript复制
#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import math
import re
import datetime
import sys
import jieba
import jieba.analyse
import codecs
from collections import Counter

#对文件进行分词处理
def segment(sentence, cut_all=False):
    sentence = sentence.replace('n', '').replace('u3000', '').replace('u00A0', '')
    sentence = ' '.join(jieba.cut(sentence, cut_all=cut_all))
    return re.sub('[a-zA-Z0-9.。::,,))((!!??”“"]', '', sentence).split()

#将文件从gb2312格式转码为utf-8格式
def EncodingtoUTF(filename):
    try:
        with codecs.open(filename, 'rb', 'mbcs') as f:
            text=f.read().encode("utf-8")
            with open(filename, 'wb') as e:
                e.write(text)
    except:
        return

# 对指定目录的文件进行分词
class DocumentsSegment(object):
    def __init__(self, dirname):
        self.dirname = dirname

        if not os.path.isdir(dirname):
            print(dirname, '- not a directory!')
            sys.exit()

    def __iter__(self):
        for dirfile in os.walk(self.dirname):
            for fname in dirfile[2]:
                # 对文件进行utf-8转码
                EncodingtoUTF(os.path.join(dirfile[0], fname))
                text = open(os.path.join(dirfile[0], fname),
                            'r', encoding='utf-8', errors='ignore').read()
                # 对文件进行迭代并进行分词
                yield segment(text)   # time consuming

class IDFGen():
    def __init__(self,inputdir,outputfile):
        self.inputdir=inputdir
        self.outputfile=outputfile
        self.documents=DocumentsSegment(inputdir)

    def gen_idf(self):
        ignored = {'', ' ', '', '。', ':', ',', ')', '(', '!', '?', '”', '“'}    #忽略词
        id_freq = {}    #词频字典
        i = 0
        for doc in self.documents:
            doc = set(x for x in doc if x not in ignored)   #剔除忽略词
            for x in doc:                                   #遍历文档
                id_freq[x] = id_freq.get(x, 0)   1          #更新词频
            if i % 1000 == 0:                               #每1000篇文章提示进度
                print('Documents processed: ', i, ', time: ',
                      datetime.datetime.now())
            i  = 1

        # 词频排序
        sortdata = dict(sorted(id_freq.items(), key=lambda x: x[1]))
        # 将词频转换后写入词频语料库
        with open(self.outputfile, 'w', encoding='utf-8') as f: #将词频取对数后,写入idf文件
            for key, value in sortdata.items():
                f.write(key   ' '   str(math.log(i / value, 2))   'n')

# 词频文件加载
class IDFLoader(object):
    def __init__(self, idf_path):
        self.idf_path = idf_path
        self.idf_freq = {}     # idf
        self.mean_idf = 0.0    # 均值
        self.load_idf()

    # 加载词频文件
    def load_idf(self):       # 从文件中载入idf
        cnt = 0
        with open(self.idf_path, 'r', encoding='utf-8') as f:
            for line in f:
                try:
                    word, freq = line.strip().split(' ')
                    cnt  = 1
                except Exception as e:
                    pass
                self.idf_freq[word] = float(freq)
            print(self.idf_freq)
        print('Vocabularies loaded: %d' % cnt)
        # 获取idf均值
        self.mean_idf = sum(self.idf_freq.values()) / cnt

if __name__ == "__main__":
    inputdir = 'C:PythonPycharmlangprocess\train'
    idffile = 'C:PythonPycharmlangprocess\udfidf.txt'
    stopwordfile= 'C:PythonPycharmlangprocess\stopwords.txt'
    filename = 'C:PythonPycharmlangprocess\trainC4-LiteratureC4-Literature02.txt'

    str = '''《三国演义》描写了从东汉末年到西晋初年之间近百年的历史风云,以描写战争为主,诉说了东汉末年的群雄割据混战和魏、蜀、吴三国之间的政治和军事斗争,最终司马炎一统三国,建立晋朝的故事。反映了三国时代各类社会斗争与矛盾的转化,并概括了这一时代的历史巨变,塑造了一群叱咤风云的三国英雄人物。全书可大致分为黄巾起义、董卓之乱、群雄逐鹿、三国鼎立、三国归晋五大部分。在广阔的历史舞台上,上演了一幕幕气势磅礴的战争场面。作者罗贯中将兵法三十六计融于字里行间,既有情节,也有兵法韬略。《三国演义》是中国文学史上第一部章回小说,是历史演义小说的开山之作,也是第一部文人长篇小说,中国古典四大名著之一。'''
    seg_list = jieba.cut(str)       #分词
    # 《|三国演义|》|描写|了|从|东汉|末年|到|西晋|初年|之间|近|百年|的|历史风云|,|以|描写|战争|为主|,|诉说|了|东汉|末年|的|群雄割据|混战|和|魏|、|蜀|、|吴三国|之间|的|政治|和|军事|斗争
    data = Counter(seg_list)        #用Counter函数构造字典
    # Counter({',': 12, '的': 10, '了': 6, '、': 6, '。': 6, '三国': 4, '是': 3, '《': 2, '三国演义': 2, '》': 2
    # Counter输出的时候有顺序,但其实内部是无顺序的,建议排序一下
    top10= data.most_common(10)     #通过Counter函数的most_common获取前10名
    #[(',', 12), ('的', 10), ('了', 6), ('、', 6), ('。', 6), ('三国', 4), ('是', 3), ('《', 2), ('三国演义', 2), ('》', 2)]
    sortdata=sorted(data.items(), key=lambda x: x[1], reverse=True)
    # [(',', 12), ('的', 10), ('了', 6), ('、', 6), ('。', 6), ('三国', 4), ('是', 3), ('《', 2), ('三国演义', 2), ('》', 2)
    # AttributeError: 'Counter' object has no attribute 'sort'
    # 所以只能转换为list再通过list进行排序
    items = list(data.items())
    items.sort(key=lambda x: x[1], reverse=True)
    # [(',', 12), ('的', 10), ('了', 6), ('、', 6), ('。', 6), ('三国', 4), ('是', 3), ('《', 2), ('三国演义', 2), ('》', 2), ('描写', 2), ('东汉', 2),

    # ----------------------------------------关键词提取-------------------------------------------
    # 基于TF-IDF算法的关键词抽取
    # 第一个参数:待提取关键词的文本
    # 第二个参数:返回关键词的数量,重要性从高到低排序
    # 第三个参数:是否同时返回每个关键词的权重
    # 第四个参数:词性过滤,为空表示不过滤,若提供则仅返回包括指定词性的词,默认值为空,即不筛选
    keywords = jieba.analyse.extract_tags(str, topK=5, withWeight=True, allowPOS=('ns', 'n', 'vn', 'v'))
    # [('三国', 0.5706667621368), ('兵法', 0.3433023063252), ('描写', 0.2863118806472), ('历史风云', 0.256041307266), ('群雄逐鹿', 0.242178363654)]

    # 基于 TF-IDF 算法的关键词抽取,使用停用词词典,使用逆向文件频率文本语料库
    tfidf = jieba.analyse.TFIDF()
    tfidf.set_stop_words('stopwords.txt')   # 使用停用词词典
    tfidf.set_idf_path('idf.txt')           # 使用默认的逆向文件频率(IDF)文本语料库
    keywords=tfidf.extract_tags(str,topK=5, withWeight=True, allowPOS=('ns', 'n', 'vn', 'v')) # 再进行
    # [('三国', 0.5706667621368), ('兵法', 0.3433023063252), ('描写', 0.2863118806472), ('历史风云', 0.256041307266), ('群雄逐鹿', 0.242178363654)]

    # 基于 TextRank 算法的关键词抽取
    # 第一个参数:待提取关键词的文本
    # 第二个参数:返回关键词的数量,重要性从高到低排序
    # 第三个参数:是否同时返回每个关键词的权重
    # 第四个参数:词性过滤,为空表示不过滤,若提供则仅返回符合词性要求的关键词,默认过滤词性是('ns', 'n', 'vn', 'v')
    keywords = jieba.analyse.textrank(str, topK=5, withWeight=True, allowPOS=('ns', 'n', 'vn', 'v'))
    # [('三国', 1.0), ('斗争', 0.7784764171715404), ('兵法', 0.6974027914816684), ('历史', 0.6748143587652791), ('时代', 0.6480813515953463)]

    # 利用jieba进行关键字提取时,有两种接口。
    # 一个基于TF-IDF算法,一个基于TextRank算法。
    # TF-IDF算法,完全基于词频统计来计算词的权重,然后排序,在返回TopK个词作为关键字。
    # TextRank相对于TF-IDF,基本思路一致,也是基于统计的思想,只不过其计算词的权重时,还考虑了词的上下文(通过窗口滑动来实现),
    #         而且计算词的权重时,也考虑了相关联系词的影响。可以说,TextRank实际上是依据位置与词频来计算词的权重的。
    # TF-IDF计算简单,运行性能更好。

    # ----------------------------------------自定义预料库后关键词提取-------------------------------------------
    #content = open(filename, 'rb').read()
    content = open(filename, 'r', encoding='utf-8', errors='ignore').read()

    jieba.analyse.set_stop_words(stopwordfile)
    keywords = jieba.analyse.extract_tags(content, topK=10)  #, withWeight=True, allowPOS=('ns', 'n', 'vn', 'v'))  # 再进行
    print('未使用自定义预料,输出关键词:',keywords)
    # 未使用自定义预料,输出关键词: ['岭南文化', '文化', '爱国主义', '学者', '近代', '研讨会', '侨乡', '传统', '研究', '炎黄']

    # 基于原始语料,生成自定义的词频库
    myidffile=IDFGen(inputdir,idffile)
    myidffile.gen_idf()
    jieba.analyse.set_stop_words(stopwordfile)
    jieba.analyse.set_idf_path(idffile);
    keywords = jieba.analyse.extract_tags(content, topK=10)
    print('使用自定义预料后,输出关键词:', keywords)
    # 使用自定义预料后,输出关键词: ['岭南文化', '爱国主义', '广东', '侨乡', '岭南', '中原', '与会', '商品经济', '学者', '近代']

0 人点赞