LDA主题模型

LDA模型简介

LDA指两者算法,一种叫线性判别分析,一种叫文档主题生成模型,在NLP中我们当然指的是后者。

LDA是一种基于统计的生成模型,它可以根据语料库生成主题模型,并根据这个模型来预测一篇文章属于哪些主题。

算法理论

前提假设

不同于传统的词袋模型,LDA模型认为,一篇文章的生成,是首先随机地决定一些主题,再从每个主题中随机地选择一些词语,这些词语构成了一篇文章。LDA并不考虑词语在文章中的顺序。

LDA的模型,实际上由一个个主题组成,每个主题下有不同的词语,每个主题下的词语对应一个概率值,表明在给定该主题时该词出现的条件概率,即p(w|t)。

而文章的主题预测,即根据文章中出现的词语以及各词语出现的次数,来判断这篇文章最符合哪些主题中词语的概率分布,从而判定文章由哪些词语构成。

LDA的主题模型

贝叶斯学派的人认为,万物皆随机。那么,在LDA模型中上文中提到的条件概率的分布也被认为是随机的。这可以说是LDA模型与PLSA模型最大的不同。

所以在LDA中一篇文章的产生,实际上是随机生成了K个词语-主题的概率分布(K表示假设的主题数量),又随机生成了一个主题-文档的概率分布,根据这个主题-文档分布的结果去在K个词语-主题分布中找到符合要求的那个分布,根据这个分布生成了文档中的一个词语,重复此过程最终生成了一篇文档。主题与主题之间相互独立,词语与词语之间也相互独立,所以上文中两个概率分布生成都是多项式分布,即

p(w⃗ )=i=1npαii ,其中

αi 表示第i个值的样本的个数。

这样每生成一个词就要做两次随机过程,由于词与词之间是独立的,那么干脆先进行2N次随机过程,把每个词的主题以及相应的概率分布确定了,再去逐个生成词语。

主题-文档的概率分布与词语-主题的概率分布,显然不会是真的随机,而是某种概率。那生成某个概率分布的概率到底是怎样的呢?Dirichlet分布便是可以表示概率的概率的一种分布,它根据一个人为设定的先验参数生成样本,再根据生成结果来更新自己得到后验概率。关于Dirichlet分布可以见下文,这里仅说明,公式

Δ(n⃗ +α⃗ )Δ(α) 用来表示在根据先验分布

α⃗  得到的概率分布下生成样本分布为

n⃗  的概率,

n⃗ 

(n1,...,nk)

那么,语料库主题生成的概率,便可以表示为

p(z⃗ |α⃗ )=i=1mp(z⃗ m|α⃗ )=i=1mΔ(n⃗ m+α⃗ )Δ(α) ,其中m为语料库中的文本数。同样的,给定主题分布后,语料库中词的生成概率也可以表示为


p(w⃗ |z⃗ ,β⃗ )=i=1kp(w⃗ k|z⃗ k,β⃗ )=i=1kΔ(n⃗ k+α⃗ )Δ(α) ,其中k表示语料库中的主题数量。这里虽然两个公式都用了n来表示分布,但它们并不表示同一个变量的分布。综上,我们可以得到语料库的主题-词语联合概率分布

p(w⃗ ,z⃗ |α⃗ ,β⃗ )=p(w⃗ |z⃗ ,β⃗ )p(z⃗ |α⃗ )

数据采样

(这里的数据采样是LDA算法中最重要的一个步骤,所以单独拎出来进行说明。)
上面的公式只是表现了语料库的生成过程,但现在我们实际上已经有了语料库,我们希望得到的是几个概率分布的值。由于语料库已知的情况下 w⃗  是已知的,故我们真正需要计算的便是 p(z⃗ |w⃗ )

