python-NLP:3关键词提取


TF /IDF方法

  TF-IDF算法(Term Frequency-Inverse Document Frequency,词频-逆文档频次算法)是一种基于统计的计算方法,常用于评估在一个文档集中一个词对某份文档的重要程度。这种作用显然很符合关键词抽取的需求,一个词对文档越重要,那就越可能是文档的关键词,人们常将TF-IDF算法应用于关键词提取中。
  从算法的名称就可以看出,TF-IDF算法由两部分组成:TF算法以及IDF算法。TF算法是统计一个词在一篇文档中出现的频次,其基本思想是,一个词在文档中出现的次数越多,则其对文档的表达能力也就越强。而IDF算法则是统计一个词在文档集的多少个文档中出现,其基本的思想是,如果一个词在越少的文档中出现,则其对文档的区分能力也就越强。
  TF算法和IDF算法也能单独使用,在最早的时候就是如此。但是在使用过程中,学者们发现这两种算法都有其不足之处。TF仅衡量词的出现频次,但是没有考虑到词的对文档的区分能力。比如针对下面这篇文档:

世界献血日,学校团体、献血服务志愿者等可到血液中心参观检验加工过程,我们会对检验结果进行公示,同时血液的价格也将进行公示。

  上文中“献血”“血液”“进行”“公示”等词出现的频次均为2,如果从TF算法的角度,他们对于这篇文档的重要性是一样的。但是实际上明显“血液”“献血”对这篇文档来说更关键。而IDF则是相反,强调的是词的区分能力,但是一个词既然能在一篇文档中频繁出现,那说明这个词能够很好地表现该篇文档的特征,忽略这一点显然也是不合理的。于是,学者们将这两种算法综合进行使用,构成TF-IDF算法,从词频、逆文档频次两个角度对词的重要性进行衡量。
  在实际使用中,TF的计算常用如下。其中n,表示词i在文档j中的出现频次,但是仅用频次来表示,长文本中的词出现频次高的概率会更大,这一点会影响到不同文档之间关键词权值的比较。所以在计算的过程中一般会对词频进行归一化。分母部分就是统计文档中每个词出现次数的总和,也就是文档的总词数。还是以上文文档为例,“献血”一词出现次数为2,文档的总词数为30,则tf(献血)=n(献血)/n(总)=2/30 ≈0.067。更直白的表示方式就是,tf(word)=(word在文档中出现的次数)/(文档总词数)。

  而IDF的计算常用式如下。|D|为文档集中总文档数,|DiI为文档集中出现词i的文档数量。分母加1是采用了拉普拉斯平滑,避免有部分新的词没有在语料库中出现过而导致分母为零的情况出现,增强算法的健壮性。

  TF-IDF 算法就是TF算法与IDF算法的综合使用,具体计算方法见式如下。对于这两种方法怎么组合,学者们也做了很多的研究,tf和idf是相加还是相乘,idf的计算究竟要取对数还是不取对数。经过大量的理论推导和实验研究后,发现下面的计算方式是较为有效的计算方式之一。

  除了上面提到的传统的TF-IDF算法之外,TF-IDF算法也有很多变种的加权方法。传统的TF-IDF算法中,仅考虑了词的两个统计信息(出现频次、在多少个文档出现),因此,其对文本的信息利用程度显然也是很少的。除了上面的信息外,在一个文本中还有许多信息能对关键词的提取起到很好的指导作用,例如每个词的词性、出现的位置等。在某些特定的场景中,如在传统的TF-IDF基础上,加上这些辅助信息,能对关键词提取的效果起到很好的提高作用。在文本中,名词作为一种定义现实实体的词,带有更多的关键信息,如在关键词提取过程中,对名词赋予更高的权重,能使提取出来的关键词更合理。此外,在某些场景中,文本的起始段落和末尾段落比起其他部分的文本更重要,如对出现在这些位置的词赋予更高的权重,也能提高关键词的提取效果。算法本身的定义是死的,但是结合我们的应用场景,对算法进行合适的重塑及改造,使之更适应对应场景的应用环境,无疑能对我们想要得到的结果起到更好的指导作用。

  源码实现
  思路:
  1对训练集文档 进行分词过滤,然后统计所有词的idf,和默认词idf(默认词表示该词不在训练集文档集中)
  2对待预测文本进行分词过滤,然后统计该文本tf。然后从1中结果查找待预测文本的idf(如果没有查找到就为默认词idf)。最后计算tf-idf。

