![a36228a85ddb2b55869672cb304844d9.png](https://i-blog.csdnimg.cn/blog_migrate/d0d93eba94c91293173e6e9dcf9cd8b2.jpeg)
LDA(Latent Dirichlet Allocation)是由Blei等人在2003年提出来的。LDA是在pLSI的基础上增加了贝叶斯框架,是pLSI变成了贝叶斯主题模型的LDA。
概率模型求参数,当然需要进行参数估计,LDA参数估计的方法有:
- 变分贝叶斯推断(VB);
- 期望传播(EP);
- Collapsed Gibbs Sampling;
- Collapsed Variational Bayesian(CVB),结合了Collapsed Gibbs Sampling和Variational Inference两种方法;
这几种方法无论哪种方法,我们所有处理的任务都是相同的,即根据给定的最优化目标函数,得到对参数的估计。
GibbsLDA ++是使用Gibbs采样技术进行参数估计和推理的Latent Dirichlet Allocation(LDA)的C / C ++实现。这里就不过多介绍理,本文主要是使用GIbbsLDA++,后期整理好笔记会写一篇关于LDA理论的文章。
需要注意的我使用的是Linux系统,因为这样使用起来比较简单。
1.准备GibbsLDA++工具
https://sourceforge.net/projects/gibbslda/sourceforge.net![595db550a907bebb2dd8f4688f1c0a02.png](https://i-blog.csdnimg.cn/blog_migrate/74e31f6f7b1309ab492fdf042c200804.png)
下载得到下面的压缩包:
![9d46876483c015de54b7ab32b025c4f5.png](https://i-blog.csdnimg.cn/blog_migrate/e6208b2e4a42b2eab477dd4f41d9957a.png)
接下来就是要使用命令对压缩包进行解压:
- cd ~ (进入用户的家目录)
- mkdir LDA (在家目录中创建一个LDA文件)
- cd ~/LDA (进入刚刚创建的LDA文件中)
- gunzip ~/Downloads/GibbsLDA++-0.2.tar.gz (因为下载后文件在~/Downloads中)
- tar -xf ~/Downloads/GibbsLDA++-0.2.tar
- ll (可以在LDA文件中查看到GibbsLDA++-0.2文件夹)
![71151d33cf34cb8ecae9628a4228e712.png](https://i-blog.csdnimg.cn/blog_migrate/0ab104d4228d74639dc2235f4f67d377.jpeg)
因为是使用C/C++编写的程序,所以需要进行编译:
- cd ~/LDA/GibbsLDA++-0.2/ (进入GibbsLDA++的目录中)
- make clean (删除旧的object)
- make (编译)
在make的时候,会重新生成objects, 也就说新的object覆盖旧的objects,make clean 是删除旧的objects。所以应该是make已经含有了make clean的功能。但是实际用的时候,比如多次编译调试运行, 有时候必须make clean一下,直接make,上次留下来的错误似乎不能清干净。
之后可能会报两种错误:
![237901a674bb520d20ea1df039653b59.png](https://i-blog.csdnimg.cn/blog_migrate/7b619069478e9bc4f0d68cd5e724f8f2.png)
![a391d2844ea581d9cf9e39683b0f74c9.png](https://i-blog.csdnimg.cn/blog_migrate/0d77cfa0af3026d2abc8d1799d07cbfb.png)
- utils.cpp 找不到 'atof'函数,补上 #include <cstdlib>
- lda.cpp 找不到 'printf' 函数,补上 #include <cstdio>
下面就是解决这两个错误的详细步骤:
- cd ~/LDA/GibbsLDA++-0.2/ (进入GibbsLDA++的目录中)
- vim src/utils.cpp (使用vim编辑文件)
- vim src/lda.cpp (使用vim编辑文件)
![319005c4bf73172d060a8e9dedb891ae.png](https://i-blog.csdnimg.cn/blog_migrate/430d109f930944b62d1d9e0f0eb13566.jpeg)
![d04102c7bbaf3f833163b4ac9e7b6a02.png](https://i-blog.csdnimg.cn/blog_migrate/556a34c216559b83446935d360bdd523.jpeg)
修改完了错误,再次执行下面两行命令:
- make clean
- make
前面的准备工作就完成了。
2.准备数据集
关于使用的语料这里有几点需要注意的:
- 文件的格式必须是dat。如果原始文件是.txt文件,你可以直接把.txt的后缀名换成.dat即可;
- 文件的第一行必须是总共的文章篇数;
- 对于文本内容:
- 英文:去掉一些停用词以及"for a of the and to in"这样无意义的词;
- 中文:进行分词,以及停用词;
- 文章格式是ANSI,文章中不能有空行;
我这里使用的是完成分词但是没有去掉停用词的2043篇不同主题的新闻文本(也就是2043行):
![a4a7a840edd65469efc19f729b8e7e62.png](https://i-blog.csdnimg.cn/blog_migrate/437e75cb60f565f841dd8c96d245a0a4.jpeg)
3.执行命令运行程序
3.1 训练
lda -est [-alpha <double>] [-beta <double>] [-ntopics <int>] [-niters <int>]
[-savestep <int>] [-twords <int>] -dfile <string>
其中([]中的参数是可选的):
- -est:从头开始估算LDA模型;
- -alpha <double>:alpha的值,LDA的超参数。alpha的默认值为50 / K(K是主题数),文档~主题的先验分布参数,也就是说在LDA中文档~主题分布不再像pLSI中的唯一确定的,而是一个随机变量,随机变量服从的就是参数为alpha的Dirichlet先验分布;
- -beta <double>:β的值,也是LDA的超参数。其默认值为0.1,主题~词项的先验分布参数,也就是说在LDA中主题~词项分布不再像pLSI中的唯一确定的,而是一个随机变量,随机变量服从的就是参数为β的Dirichlet先验分布;
- -ntopics <int>:主题数量。其默认值为100.这取决于输入数据集;
- -niters <int>:Gibbs采样迭代次数。默认值为2000;
- -savestep <int>:将LDA模型保存到硬盘的步骤(由Gibbs采样迭代次数计算)。默认值为200;
- -twords <int>:每个主题最可能的单词数。默认值为零。如果您将此参数设置为大于零的值(例如20),则每次将模型保存到硬盘时,GibbsLDA ++将根据上面的参数savedtep打印出每个主题最多20个最可能单词的列表。
- -dfile <string>:输入训练数据文件;
训练程序只需要执行下面的命令:
- cd ~/LDA/GibbsLDA++-0.2/ (进入GibbsLDA++的目录)
- src/lda -est -alpha 0.5 -beta 0.1 -ntopics 100 -niters 1000 -savestep 100 -twords 20 -dfile ~/Desktop/news.dat (因为我的数据文件在桌面上,并且名称为news.dat)
上面命令的含义就是我们执行LDA程序是以参数为alpha = 0.5的先验Dirichlet分布选择文档~主题分布,以参数β = 0.1的先验Dirichlet分布选择主题~词项分布,选择100个主题数,然后迭代1000次,每100次输出结果,结果中的主题和词项分布中每一个主题下概率值最大的前20个词项,训练的数据地址~/Desktop/news.dat。
![4b9991a7b4c0ce040815e49694059ecc.png](https://i-blog.csdnimg.cn/blog_migrate/3f4315a78223505ac0b52eb72b3f0b3c.jpeg)
然后会发现生成了很多文件,因为前面每迭代100次输出保存一次模型:
![c6ab0658925de9f0d8aa2614e36660e6.png](https://i-blog.csdnimg.cn/blog_migrate/c2d252f10240777fee6a7b1e2dd22cd2.jpeg)
从结果上来看我们最后也保存了最终的模型(model-final),从上面的一堆文件中可以找到最终模型文件:
![0aa28ab71b4c903ed69b17d4c6a746aa.png](https://i-blog.csdnimg.cn/blog_migrate/bb08d71c390944afe0fd0c5c9aab29db.jpeg)
既然得到的最终的模型,那现在来看一个这6(还有一个整个过程只有一个的wordmap.txt)文件都表示什么吧:
- wordmap.txt:是word与id的映射关系表(一共64374个词项)
![88d24eb25e724552c63ce869182351b7.png](https://i-blog.csdnimg.cn/blog_migrate/dade97cdee0e003536a69574852ceab7.jpeg)
- model-final.theta:每篇文档的主题分布(2043 x 100矩阵),2043篇文章,100个主题
![ea9a7076b851a8041112027029078729.png](https://i-blog.csdnimg.cn/blog_migrate/605f0ba90fb09d3e014b7376078da936.jpeg)
- model-final.phi:每个主题的词项概率分布,一个主题数×词数量的矩阵(我的数据是100×),数据还是挺大的,特征稀疏,每一篇文档的词项数量稀少,所以会有下面的这种状况
![e6b456d2ca55d3edb77b61d9bd92f222.png](https://i-blog.csdnimg.cn/blog_migrate/87f691959979fd75c12011968fa5cc18.png)
- model-final.tassign:每篇文章中不同的词语对应的不同的topic的分类,所以共有2043行
![dcccd57de7e3d0b4a49e73d927d5c13f.png](https://i-blog.csdnimg.cn/blog_migrate/256170972a08340a71e84abcde8ee97b.jpeg)
- model-final.twords:这个文件表示了每个主题和主题下对应的词,以及词的概率:
![13869c0dcd3e82b8de798ec7506a8157.png](https://i-blog.csdnimg.cn/blog_migrate/fde9938381b1d0d898228c8ddbde2bf9.jpeg)
- model-final.others :指的是训练的时候所使用的参数,下面和我们前面的命令中指定的参数一致:
![a8f6df20974e92b1b3f1374b3eab7182.png](https://i-blog.csdnimg.cn/blog_migrate/b6637514c9cb6435ac1e767f5b665cce.jpeg)
3.2 测试
前面介绍了使用-est从头重新训练模型的命令,当然还有两个训练模型的命令:
- -estc就是在原有模型的基础上,再次训练模型;
- -inf就是用已经训练好的模型进行文档的主题分布的推断;
使用-estc命令其实和-est的使用差不多,下面主要介绍一下使用-inf命令使用已经训练好的模型推断新的文章,当然在第一行写上文章的数量以及文件的后缀名为.dat都是不能少的:
1
参考消息 网 报道 洛杉矶 冠 有 冷酷 沉睡 者 GrimSleeper 之 称 的 连环 杀人 事件 在 拖延 超过 年后 嫌犯 终于 在 定罪 曾 在 洛杉矶 警局 停车场 做 过 清洁工 今 已 的 LonnieDavidFranklinJr 在 年前 涉嫌 犯下 起 谋杀 和 起性 侵 被 陪审团 判 有罪 台湾 中 时 电子报 援引 洛杉矶 时报 的 报道 称 当 宣判 罪行 时 嫌犯 面 无表情 令人发指 但 受害者 家人 对于 结果 表示 高兴 他们 说 我们 逮到 他 了 虽然 花 了 长时间 但 感谢 老天爷 的 帮忙 此 案件 拖延 已 久 警方 一直 无法 查出 这个 当时 恶名昭彰 的 冷酷 沉睡 者 甚至 数度 抓 错 人 但 因 嫌犯 儿子 年前 曾 因 案 入狱 让 警方 有 了 意外 的 收获 据 了解 警方 因 在 采集 嫌犯 儿子 DNA 时 意外 发现 他 与 嫌犯 有 血缘关系 最终 因为 这 DNA 证据 得以 将 嫌犯 逮捕 归案 据 了解 嫌犯 被 指控 在 至 期间 曾多次 谋杀 经济 困顿 的 至 的 黑人 女子 被害人 先 遭到 性 侵 之后 在 胸口 中 枪 死亡 再 被装 进 垃圾袋 中 另外 警方 表示 嫌犯 还 在 家中 收藏 了 疑似 为 受害者 的 照片 推断 是 性 侵 后 留给 自己 的 纪念品 此案 经过 的 审理 后 陪审团 在 判决 出炉 以 项 谋杀罪 和 项 谋杀 未遂 罪名 起诉 他 稿件 来源 参考消息 网
下面看一看命令以及命令的各个参数:
src/lda -inf -dir <string> -model <string> [-niters <int>]
[-twords <int>] -dfile <string>
其中([]中的参数是可选的):
- -inf:使用先前估计的LDA模型推断先前未见过的(新)数据;
- -dir <string>:该目录包含先前估计的模型;
- -model <string>:先前估计的模型的名称;
- -niters <int>:用于推理的吉布斯采样迭代次数。默认值为20;
- -twords <int>:新数据的每个主题最可能的单词数。默认值为零。如果将此参数设置为大于零的值(例如20),GibbsLDA ++将在推断后打印出每个主题最可能出现的前20个单词列表;
- -dfile <string>:包含新数据的文件;
执行下面的命令,直到迭代完成:
- src/lda -inf -dir ~/Desktop/ -model model-final -niters 100 -twords 20 -dfile test_new.txt
这里有几点需要注意的:
- -dir是一个目录,也就是包含产生的模型的目录;
- -model是先前估计的模型,会发现产生了很多的文件,到底哪个能作为产生模型的名称呢?比如迭代第400次时候产生很多model-00400.[ theta | phi | tassign | twords | others],前面的model-00400就是我们模型的名称,本次实验,我使用的是最后产生的模型,那么模型名称也就是model-final,当然这里我们可以使用任意被我们保存的时刻,比如说使用迭代200次的模型,那么相对应的模型名称就是model-00200;
- -dfile是要测试的文件,格式和训练的文件格式相同(.dat后缀,第一行为文章数),注意这里只需要写上文件名称即可(也就是测试文件和模型都需要放在一个目录中,也就是-dir后面的目录下);
![1040385e1bd2a00a7721e0c6a991376b.png](https://i-blog.csdnimg.cn/blog_migrate/605240ab96ad38e358fde6258be86568.jpeg)
![c40755377ccfc195243a3d074e1ff9e5.png](https://i-blog.csdnimg.cn/blog_migrate/269092b2013b9ff30f8e4f6f0e8a90b7.jpeg)
测试产生的每个文件和训练的时候产生的文件含义一样,这里就不在赘述。