之前也提过,实际上我们可以从语料库来计算主题。我们用 zi 表示语料库中第i个词的主题, i=(m,n) ,表示这个词是第m个文档中第n个词,我们用 z⃗ ¬i 表示语料库中i以外词语文档主题。那么对于我们要求的 p(z⃗ |w⃗ ) 其实就可以转化成 z⃗  中的每一维的条件概率,即 p(z⃗ i|z⃗ ¬i,w⃗ ) 。至于这里为什么在条件中加上 z⃗ ¬i ,想必直观上也多少能感觉是有些关系的,它的作用请看下文中提到的Gibbs Sampling。由于语料库是已知的,所以这里的第i个词的值实际上是可观测的,所以原式等价于
p(zi=k,wi=t|z⃗ ¬i,w⃗ ¬i)

之前也提到了用Dirichlet分布表示概率的概率,那么这里用 θ⃗ m 表示第m篇文档主题分布的概率的概率分布,用 ϕ⃗ k 表示第k个主题词语分布的概率的概率分布,同时注意到去掉语料库中第i个词并不影响分布的性质,即之前的条件概率中的条件变量也是符合Dirichlet分布的,所以

p(θ⃗ m|z⃗ ¬i,w⃗ ¬i)=Dir(θ⃗ m|n⃗ m,¬i+α)


p(ϕ⃗ k|z⃗ ¬i,w⃗ ¬i)=Dir(ϕ⃗ k|n⃗ k,¬i+β)

根据上面两个式子,我们可以如下推导,得到采样计算公式:


p(z⃗ i|z⃗ ¬i,w⃗ )p(zi=k,wi=t|z⃗ ¬i,w⃗ ¬i)=p(zi=k,wi=t,θ⃗ m,ϕ⃗ k|z⃗ ¬i,w⃗ ¬i)dθ⃗ mdϕ⃗ k=p(zi=k,θ⃗ m|z⃗ ¬i,w⃗ ¬i)dθ⃗ mp(wi=t,ϕ⃗ k|z⃗ ¬i,w⃗ ¬i)dϕ⃗ k=p(zi=k|θ⃗ m)p(θ⃗ m|z⃗ ¬i,w⃗ ¬i)dθ⃗ p(wi=t|ϕ⃗ k)p(ϕ⃗ k|z⃗ ¬i,w⃗ ¬i)dϕ⃗ k=E(θmk)E(ϕkt)

根据连续变量概率密度的定义,倒数第二步那两个积分值显然就是随机变量取特定值时的期望,即得到最后一步的结果。这里

θmk 表示第m篇文档中出现主题k这一事件,

ϕkt 表示在主题k中出现词语t这一事件,由于其本身的值是概率,所以其期望值即事件发生的概率,这里我们取除这篇文档外所有出现词语i的文档中主题k的出现概率加上先验

α 作为

θmk 期望,即


E(θmk)=n(k)m,¬i+αk(ki=1n(t)m,¬i)+αk

取除这篇文档外所有词语中被主题k的出现概率加上先验

β 作为期望,即


E(ϕkt)=n(t)k,¬i+βt(vi=1n(t)k,¬i)+βt

所以,我们最终得到,


p(z⃗ i|z⃗ ¬i,w⃗ )n(k)m,¬i+αk(ki=1n(t)m,¬i)+αkn(t)k,¬i+βt(vi=1n(t)k,¬i)+βt

训练与预测

LDA算法说起来分为两个部分,一个部分是根据语料库训练出主题模型,另一部分是根据主题模型预测一篇输入文档的主题。我们分开来进行说明。

训练

训练的最终结果,自然是计算出主题-文档的条件概率分布 θ 与词语-主题的条件概率分布 ϕ

训练的过程很简单,随机初始化语料库中每个词的所属主题,然后循环“数据采样”这一过程。即每次循环中,对每一个词用上面的公式预测它的主题。关于条件变量的取值,在本次循环已计算过的词语则取本次计算中的结果值,尚未计算的词语则取上次循环的结果,对于第一次循环,“上次的结果”自然就是初始化值。