import math

import jieba
import jieba.posseg as psg
import functools


# 停用词表加载方法
def get_stopword_list(stop_word_path):
    # 停用词表存储路径,每一行为一个词,按行读取进行加载
    stopword_list = [sw.replace('\n', '') for sw in open(stop_word_path,encoding='utf-8').readlines()]
    return stopword_list

# 分词方法,调用结巴接口
def seg_to_list(sentence, pos=False):
    if not pos:
        # 不进行词性标注的分词方法
        seg_list = jieba.cut(sentence) #返回可迭代对象
    else:
        # 进行词性标注的分词方法
        seg_list = psg.cut(sentence)#返回可迭代对象
    return seg_list

# 去除干扰词
def word_filter(seg_list, stopword_list,pos=False):
    stopword_list = stopword_list
    filter_list = []
    # 根据POS参数选择是否词性过滤
    ## 不进行词性过滤,则将词性都标记为n,表示全部保留
    for seg in seg_list:
        if not pos:
            word = seg
            flag = 'n'
        else:
            word = seg.word
            flag = seg.flag
        if not flag.startswith('n'):
            continue
        # 过滤停用词表中的词,以及长度为<2的词
        if not word in stopword_list and len(word) > 1:
            filter_list.append(word)

    return filter_list

# 数据加载,stopword_list为停用词 pos为是否词性标注的参数,corpus_path为数据集路径
def load_data( stopword_list,pos=False,corpus_path='./corpus.txt'):
    # 调用上面方式对数据集进行处理,处理后的每条数据仅保留非干扰词
    doc_list = []
    for line in open(corpus_path, 'r',encoding='utf-8'):
        content = line.strip()
        seg_list = seg_to_list(content, pos)
        filter_list = word_filter(seg_list,stopword_list,pos)
        doc_list.append(filter_list)

    return doc_list


# idf值统计方法
def train_idf(doc_list):
    """
    :param doc_list: 经过分词 且过滤的
    :return:
    """
    idf_dic = {}
    # 总文档数
    tt_count = len(doc_list)#

    # 每个词出现的文档数
    for doc in doc_list:
        for word in set(doc):
            idf_dic[word] = idf_dic.get(word, 0.0) + 1.0

    # 按公式转换为idf值,分母加1进行平滑处理
    for k, v in idf_dic.items():
        idf_dic[k] = math.log(tt_count / (1.0 + v))

    # 对于没有在字典中的词,默认其仅在一个文档出现,得到默认idf值
    default_idf = math.log(tt_count / (1.0))
    return idf_dic, default_idf



#  排序函数,用于topK关键词的按值排序
def cmp(e1, e2):
    import numpy as np
    res = np.sign(e1[1] - e2[1])
    if res != 0:
        return res
    else:
        a = e1[0] + e2[0]
        b = e2[0] + e1[0]
        if a > b:
            return 1
        elif a == b:
            return 0
        else:
            return -1


# TF-IDF类
class TfIdf(object):
    # 四个参数分别是:训练好的idf字典,默认idf值,处理后的待提取文本,关键词数量
    def __init__(self, idf_dic, default_idf, word_list, keyword_num):
        self.word_list = word_list
        self.idf_dic, self.default_idf = idf_dic, default_idf
        self.tf_dic = self.get_tf_dic()#待提取文本的tf值
        self.keyword_num = keyword_num

    # 统计tf值
    def get_tf_dic(self):
        tf_dic = {}
        for word in self.word_list:
            tf_dic[word] = tf_dic.get(word, 0.0) + 1.0

        tt_count = len(self.word_list)
        for k, v in tf_dic.items():
            tf_dic[k] = float(v) / tt_count

        return tf_dic
    # 按公式计算tf-idf

    def get_tfidf(self):
        tfidf_dic = {}
        for word in self.word_list:
            idf = self.idf_dic.get(word, self.default_idf)
            tf = self.tf_dic.get(word, 0)

            tfidf = tf * idf
            tfidf_dic[word] = tfidf

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

