相关文章推荐
博学的钢笔  ·  java 并发时时间戳 ...·  1 年前    · 
魁梧的排球  ·  python - ...·  1 年前    · 

主题建模是一种无监督的机器学习方法,它帮助我们发现文档(语料库)中隐藏的语义结构,它使我们能够快速的发现文档中所包含的主题。 主题模型可以应用于推荐系统和论坛中的帖子自动加注标签等这样的应用中。Latent Dirichlet Allocation(LDA)是一种用于发现文档(语料库)中存在的主题的算法。如果您使用的是Python,目前有一些开源库如Gensim、SkLearn都提供了主题建模的工具,今天我们就来使用这两个开源库提供的3种主题建模工具如Gensim的 ldamodel 和SkLearn的 sklearn.decomposition.NMF sklearn.decomposition.LatentDirichletAllocation 对中文语料库进行主题建模,并比较它们的结果。

LDA和NMF的工作原理

在这里我们不会对主题建模的数学原理进行深入的分析和讲解,因为我们的目的是“实战”和“应用”,如果想深入了解主题建模请自行搜索相关资料和我上面提供的文档的链接。LDA和NMF的数学原理是不一样的,但两种算法都能够返回属于语料库中的主题对应的文档和属于主题的单词。 LDA基于概率图形建模,而NMF是基于于线性代数。 两种算法都将词袋矩阵作为输入(即,每个文档表示为行,每列包含语料库中的单词计数)。 然后,每个算法都会产生2个矩阵: 文档的主题分布矩阵 主题的单词分布矩阵 :

我们要在建模之前指定文档集中所包含的主题数,这是一个问题,上述算法都没有自动确定主题数的功能,主题数类似与聚类算法中的聚类中心数,目前还没有太好的办法来自动确定主题数,一般都是凭经验和对业务的了解来确定主题数。