循环到什么时候呢?这里需要再提一下,数据采样中提到的Gibbs Sampling是一个基于马可夫链的采样方法,它最终是收敛的,且收敛值与初始值无关。也就是说,上面的循环经过一段时间后,对词语的预测结果将几乎不再更新,此时循环就可以结束了。实现上,可以设定一个阈值,来判断是否可以停止循环。至于说,为什么这样采样结果就是收敛的,即使在下文也只是一个粗略的介绍,感兴趣可以查找更多的资料。

预测

对于一篇新的文档,预测时,同样要先为其中每个词随机赋予主题。不同的是,这次 ϕ 即词语-主题条件概率分布是根据训练结果得出的,即预测过程中这个值不会变更,变更的只是 θ 即主题-文档条件概率分布。

预测的过程,同样是跟循环进行Gibbs Sampling,直至结果收敛。统计每个词的主题,最终结果即文档的主题分布。

相关数学理论简介

上面的介绍其实已经可以让你大概的了解LDA的原理,下面仅是对上文中提到的一些数学名词进行解释。

Dirichlet分布

讲Dirichlet分布之前,我们需要先介绍一下beta分布。
公式:

f(x)=Γ(α+β)Γ(α)Γ(β)xα1(1x)β1=1B(α,β)xα1(1x)β1

其中,Gamma函数定义如下:

Γ(x+1)=xΓ(x) 显然易得

Γ(n+1)=n!

beta分布表示一个定义在[0,1]上的连续变量的概率密度函数。它是伯努利分布和二项分布的共轭先验分布,共轭即beta分布的先验分布和后验分布都是beta分布。

beta的先验分布即初始给定的 α β 值,这两个值表现了一个先验的随机事件发生的概率是 αα+β 。而开始进行抽样或观测后,根据结果,去更新这个 α β 的值,每出现一个正样本 α 值增1,每出现一个负样本 β 值增1。假如出现了m次正样本,n次负样本,则加入后验分布后该随机变量新的概率分布为

f(x)=1B(α+m,β+n)xα+m1(1x)β+n1

这个概率密度函数可以帮助我们根据事件的发生去更新概率模型。

想要更直观地了解可以查看如何通俗理解beta分布?
至于为什么这个分布有这样的性质,它是怎么推导出来的,有兴趣地可以找相关资料更细致学习,这里仅提供公式特性以及一个感性的认识。

刚才的beta分布仅考虑了一个随机变量的情况,假如有多个随机变量呢?

Dirichlet分布即是beta分布向多维的一个推广,三维时公式如下:

f(x1,x2,x3)=Γ(α1+α2+α3)Γ(α1)Γ(α2)Γ(α3)xα111xα212xα313

其性质与beta分布类似,这里就不再赘述。

Gibbs Sampling

对于普通的一维的概率分布函数,我们可以先用线性同余产生一个符合均匀分布Uniform(0,1)的样本,再通过数学变换,得到符合要求的分布的样本序列。但对于一些分布复杂的随机变量,或者高维的概率分布函数,我们没有办法通过上面的方法得到符合要求的样本,这时怎么办呢?

对于高维的概率分布,它的概率函数很难表示,但一个一维随机变量的条件概率却很容易表示。对于n维的概率分布,我们构造一个n阶的方阵,它刻画了某事物的状态转移,其中(i,j)表示从状态i转移到状态j的概率。我们记分布

πi=[πi(1),πi(2),...,πi(n)] 表示经过i次转移后样本集合中各状态的样本的比例,显然

πk=π0Pk ,其中P表示n阶状态转移矩阵。研究发现,当i足够大时,分布

πi 是收敛的,且这个收敛值与初始分布

π0 无关,仅与状态转移矩阵P有关。也就是说,对于一个n维的概率分布,有一个状态转移矩阵P收敛于这个分布,且有

π(j)=i=0π(i)P(i,j) 。那么我们构造一个状态转移矩阵P,则在k次转移完收敛后,再根据P产生的新样本都是符合分布