def tfidf_extract(word_list, filedata,pos=False, keyword_num=10):
    """
    :param word_list: 需要预测的分词数据
    :param filedata:
    :param pos:
    :param keyword_num:
    :return:
    """
    doc_list = filedata#训练集文件数据
    idf_dic, default_idf = train_idf(doc_list)#获取训练集文本集 idf 和默认idf(不存在的单词为默认idf)
    tfidf_model = TfIdf(idf_dic, default_idf, word_list, keyword_num)
    tfidf_model.get_tfidf()

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

    pos = True
    seg_list = seg_to_list(text, pos)#对text分词
    filter_list = word_filter(seg_list,stopword_list, pos)#去除text中的干扰词
    filedata=load_data(stopword_list,pos=False, corpus_path=data_path)#加载训练数据集文本

    print('TF-IDF模型结果:')
    tfidf_extract(filter_list,filedata,pos=False, keyword_num=10)


TfidfVectorizer实现

import jieba
import jieba.posseg as pseg
from sklearn.feature_extraction.text import TfidfVectorizer

# 获取停用词
def load_stopwords(stopwords_file):
    stopwords = set()
    with open(stopwords_file, 'r', encoding='utf-8') as f:
        for line in f:
            stopwords.add(line.strip())
    return stopwords


# 加载文档集,对文档集过滤词性和停用词
def filter_documents(data_path, stopwords):
    documents = []
    with open(data_path, 'r', encoding='utf-8') as f:
        for line in f:
            document = []
            words = pseg.cut(line.strip())
            for word, flag in words:
                if flag.startswith('n') and word not in stopwords and len(word) > 1:
                    document.append(word)
            documents.append(document)
    return documents


# 使用TF-IDF提取关键词
def extract_keywords_tfidf(documents, top_n=20):
    # 将分词过滤后的文档集转化为文本列表
    documents_text = [' '.join(document) for document in documents]

    # 创建TF-IDF向量化器
    tfidf_vectorizer = TfidfVectorizer()

    # 计算TF-IDF权重
    tfidf_matrix = tfidf_vectorizer.fit_transform(documents_text)

    # 获取特征词列表
    features = tfidf_vectorizer.get_feature_names() #scikit-learn版本小于或等于0.24.x 使用get_feature_names() 否则使用get_feature_names_out()
    #print(features)#['4s店', 't恤', 't恤衫', '一事', '一分钱', '一卡通', '一号线', '一块钱'....]

    # 计算每个文档中的关键词
    top_keywords_per_document = []
    for doc_id in range(len(documents)):
        document_tfidf_weights = tfidf_matrix[doc_id].toarray()[0]
        top_keyword_indices = document_tfidf_weights.argsort()[-top_n:][::-1]
        top_keywords = [features[idx] for idx in top_keyword_indices]
        top_keywords_per_document.append(top_keywords)

    return top_keywords_per_document




if __name__ == "__main__":
    stopwords_file = r'D:\deeplearn\xuexicaogao\web\stopword.txt'  # 停用词文件路径
    data_path = r'D:\deeplearn\xuexicaogao\web\corpus.txt'  # 文档集文件路径

    stopwords = load_stopwords(stopwords_file)
    documents = filter_documents(data_path, stopwords)
    print('停用词表的大小为:', len(stopwords))
    print('文档的数量为', len(documents))

    # 提取关键词
    top_keywords = extract_keywords_tfidf(documents)

  # 打印每个文档的前10个关键词
    for doc_id, keywords in enumerate(top_keywords):
        print(f'文档 {doc_id + 1} 的前10个关键词: {", ".join(keywords)}')

TextRank

  TextRank 算法是一种基于图的排序算法,主要用于文本处理中的关键词提取和文本摘要。它基于图中节点之间的关系来评估节点的重要性,类似于 Google 的 PageRank 算法。TextRank 算法的关键思想是,一个词语在文本中的重要性可以通过与其他词语的关系来评估,而这些关系可以表示为图中的边。
  图构建(Graph Construction): 将文本中的词语或短语表示为图的节点,词语之间的关系可以是共现关系、语义相似度等。通常,可以使用共现矩阵或者基于词向量的相似度来构建图。
