LDA(Latent Dirichlet Allocation)主题建模是NLP确定文档主题方法,为无监督学习方法,当面对多个文档,能挖掘潜在的主题,类似于聚类方法,但又何聚类实质不一样,LDA从概率的角度来推出主题和词的分布,主题和词相互混合,没有聚类算法界限那么清晰。
理解LDA牵涉很多算法和思想,马尔科夫链蒙特卡洛算法(MCMC)、吉布斯采样(Gibbs Sampling)、Gammer函数、贝塔分布、狄利克雷分布(Dirichlet)、多项式分布、EM算法、马尔科夫链……
这里仅从图解的角度理解LDA算法原理,图1是整体LDA生成文档的过程,主要讲解图2,如图2,首先看到LDA变量联合概率分布,α(Alpha)与β(Beta)服从狄利克雷分布,(为什么选择狄利克雷,从图这里很明显可以感受狄利克雷分布的优势可以将文档中主题和词语的可以进行有效分割),假设我们事先准确知道主题及主题数量,事实上主题是最后根据词结合对数据的理解,人为定义,这里只是方便表述图示,第一步,主题1对某个文档根据狄利克雷分布生成主题,主题1=0.7science+0.1politics+0.2sports,到主题2,从主题2方框里随机又放回的抽取主题,根据主题1概率分布,会得到一堆主题,显然是满足多项式分布的,到这里我们已经知道主题了。第二步,词语1根据狄利克雷分布生成,我们可以看出蓝色球的为science主题,对应的词分布science = 0.4Galaxy+0.4Planet+0.1Ball+0.1Referendum,那对应的词语2有相应的词语,这个时候如何将主题与词语联系起来?这个时候从主题2随机选取主题,接着从词语2挑选,循环多次,这个时候生成了一个新的文档。图2展示的是生成1个新文档的过程,实际根据生成原始文档,会生成一系列的文档集合,这里记做A1,调整α与β的值,会生成新的文档集合A2、A3……,现在比较A1、A2……文档与源文档的相同程度,理论上生成相同的概率特别低,这里比较小概率下那个文档相同程度更高一点,相同程度高一点对应的设置α与β才是最佳参数,也正是我们需要的最佳主题,图3所示。
图1
图2
图3
狄利克雷(Dirichlet)与多项式分布满足共轨分布,样本信息前先验概率分布与后验分布均属于同一分布
吉布斯采样(Gibbs Sampling),是MCMC算法的一种变形,对于未知的概率分布或者难以直接抽样获得的分布确定联合分布,但需要知道每个变量的条件概率分布,同时满足容易抽样,来模拟联合分布,常用于统计推断,这里对LDA联合概率分布的隐变量进行推断。如图公式,吉布斯采样做的是将给定主题条件下选择词语的最大化的概率。
如图吉布斯采样解决的问题是尽可能的将文章和文字尽趋近单色,选择Doc1的ball,Topic3出现在Doc1出现两次同时选择的ball在Topic3出现了3次,为了避免出现0值出现,我们加入α和β伪数字,这时候发现ball属于Topic3的概率最大,这时候我们将ball这个词变成红色,通过不断循环将每个词进行着色,最后得出结果,Topic1中的出现plant和galaxy,我们可以将其定义为Science这个主题。
缺点:
1.不适用短文本,由于LDA将文档建模为主题混合,后从主题从提取相对应的词,这里提取相应的词,类似于你从黑盒子里抽取一些球,只有抽取的球足够多,才能推断黑盒子里的球颜色的分布,如果词很少,很难推断参数,
2.需要不断调整模型参数,才能凝练出合适的主题
其实无监督模型(包括聚类算法)对数据质量还是有一定的要求,根据经验,除了保证数据的干净外,越是差异化的大的数据,越是能得到比较好的效果,这要求使用者对数据有足够的敏感度,上来套模型大概率会得不到满意效果
代码演示及结论解释
import pandas as pd
import numpy as np
import re
import gensim
import jieba
from gensim import corpora
from gensim.models.coherencemodel import CoherenceModel
import pyLDAvis
import pyLDAvis.gensim_models
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'SimHei'
%matplotlib inline
#分词代码
def jieba_cut(mytext):
jieba.load_userdict('custwords.txt')
jieba.initialize()
with open('stopwords.txt',encoding ='utf-8') as f:
file_stop = f.readlines()
stop_list = []
for line in file_stop:
line = re.sub('\n|\\r', '', line)
stop_list.append(line)
word_list = []
#jieba分词
seg_list = jieba.lcut(mytext)
for seg_word in seg_list:
if seg_word not in stop_list:
word_list.append(seg_word)
return (" ").join(word_list)
#读取数据
df_data = pd.read_excel('hotelkk.xlsx').astype(str)
df_data['content_clean'] = df_data.content_clean.apply(jieba_cut)
cut_word_list = [cont.split() for cont in df_data.content_clean.tolist()]
#α和β为超参数,选择默认的,gensim调参做的还可以,里面已经封装好参数,如果有需要可以自行设置里面的参数,这里面是优化空间的
def compute_coherence_values(dictionary, corpus, texts, limit, start=2, step=3):
coherence_values = []
model_list = []
for num_topics in range(start, limit, step):
model = gensim.models.ldamodel.LdaModel(corpus=corpus, num_topics=num_topics, id2word=dictionary)
model_list.append(model)
coherencemodel = CoherenceModel(model=model, texts=texts, dictionary=dictionary, coherence='c_v')
coherence_values.append(coherencemodel.get_coherence())
return model_list, coherence_values
#为主题一致性得分做准备,里用的主题一致性得分(coherence scores),选择得分最高的主题
dictionary = corpora.Dictionary(cut_word_list)
doc_term_matrix = [dictionary.doc2bow(rev) for rev in cut_word_list]
model_list, coherence_values = compute_coherence_values(dictionary=dictionary, corpus=doc_term_matrix, texts=cut_word_list, start=2, limit=30, step=1)
# 主题一致性得分图形展示
limit=30; start=2; step=1;
x = range(start, limit, step)
plt.plot(x, coherence_values)
plt.xlabel("主题数")
plt.ylabel("主题得分")
plt.legend(("coherence_values"), loc='best')
plt.show()
# 主题分数
for m, cv in zip(x, coherence_values):
print("主题数量 =", m, "Coherence Value(主题一致性得分)", round(cv, 4))
这里遇到一个很奇怪的问题,明明是主题25的时候得分最高,是否选择主题25,首先主题一致性得分(Coherence Value)是一个存在争议的问题,它不是标准做法,只是辅助选择合适的主题数量而已,根据经验选择主题6更加合适
# 挑选得分最高的主题数量
optimal_model = model_list[4]
model_topics = optimal_model.show_topics(formatted=False)
optimal_model.print_topics(num_words=10)
# 可视化展示
pyLDAvis.enable_notebook()
vis = pyLDAvis.gensim_models.prepare(optimal_model, doc_term_matrix, dictionary)
vis
解读一下结果,这里可以看出
主题1(37.5%):主要讲诉客户入住过程(入住渠道、前台、入住时间、入住价格等词)
主题2(26.3%):客户更多讲诉入住感受(早餐、服务员、设施、方便等词)
……
这个由人为定义去定义的,
这里有个反直觉的地方,入住感受占比应该是最高的,为什么入住过程反而占比最高,推测主要由于评论数据都是精选评论,就是表述又长又详细,将自己旅行过程全部分享一遍的那种评论