我们的数据来自于搜狗的新闻语料库,你可以从 百度网盘 中下载,你也可以下载经过我整理好的csv文件( https://pan.baidu.com/s/10HqLPMyw2nMLgFgrb127VQ 提取码:546q)。首先我们加载所需要的库

import pandas as pd
import chardet
import pandas as pd
import numpy as np
import jieba as jb
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer
from sklearn.decomposition import NMF, LatentDirichletAllocation
import gensim
from gensim import corpora
import pyLDAvis.gensim
df = pd.read_csv('./data/sogou2006_2.csv')
df=df[['text','label']]
print(len(df))
df.sample(10)

总共有17909条记录,label是原来文件对应的文件夹名称,所以我导入每个文件夹里面的文件后把它们所在的文件夹作为label,我们查看一下总共有多少个lable:

df['label_id'] = df['label'].factorize()[0]
label_id_df = df[['label', 'label_id']].drop_duplicates().sort_values('label_id').reset_index(drop=True)
label_id_df

总共有9个label,我将其转换成对应的label_id,接下来我们查看几个新闻的具体内容:

经过对上述新闻内容的查看,我感觉label_id=3的新闻内容是关于“体育”方面的内容,label_id=5好像是和"教育"相关的内容,label_id=8好像是和“军事”相关的内容。由此可见不同的label_id对应不同类型的新闻内容。下面我们要进行数据清洗,因为新闻内容中充斥着大量的符号(回车符换行符等),首先我们定义几个数据清洗的函数:

#定义删除除字母,数字,汉字以外的所有符号的函数
def remove_punctuation(line):
    line = str(line)
    if line.strip()=='':
        return ''
    rule = re.compile(u"[^\u4E00-\u9FA5]")
    line = rule.sub('',line)
    return line
#停用词列表
def stopwordslist(filepath):  
    stopwords = [line.strip() for line in open(filepath, 'r', encoding='utf-8').readlines()]  
    return stopwords  
#加载停用词
stopwords = stopwordslist("./data/chineseStopWords.txt")

接下来我开始分词和过滤停用词,并生成两个新的字段clean_text和cut_text:

#删除除汉字以外的所有符号
df['clean_text'] = df['text'].apply(remove_punctuation)
#分词,并过滤停用词
df['cut_text'] = df['clean_text'].apply(lambda x: " ".join([w for w in list(jb.cut(x)) if w not in stopwords]))
df.head()

下面我们要对cut_text进行向量化处理,我们将使用两种方法来进行方法来进行文本的向量化处理:CountVectorizer和TfidfVectorizer这两种方法在我之前的博客中都多次提到,这里不再详细讲解:

no_features = 1000
tfidf = TfidfVectorizer(max_features=no_features)
tfidf_features = tfidf.fit_transform(df.cut_text)
tfidf_feature_names = tfidf.get_feature_names()
cv = CountVectorizer(max_features=no_features)
cv_features = cv.fit_transform(df.cut_text)
cv_feature_names = cv.get_feature_names()

NMF和LatentDirichletAllocation

接下来我们要使用SKLearn的两种主题建模的方法 NMF LatentDirichletAllocation 分别来进行主题建模,其中NMF是基于非负矩阵分解(Non-negative Matrix Factorization)来实现主题建模,原始数据中包含了9个分类,那么我们在这里也指定9个主题。在NMF模型中我们使用tf-idf特征向量来训练模型,而在LDA的模型中我们使用CountVectorizer特征向量来训练模型。

两个模型中的参数请参考官方文档,在这里不一一说明。

no_topics = 9
nmf_tfidf = NMF(n_components=no_topics, random_state=1, alpha=.1, l1_ratio=.5, init='nndsvd').fit(tfidf_features)
lda_cv = LatentDirichletAllocation(n_topics=no_topics, max_iter=5, learning_method='online', learning_offset=50.,random_state=0).fit(cv_features)

模型训练完成后,下面我们打印一下主题的分布:

def display_topics(model, feature_names, no_top_words):
    for topic_idx, topic in enumerate(model.components_):
        print("主题 {} : {}".format(topic_idx,"|".join([feature_names[i] for i in topic.argsort()[:-no_top_words - 1:-1]])))
no_top_words = 10
print('---------------NMF-tfidf_features 主题-----------------------------------------')
display_topics(nmf_tfidf, tfidf_feature_names, no_top_words)
print()
print('--------------Lda-CountVectorizer_features 主题--------------------------------')
display_topics(lda_cv, cv_feature_names, no_top_words)

我们看到两个模型分布生成了它们的主题的分布,和每个主题中概率最高的前10个词语,下面我们来分析一下这两个模型生成的主题分布:

NMF的主题分布 

  • 主题0: 应该和生活相关
  • 主题1: 好像和金融证券相关
  • 主题2:和体育相关
  • 主题3: 和旅游相关
  • 主题4: 和工作、职业相关
  • 主题5: 和教育考试相关
  • 主题6: 和医疗相关
  • 主题7:和军事相关
  • 主题8:和企业相关

LDA的主题分布

  • 主题0: 好像和金融证券相关
  • 主题1: 和工作、职业相关
  • 主题2:和企业相关
  • 主题3:  和企业相关
  • 主题4: 似乎和体育有关,但不是很明确
  • 主题5: 似乎和教育考试相关
  • 主题6:  不是很明确
  • 主题7:不是很明确
  • 主题8:好像和军事有关

经过上述分析,个人感觉好像NMF的主题分布更加明确。LDA的主题分布有些不明确的地方,也有些主题含义似乎有重叠。

接下来我们使用训练集以外的数据来预测一下主题,我们随机从各大门户网站摘录几条新闻来进行预测:

def predict_topic_by_cv(text):
    txt = remove_punctuation(text)
    txt = [w for w in list(jb.cut(txt)) if w not in stopwords]
    txt = [w for w in txt if len(w)>1]
    txt = [" ".join([w for w in txt])]
    newfeature = cv.transform(txt)
    doc_topic_dist_unnormalized = np.matrix(lda_cv.transform(newfeature))
    doc_topic_dist = doc_topic_dist_unnormalized/doc_topic_dist_unnormalized.sum(axis=1)
    topicIdx = doc_topic_dist.argmax(axis=1)[0,0]
    print('该文档属于:主题 {}'.format(topicIdx))
    print("主题 {} : {}".format(topicIdx,"|".join([cv_feature_names[i] for i in (lda_cv.components_[topicIdx,:]).argsort()[:-no_top_words - 1:-1]])))

上述随机从门户网站上摘录的新闻预测结果似乎是正确的。

Gensim 主题建模

下面我们使用Gensim库来进行LDA主题建模,Gensim的LDA建模需要两个东西: dictionary(字典)和corpus(语料),其中dictionary用来存放文档集的词汇表和索引,corpus则是文档集的向量化表示,它类似与sklearn的CountVectorizer和TfidfVectorizer的向量化表示,因此corpus也有两种表示方法:基于计算的和基于TF-IDF的向量化表示:

text_data = df.cut_text.apply(lambda x:x.split())
#过滤掉单个汉字的词语
text_data = text_data.apply(lambda x:[w for w in x if len(w)>1] )
dictionary = corpora.Dictionary(text_data)
#过滤掉词频小于5次,和词频大于90%的词语
dictionary.filter_extremes(no_below=5, no_above=0.9)

下面我们使用基于计数的语料来进行主题建模,我们指定了7个主题:

#计数的语料
corpus = [dictionary.doc2bow(text) for text in text_data]
#普通LDA模型
import gensim
no_topics = 9
ldamodel = gensim.models.ldamodel.LdaModel(corpus, num_topics = no_topics, id2word=dictionary)
topics = ldamodel.print_topics(num_words=8)
for topic in topics:
    print("主题 %d: " % (topic[0]))
    print(topic[1])
    print()

 下面我们使用基于TF-IDF的语料来进行主题建模,我们同样指定了7个主题,在这里我们使用的是基于并发的多核LDA模型(LdaMulticore),如果你的CPU是多核的可以使用该方法来训练模型,这样可以缩短训练的时间:

#tf-idf语料
tfidf = gensim.models.TfidfModel(corpus)
corpus_tfidf = tfidf[corpus]
#多核并行lda模型
no_topics = 9
tf_idf_lda_model = gensim.models.LdaMulticore(corpus_tfidf, num_topics=no_topics, id2word=dictionary, passes=2, workers=4)
topics = tf_idf_lda_model.print_topics(num_words=8)
for topic in topics:
    print("主题 %d: " % (topic[0]))
    print(topic[1])
    print()

pyLDAvis是一个可以帮助用户理解语料库中主题分布的一个可视化工具。 pyLDAvis从训练好的LDA主题模型中提取信息,以通Web的交互式形式将主题分布做可视化的展示。

lda_display = pyLDAvis.gensim.prepare(tf_idf_lda_model, corpus_tfidf, dictionary, sort_topics=False)
pyLDAvis.display(lda_display)
lda_display = pyLDAvis.gensim.prepare(ldamodel, corpus, dictionary, sort_topics=False)
pyLDAvis.display(lda_display)

图中圆圈代表不同的主题,圆圈的大小代表主题的重要程度,圆圈越大表示该主题对应数据来说更重要。如果圆圈之间有相互重叠则说明它们所代表的主题有相似之处。

完整代码在此下载

LDA主题模型在2002年被David M. Blei、Andrew Y. Ng(是的,就是吴恩达老师)和Michael I. Jordan三位第一次提出,近几年随着社会化媒体的兴起,文本数据成为越来越重要的分析资料;海量的文本数据对社会科学研究者的分析能力提出了新的要求,于是LDA主题模型(Topic Model)作为一种能够从大量文本中提取出主题的概率模型,被越来越多的运用到主题发现、文档标记... 简介所谓分析,通常都是指从数据中获取“信息”。近来,随着数据迅猛增长——其中绝大多数数据是非结构的,要想获得相关想要的信息变成越来越困难。庆幸地是,与此同时出现了一些强大的方法来帮助我们从这些数据中抽取出我们想要的信息。文本挖掘领域中这样相关的一种技术是主题建模。正如其名,主题建模能够从一个文本对象中自动识别它的主题,并且发现隐藏的模式。这些能够帮助做出更好的决策。主题建模和那些基于规则的文本挖掘方 信息时代的高速发展让我们得以使用手机、电脑等设备轻松从网络上获取信息。但是,这似乎也是一把双刃剑,我们在获取到众多信息的同时,又可能没有太多时间去一一阅读它们,以至于“收藏从未停止,学习从未开始”的现象屡见不鲜。 这篇文章估计以后也会在收藏夹里面吃灰吧! 为了能够高效地处理巨大的文档信息,我在学习的过程中,接触到了 LDA 主题提取这个方法。经过学习,发现它特别有意思,它的主要功能是 能将众多文档进行主题分类,同时展示出主题词 当我发现这个功能之后,我便开始奇思妙想了,譬如我可以根据它的这个 作者 |云朵君来源 | 数据STUDIO主题识别是一种在大量文本中识别隐藏主题的方法。潜在狄利克雷分配 (LDA) 技术是一种常见的主题建模算法,在 Python 的 Gensim 包中有很好的实现。问题是确定如何提取独特、重要的高质量主题。这取决于文本准备质量和确定理想主题数量的方法。本文中将和大家一起尝试解决这两个问题。写在前面从大量文本中自动提取人们谈论的主题(主... 主题建模是对文本进行分析的一种方法,通过将文本分成不同的主题进行分析,可以更好地了解文本中的信息和结构。潜在狄利克雷分配(LDA,Latent Dirichlet Allocation)是一种用于主题建模的机器学习算法,它能够自动地发现文档集合中的主题。我们通过上述步骤实现了LDA模型对文本进行主题建模的过程。这里只是简单演示了实现过程,实际应用时可能需要对参数进行调优,以得到更好的效果。接下来,我们需要对文本进行预处理,包括去除停用词、分词、去除低频词等操作。最后,我们可以将模型保存下来,以便后续使用主题模型LDA的实现及其可视化pyLDAvis1. 无监督提取文档主题——LDA模型1.1 准备工作1.2 调用api实现模型2. LDA可视化交互分析——pyLDAvis2.1 安装pyLDAvis2.2 结合gensim调用api实现可视化p.s. 保存结果为独立网页p.p.s. 加快prepare速度?2.3 如何分析pyLDAvis可视化结果2.3.1. **每个主题表示什么意义?**2.3.2 每个主题有多么普遍?2.3.3 主题之间有什么关联? 1. 无监督提取文档主题——LDA模型 1、LDA:(来自百度百科) LDA(Latent Dirichlet Allocation)是一种文档主题生成模型,也称为一个三层贝叶斯概率模型,包含词、主题文档三层结构。所谓生成模型,就是说,我们认为一篇文章的每个词都是通过“以一定概率选择了某个主题,并从这个主题中以一定概率选择某个词语”这样一个过程得到。文档主题服从多项式分布主题到词服从多项式分布LDA是一种非... 链接入口:【python-sklearn】中文文本 | 主题模型分析-LDA(Latent Dirichlet Allocation)_哔哩哔哩_bilibili概念主题:自动将文本语料库编码为一组具有实质性意义的类别主题分析的典型代表:隐含狄利克雷分布LDA)最明显的特征:能够将若干文档自动编码分类为一定数量的主题主题数量需要人为确定主题数量通过对比新旧文档来判断模型的好坏,然后在不同参数的很多模型找到最优模型。 定义函数print_top_words: file_path = 'D:/lda/data' os.chdir(file_path) data=pd.read_excel("data.xlsx")#content type Familia开源项目包含文档主题推断工具、语义匹配计算工具以及基于工业级语料训练的三种主题模型:Latent Dirichlet Allocation(LDA)、SentenceLDA 和Topical Word Embedding(TWE)。 支持用户以“拿来即用”的方式进行文本分类、文本聚类、个性化推荐等多种场景的调研和应用。考虑到主题模型训练成本较高以及开源主题模型资源有限的现状,我们会陆...