边权重计算(Edge Weighting): 计算图中边的权重,反映节点之间的关系强度。例如,可以使用共现词频、词向量相似度等作为边的权重。
  节点权重计算(Node Weighting): 利用图中节点之间的关系以及边的权重来计算节点的权重。通常采用迭代方法,类似于 PageRank 算法,根据节点之间的相互影响来计算节点的权重。
  排名(Ranking): 根据节点的权重对节点进行排名,排名较高的节点被认为是重要的词语或短语。
TextRank 算法的节点得分更新公式:

import jieba
import jieba.posseg as psg
from jieba import analyse

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

    print('TextRank模型结果:')
    textrank_extract(text)

LSA/LSI/LDA算法

  LSA(Latent Semantic Analysis,潜在语义分析)和LSI(Latent Semantic Index,潜在语义索引),二者通常被认为是同一种算法,只是应用的场景略有不同,LSA是在需要构建的相关任务中的叫法。可以说,LSA和LSI都是对文档的潜在语义进行分析,但是潜在语义索引在分析后,还会利用分析的结果建立相关的索引。
LSA的主要步骤如下:

  1. 使用BOW模型将每个文档表示为向量;
  2. 将所有的文档词向量拼接起来构成词–文档矩阵(m×n);
  3. 对词–文档矩阵进行奇异值分解(SVD)操作([m×r]·[r×r]·[r×n]);
  4. 根据SVD的结果,将词–文档矩阵映射到一个更低维度k([m×k]·[k×k]·[k×n],0<k<r)的近似SVD结果,每个词和文档都可以表示为k个主题构成的空间中的一个点,通过计算每个词和文档的相似度(相似度计算可以通过余弦相似度或者是KL相似度进行),可以得到每个文档中对每个词的相似度结果,取相似度最高的一个词即为文档的关键词。

  LDA根据词的共现信息的分析,拟合出词–文档–主题的分布,进而将词、文本都映射到一个语义空间中。
  结合吉布斯采样的LDA模型训练过程一般如下:

  1. 随机初始化,对语料中每篇文档中的每个词w,随机地赋予一个topic编号z。
  2. 重新扫描语料库,对每个词w按照吉布斯采样公式重新采样它的topic,在语料中进行更新。
  3. 重复以上语料库的重新采样过程直到吉布斯采样收敛。
  4. 统计语料库的topic-word共现频率矩阵,该矩阵就是LDA的模型。

  经过以上的步骤,就得到一个训练好的LDA模型,接下来就可以按照一定的方式针对新文档的topic进行预估,具体步骤如下:

  1. 随机初始化,对当前文档中的每个词w,随机地赋一个topic编号z。
  2. 重新扫描当前文档,按照吉布斯采样公式,重新采样它的topic。
  3. 重复以上过程直到吉布斯采样收敛。
  4. 统计文档中的topic分布即为预估结果。
# -*- coding: utf-8 -*-
import math
import jieba
import jieba.posseg as psg
from gensim import corpora, models
import functools
 
 
def get_stopword_list():
    stop_word_path = 'stopwords.txt'
    stopword_list = [sw.replace('\n', '') for sw in open(stop_word_path, encoding='utf-8').readlines()]
    return stopword_list
 
 
# 分词方法
def seg_to_list(sentence, pos=False):
    if not pos:
        # 不进行词性标注的分词方法
        seg_list = jieba.cut(sentence)
    else:
        # 进行词性标注的分词方法
        seg_list = psg.cut(sentence)
    return seg_list
 
 
# 去除干扰词,根据pos判断是否过滤除名词外的其他词性,再判断词是否在停用词表中,长度是否大于等于2等。
def word_filter(seg_list, pos=False):
    stopword_list = get_stopword_list()
    filter_list = []
    # 根据pos参数选择是否词性过滤
    # 不进行词性过滤,则将词性都标记为n,表示全部保留
    for seg in seg_list:
        if not pos:
            word = seg
            flag = 'n'
        else:
            word = seg.word
            flag = seg.flag
        if not flag.startswith('n'):
            continue
        # 过滤高停用词表中的词,以及长度为<2的词
        if word not in stopword_list and len(word) > 1:
            filter_list.append(word)
    return filter_list
 
 