π 的。

有了上面的启发,假如我们能根据已知的概率分布p(x)构造一个转移矩阵P使其恰好收敛到p(x),那么就可以生成符合p(x)的样本了。该矩阵的构造依赖于一个细致平稳条件的定理。

细致平稳条件要求,对于一个非周期马氏链的转移矩阵P以及分布 π(x) ,满足 π(i)P(i,j)=π(j)P(j,i)

对于一个转移矩阵Q以及已知的p(x),上面的公式一般而言是不满足的,但我们可以在两侧引入参数 α(i,j) α(j,i) ,使得 p(i)q(i,j)α(i,j)=p(j)q(j,i)α(j,i) 成立。观察对称性,分别令 α(i,j)=p(j)q(j,i) 以及 α(j,i)=p(i)q(i,j) 即可。这样我们就得到了一个新矩阵Q’, Q(i,j)=Q(i,j)α(i,j) ,这个Q’符合细致平稳分布的条件,就是我们要找的转移矩阵。其中的 α(i,j) 可以理解为一个“接受概率”,即样本经过状态转移矩阵得到转移结果后,是否“接受”这个转移。事实上,为了加速算法, α 值可以调整为 min{p(j)q(j,i)p(i)q(j,i),1} ,这样转移的接受概率将更高使得收敛速度更快。这就是传统的MCMC算法。

但是即使放大接受概率,在高维时由于这一概率存在,收敛速度依旧很慢,我们更希望两边的转移的接受概率都是1。重新观察概率公式,注意到

p(x1,y1)p(y2|x1)=p(x1,y2)p(y1|x1) ,即对于二维分布,沿着其中一维座标轴平行线的转移总是满足细致平稳条件的。那么,自然的,我们可以将采样的循环更改为


yt+1p(y|xt)


xt+1p(x|yt+1)

对于更多维的情况,也仅需改成

xt+1(i)p(x(i)|xt+11,...,xt+1(i1),xt(i+1),...,xt(n))

代码实现

实际上你也可以看出,这一算法虽然容易,但原理上很复杂。所以基本上不是很推荐去使用自己实现的代码,除非你的水平确实很高,或者应用场景需要对LDA算法内部进行某些修改。当然,自己实现一次可以锻炼你的算法能力,同时有助于你对算法有更深的理解。我仅仅是说不推荐实际使用自己实现的代码,因为很多库都提供了简洁轻量的API来帮助你使用LDA模型来对主题进行预测。下面是使用gensim.models.LdaModel的一个简单例子

from gensim.corpora import Dictionary
from gensim.models import LdaModel
# 语料库是一个列表的列表,内部每个列表表示一篇文档,内部列表元素是文档词语
corpus = get_corpus()
# 从语料库获取词典,每个词对应一个编号
word_dict = Dictionary(corpus)
# 根据词典,将原来的语料库转换成词袋模型语料库
bow_corpus = [word_dict.bow(doc) for doc in corpus]
# 训练LDA模型,其中num_topics为设定的主题数量
lda_model = LdaModel(bow_corpus, id2word=word_dict, num_topics=100)
# 显示主题下词语概率分布,这里显示10个主题以及每个主题下概率最大的10个词
print(lda_model.show_topcis(num_topics=10, num_words=10))
# 将要预测的文档转换为词袋模型
bow_doc = word_dict.bow(get_doc())
# 预测
print(lda_model[bow_doc])

关于gensim的LdaModel的更多用法,可以前往官方文档查看

总结

LDA在2003年被提出,直到现在,依然是一个不错的主题模型。但一方面,使用Gibbs Sampling的话每一个数据的更新依赖于之前的结果难以并行化,并行化的话只能在迭代优化部分使用更慢的EM或Online;另一方面,对于短文本,LDA的效果往往不是很好。
在大数据时代,随着词向量模型的提出,新的主题聚类方法可能随时会出现。

点赞