LDA由PLSA发展而来,PLSA由LSA发展而来,同样用于隐含语义分析,这里先给出两篇实现LSA和PLSA的文章链接。
自然语言处理之LSA
自然语言处理之PLSA
我们知道,PLSA也定义了一个概率图模型,假设了数据的生成过程,但是不是一个完全的生成过程:没有给出先验。因此PLSA给出的是一个最大似然估计(ML)或者最大后验估计(MAP)。
LDA拓展了PLSA,定义了先验,因此LDA给出的是一个完整的贝叶斯估计。
符号
这里先给出本文公式中以及python代码中使用到的符号及其含义。关于编号,公式中从1开始编号,代码中从0开始编号,只是为了方便。
公式中的符号 | 描述 | 代码中的符号 | 描述 |
---|---|---|---|
N | 文档总数 | N | |
Ni | 第i篇文档单词数 | ||
K | topic总数 | K | |
M | 词表长度 | M | |
d | 文档编号,是一个整数 | d | |
z | topic编号,是一个整数 | z | |
w | 单词编号,是一个整数 | w | |
→α | document-topic分布的超参数,是一个K维向量 | alpha | 是一个标量,→α的每一维都是alpha |
→β | topic-word分布的超参数,是一个M维向量 | beta | 是一个标量,→β的每一维都是beta |
→θi | p(z|d=i)组成的K维向量,其中z∈[1,K] | ||
Θ | Θ={→θi}Ni=1 | ||
→φk | p(w|z=k)组成的M维向量,其中w∈[1,M] | ||
Φ | Φ={→φk}Kk=1 | ||
zi,j | 第i篇文档的第j个单词的topic编号 | Z[i,j] | Z是一个元素为list的list |
wi,j | 第i篇文档的第j个单词在词表中的编号 | docs[i,j] | docs是一个元素为list的list |
l | 二维下标(i,j),对应第i篇文档的第j个单词 | ||
⌝l | 下标包含这一项表示将第i篇文档的第j个单词排除在外 | ||
niz | 第i篇文档中由z这个topic产生的单词计数 | ndz[i,z] | ndz是一个二维矩阵,ndz[i,z]等于niz加上伪计数alpha |
ni | 第i篇文档由每个topic产生的单词计数组成的向量 | ||
nzw | 第z个topic产生单词w的计数 | nzw[z,w] | nzw是一个二维矩阵,nzw[z,w]等于nzw加上伪计数beta |
nz | 第z个topic产生全部单词的计数 | nz[z] | nz是一个一维矩阵,nz[z]等于nz加上M倍的beta |
概率图模型
LDA的概率图模型见下图。箭头定义了随机变量间的关系。每个方框定义了每个过程,方框右下角的变量是该过程的重复次数。
生成过程
LDA认为数据的生成过程如下图。
由该生成过程以及dirichlet-multinomial共轭可得:
p(→z|→α)=N∏i=1Δ(→ni+→α)Δ(→α)
p(→w|→z,→β)=K∏z=1Δ(→nz+→β)Δ(→β)
p(→w,→z|→α,→β)=p(→w|→z,→β)p(→z|→α)=K∏z=1Δ(→nz+→β)Δ(→β)N∏i=1Δ(→ni+→α)Δ(→α)
从而得到了联合概率分布 p(→w,→z)。
似然性
根据上面的概率图模型,可以得出第i篇文档的complete-data似然性为:
p(→wi,→zi,→θi,Φ|→α,→β)=Ni∏j=1p(wi,j|→φzi,j)p(zi,j|→θi)⋅p(→θi|→α)⋅p(Φ|→β)
第i篇文档第j个单词在词表中编号为w的概率为:
p(wi,j=w|→θi,Φ)=K∑k=1p(wi,j=w|→φk)p(zi,j=k|→θi)
整个数据集的似然性为:
p(D|Θ,Φ)=N∏i=1p(→wi|→θi,Φ)=N∏i=1Ni∏j=1p(wi,j|→θi,Φ)
那么接下来怎么办呢?我们回忆一下在PLSA中是怎么做的。
PLSA中的概率图模型由于没有先验,模型比LDA简单一些,认为文档决定topic,topic决定单词,写出了整个数据集的对数似然性,然后由于要求解的参数以求和的形式出现在了对数函数中,无法通过直接求导使用梯度下降或牛顿法来使得这个对数似然最大,因此使用了EM算法。
LDA同样可以使用EM算法求解参数,但需要在E步计算隐变量的后验概率时使用变分推断进行近似,一种更简单的方法是使用gibbs sampling。
gibbs sampling
根据生成过程已经得到了联合概率分布 p(→w,→z)。由于每个文档中的单词 →w 是可以观测到的已知数据,我们需要采样的分布是 p(→z|→w)。
下面推导gibbs sampling采样 p(→z|→w) 分布的公式。
p(zl=z|→z⌝l,→w)=p(→w,→z)p(→w,→z⌝l)=p(→w|→z)p(→z)p(→w⌝l|→z⌝l)p(wl)p(→z⌝l)∝p(→w|→z)p(→z)p(→w⌝l|→z⌝l)p(→z⌝l)=Δ(→ni+→α)Δ(→ni,⌝l+→α)⋅Δ(→nz+→β)Δ(→nz,⌝l+→β)=Γ(niz+αz)Γ(∑Kz=1(niz,⌝l+αz))Γ(niz,⌝l+αz)Γ(∑Kz=1(niz+αz))⋅Γ(nzw+βw)Γ(∑Mw=1(nzw,⌝l+βw))Γ(nzw,⌝l+βw)Γ(∑Mw=1(nzw+βw))=niz,⌝l+αz∑Kz=1(niz,⌝l+αz)⋅nzw,⌝l+βw∑Mw=1(nzw,⌝l+βw)∝nzw,⌝l+βw∑Mw=1(nzw,⌝l+βw)⋅(niz,⌝l+αz)=nzw[z,w]nz[z]⋅(ndz[i,z])
下面解释一下这个推导过程,前两个等号是利用了贝叶斯公式,第三步的正比于符号这一行是去掉了一项常数 p(wl),第四步利用了前面计算好的 p(→w,→z) 联合概率公式,第五、六步是将函数展开并化简,第七步的正比于符号是去掉了一项不依赖于z的项(即z取何值该项都相同),最后一行给出了对应代码中的表达。
这样我们就得到了吉布斯采样公式,每一轮gibbs sampling的迭代中依次遍历每个二维下标 l, 即遍历每篇文档的每一个单词,重新采样这个下标对应的topic编号。
LDA的实现
用python编写了一个使用gibbs sampling实现的LDA。数据集放在文件dataset.txt中,一行表示一篇文档,只需使用原始数据即可,可处理中文和英文。
采用了jieba分词工具,停止词使用英文停止词、中文停止词、标点符号以及所有日文字符。
下面给出代码。
1 | # 预处理(分词,去停用词,为每个word赋予一个编号,文档使用word编号的列表表示) |
实验结果
实验部分,使用两个数据集进行测试,第一个数据集是PLSA实验中使用的第二个关于one piece的16个英文文档,来源于维基百科,其中包含日文字符,因此停止词中加入了日语字符,第二个数据集是5000篇新浪社会新闻,是中文文档。
第一个英文数据集的部分截图如下。
设置的参数为K=10,iterationNum=50。
实验结果如下图。给出了每个主题top10的词语。
第二个中文数据集的部分截图如下。
参数设置为K=10,iterationNum=50:
主题0关于犯罪,主题8关于法院,主题2关于医疗,主题3关于交通事故,主题4关于学校,主题7是一些称谓,主题6关于社区。
参数设置为K=30,iterationNum=50:
可以看到,当topic数设置大一些,得到的主题将变得更为具体一些。由于停止词表的选用问题,有些停止词没有被过滤掉,比如一种,一只等数量词,完善停止词表可以让结果更好。
参考资料
1 Parameter estimation for text analysis by Gregor Heinrich
2 Latent Dirichlet Allocation by David M. Blei et al.
3 LDA数学八卦 by Rickjin
完整代码、停用词以及数据集已托管至 github