# 数据加载
def load_data(pos=False, corpus_path='text2.txt'):
    doc_list = []
    for line in open(corpus_path, 'r', encoding='utf-8'):
        content = line.strip()
        seg_list = seg_to_list(content, pos)
        filter_list = word_filter(seg_list, pos)
        doc_list.append(filter_list)
    return doc_list
 
 
# topK
def cmp(e1, e2):
    import numpy as np
    res = np.sign(e1[1] - e2[1])
    if res != 0:
        return res
    else:
        a = e1[0] + e2[0]
        b = e2[0] + e1[0]
        if a > b:
            return 1
        elif a == b:
            return 0
        else:
            return -1
 
 
# 主题模型
class TopicModel(object):
    def __init__(self, doc_list, keyword_num, model="LSI", num_topics=4):
        # 使用gensim接口,将文本转为向量化表示
        self.dictionary = corpora.Dictionary(doc_list)
        # 使用BOW模型向量化
        corpus = [self.dictionary.doc2bow(doc) for doc in doc_list]
        # 对每个词,根据tf-idf进行加权,得到加权后的向量表示
        self.tfidf_model = models.TfidfModel(corpus)
        self.corpus_tfidf = self.tfidf_model[corpus]
 
        self.keyword_num = keyword_num
        self.num_topics = num_topics
        # 选择加载的模型
        if model == 'LSI':
            self.model = self.train_lsi()
        else:
            self.model = self.train_lda()
        # 得到数据集的主题-词分布
        word_dic = self.word_dictionary(doc_list)
        self.wordtopic_dic = self.get_wordtopic(word_dic)
 
    def train_lsi(self):
        lsi = models.LsiModel(self.corpus_tfidf, id2word=self.dictionary, num_topics=self.num_topics)
        return lsi
 
    def train_lda(self):
        lda = models.LdaModel(self.corpus_tfidf, id2word=self.dictionary, num_topics=self.num_topics)
        return lda
 
    def get_wordtopic(self, word_dic):
        wordtopic_dic = {}
        for word in word_dic:
            single_list = [word]
            wordcorpus = self.tfidf_model[self.dictionary.doc2bow(single_list)]
            wordtopic = self.model[wordcorpus]
            wordtopic_dic[word] = wordtopic
        return wordtopic_dic
 
    # 词空间构建方法和向量化方法,在没有gensim接口时的一般处理方法
    def word_dictionary(self, doc_list):
        dictionary = []
        for doc in doc_list:
            dictionary.extend(doc)
 
        dictionary = list(set(dictionary))
 
        return dictionary
 
    def doc2bowvec(self, word_list):
        vec_list = [1 if word in word_list else 0 for word in self.dictionary]
        return vec_list
 
    # 计算词的分布和文档的分布的相似度,取相似度最高的keyword_num个词作为关键词
    def get_simword(self, word_list):
        sentcorpus = self.tfidf_model[self.dictionary.doc2bow(word_list)]
        senttopic = self.model[sentcorpus]
 
        # 余弦相似度计算
        def calsim(l1, l2):
            a, b, c = 0.0, 0.0, 0.0
            for t1, t2 in zip(l1, l2):
                x1 = t1[1]
                x2 = t2[1]
                a += x1 * x1
                b += x1 * x1
                c += x2 * x2
            sim = a / math.sqrt(b * c) if not (b * c) == 0.0 else 0.0
            return sim
 
        # 计算输入文本和每个词的主题分布相似度
        sim_dic = {}
        for k, v in self.wordtopic_dic.items():
            if k not in word_list:
                continue
            sim = calsim(v, senttopic)
            sim_dic[k] = sim
 
        for k, v in sorted(sim_dic.items(), key=functools.cmp_to_key(cmp), reverse=True)[:self.keyword_num]:
            print(k + "/ ", end='')
        print()
 
 
def topic_extract(word_list, model, pos=False, keyword_num=10):
    doc_list = load_data(pos)
    topic_model = TopicModel(doc_list, keyword_num, model=model)
    topic_model.get_simword(word_list)
 
 
if __name__ == '__main__':
    text = '6月19日,《2012年度“中国爱心城市”公益活动新闻发布会》在京举行。' + \
           '中华社会救助基金会理事长许嘉璐到会讲话。基金会高级顾问朱发忠,全国老龄' + \
           '办副主任朱勇,民政部社会救助司助理巡视员周萍,中华社会救助基金会副理事长耿志远,' + \
           '重庆市民政局巡视员谭明政。晋江市人大常委会主任陈健倩,以及10余个省、市、自治区民政局' + \
           '领导及四十多家媒体参加了发布会。中华社会救助基金会秘书长时正新介绍本年度“中国爱心城' + \
           '市”公益活动将以“爱心城市宣传、孤老关爱救助项目及第二届中国爱心城市大会”为主要内容,重庆市' + \
           '、呼和浩特市、长沙市、太原市、蚌埠市、南昌市、汕头市、沧州市、晋江市及遵化市将会积极参加' + \
           '这一公益活动。中国雅虎副总编张银生和凤凰网城市频道总监赵耀分别以各自媒体优势介绍了活动' + \
           '的宣传方案。会上,中华社会救助基金会与“第二届中国爱心城市大会”承办方晋江市签约,许嘉璐理' + \
           '事长接受晋江市参与“百万孤老关爱行动”向国家重点扶贫地区捐赠的价值400万元的款物。晋江市人大' + \
           '常委会主任陈健倩介绍了大会的筹备情况。'
 
    pos = True
    seg_list = seg_to_list(text, pos)
    filter_list = word_filter(seg_list, pos)    # 返回的是一个没有停用词 并且长度>2的词的list
 
    print('LSI模型结果:')
    topic_extract(filter_list, 'LSI', pos)
    print('LDA模型结果:')
    topic_extract(filter_list, 'LDA', pos)
 

gensim LDA实战

import jieba
import pandas as pd
import numpy as np
doc1="从海南、安徽、上海等省市的互联网医院管理规定来看,关于复诊、医生执业要求,虽然都在国家卫健委文件的框架之内,但各地形成了不同的细化版本。相关负责人认为,在《意见》指导下,未来互联网医院可能会在审批、医生执业、互联网诊疗科目范围、服务流程等方面有更明确的界定;行业标准的补位和监管政策的统一,能在一定程度上改善目前市场某些机构和服务参差不齐的情况,有利于行业更规范、更健康发展。尽管文件中“全国统一的互联网医疗审批标准”这一表述可能包含很多方面,可能是准入标准,可能是审批流程,也可能是对不同主体的开放程度,无论是包含哪些方面,能做到最大程度的统一,就能促进行业的进一步规范。"
doc2="近年来,农业机械化已经取得了长足的进步,包括整地,播种,采收等等工作都可以通过机械来完成,大大的解放了劳动力。在此基础上,农业机械正朝着无人操作的全自动化方向发展,包括利用GPS技术和感应技术的无人驾驶除草机,喷药机,还有结合仿生学的果实采摘机器人。很多公司已经投入了大量的资金和技术努力实现作物生产过程中全面的机器人操作。可以想象,未来的农业,再也不需要人们在极端的环境条件下挥汗如雨,辛勤劳作。采用机器人,让他们按照设定好的程序完成指定的任务,不仅能够节约人工成本,还能够突破时间的限制,实现24小时作业,同时更能够达到精准的操作,保证产品的一致性。"
doc3="在这个特殊时期,热身赛也有特殊的意义。CBA早已恢复正常,而美国由于大环境糟糕,现在还只能试水热身赛。无论如何,总算迈出了第一步。詹姆斯已经迫不及待,“开工吧,今天重返赛场,我已经等不及了,这只是一场热身赛,但对于我而言,这场比赛的意义不止于此,要时刻保持冠军心态。”詹姆斯写道。开场后,两队大举对攻,防守都比较松,完全是热身赛的架势。两队的命中率也都很高,特别是独行侠首发的小库里,三分球连连命中。前几分钟,独行侠弹无虚发,两队得分很快就达到两位数。不过独行侠提前变阵,换上了“大杀器”马扬诺维奇和巴里亚,命中率略有下降,而湖人继续猛攻。韦特斯投中本节的压哨三分,湖人以29-22结束首节。"
doc4="当前医疗的问题仍然是医疗资源分布不均带来的‘看病贵、看病难’以及分级诊疗的切实落实。”39互联网医院相关负责人称,“互联网医疗产品和平台能解决这些问题,能带来根本性的改变。对此,中国社科院经济研究所公共政策研究中心主任朱恒鹏则建议,放开处方药的网上销售;放开医生网上诊断,患者在网上获取医生的处方后能在线买药;开放医保账户针对医生网上诊疗费用的支付,让医生可以从网上收取诊疗费。同时,由于处方在网上公开,极大强化了个人声誉,让医生更重医德不贪小利。"
content = [doc1, doc2, doc3,doc4]

#分词
content_S = []
for line in content:
    current_segment = [w for w in jieba.cut(line) if len(w)>1]#分词并去除单字词
    if len(current_segment) > 1 and current_segment != '\r\t':
        content_S.append(current_segment)
#分词结果转为DataFrame
df_content = pd.DataFrame({'content_S':content_S})


#停用词加载
stopwords = pd.read_table(r'D:\deeplearn\xuexicaogao\web\stopword.txt',names = ['stopword'],quoting = 3) #quoting = 3保存的文本会在头和尾不会多出双引号。


# 去除停用词
def drop_stopwords(contents, stopwords):
    contents_clean = []
    all_words = []
    for line in contents:
        line_clean = []
        for word in line:
            if word in stopwords:
                continue
            line_clean.append(word)
            all_words.append(word)
        contents_clean.append(line_clean)
    return contents_clean, all_words


contents = df_content.content_S.values.tolist()
stopwords = stopwords.stopword.values.tolist()
# contents_clean存储的是一个文本处理结果一个数组,all_words是将所有文本处理结果存储为1个数组
contents_clean, all_words = drop_stopwords(contents, stopwords)

# 处理后的结果转化为DataFrame
df_content = pd.DataFrame({'contents_clean': contents_clean})  # 文本处理结果
df_all_words = pd.DataFrame({'all_words': all_words})  # 语料词典



from gensim import corpora, models, similarities
import gensim

dictionary = corpora.Dictionary(contents_clean)
corpus = [dictionary.doc2bow(sentence) for sentence in contents_clean]
lda = gensim.models.ldamodel.LdaModel(corpus=corpus, id2word=dictionary, num_topics=3, random_state=3)

print(lda.print_topics(num_topics=3, num_words=3))
# 预测文本的主题
for e, values in enumerate(lda.inference(corpus)[0]):
    print(content[e])
    for ee, value in enumerate(values):
        print('\t主题%d推断值%.2f' % (ee, value))

可以看出给出的doc1和doc4是医疗类,很好的将它归为1类主题。
注意 要指定 random_state的值,不指定每次运行结果不一样。
LDA运行结果的主题分类不一定是我们想要的,有可能它将doc1和doc2归为1类,因为一篇文档的主题有多个,可能存在的分类也有多种。
模型保存

lda.save('lda.model')

对新文本进行预测

#coding:utf-8

from gensim.models import  ldamodel
doc0="从海南、安徽、上海等省市的互联网医院管理规定来看,关于复诊、医生执业要求,虽然都在国家卫健委文件的框架之内,但各地形成了不同的细化版本。相关负责人认为,在《意见》指导下,未来互联网医院可能会在审批、医生执业、互联网诊疗科目范围、服务流程等方面有更明确的界定;行业标准的补位和监管政策的统一,能在一定程度上改善目前市场某些机构和服务参差不齐的情况,有利于行业更规范、更健康发展。尽管文件中“全国统一的互联网医疗审批标准”这一表述可能包含很多方面,可能是准入标准,可能是审批流程,也可能是对不同主体的开放程度,无论是包含哪些方面,能做到最大程度的统一,就能促进行业的进一步规范"
# 加载模型
lda = ldamodel.LdaModel.load('lda.model')

#停用词加载
stopwords = pd.read_table('stopwords.txt',names = ['stopword'],quoting = 3)
#分词 并去除停用词
word = [w for w in jieba.cut(doc0) if len(w) > 1 and w not in stopwords]
bow = dictionary.doc2bow(word)
print(lda.get_document_topics(bow))

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

总裁余(余登武)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值