最近新闻个性化推荐项目中用到 LDA 来确定各个新闻的主题分布,我优先使用了 Spark Mllib LDA,发现并不理想,主要表现在极吃内存且计算慢,所以打算暂时放弃之。优先使用 Spark LDA 的主要原因是希望和能和 Spark Streaming 结合在一起进行实时预测。所以在考察新方案时优先考虑 Java 实现的 LDA 开源版本,之后发现了 JGibbLDA,下面从使用角度进行简单介绍
JGibbLDA 是一个由 Java 语言实现的 LDA 库,使用吉布斯采样进行参数估计和推断
在命令行中训练 JGibbLDA 模型
本节,将介绍如何使用该工具。假设当前工作目录是在 JGibbLDA 根目录并且我们使用的是 linux,命令行如下:
java [-mx512M] -cp bin:lib/args4j-2.0.6.jar jgibblda.LDA -est [-alpha <double>] [-beta <double>] [-ntopics <int>] [-niters <int>] [-savestep <int>] [-twords <int>] –dir <string> -dfile <string>
各参数含义:
-
-est
:从头开始推断 LDA 模型 -
-alpha <double>
:alpha 的值,LDA 的超参数。默认值为50/K
(K 是 topics 个数) -
-beta <double>
:beta 的值,同样是 LDA 的超参数。默认值为 0.1 -
-ntopics <int>
:topics 个数。默认值为100,需要根据输入数据集来定 -
-niters <int>
:吉布斯采样迭代次数。默认值为 2000 -
-savestep <int>
:LDA 模型在哪一步(以吉布斯采样迭代为单位)保存到磁盘。默认值为200 -
-twords <int>
:每个 topic 最匹配的词个数。默认值为0。如果将该值设为大于0,比如 20,JGibbLDA 将在每次将模型保存到磁盘的时候都会打印出每个 topic 最匹配的 20 个词 -
-dir <string>
:训练数据文件所在目录 -
-dfile <string>
:训练数据文件名
数据格式
训练数据和待预测数据具有相同的格式,如下:
[M]
[document1]
[document2]
...
[documentM]
第一行 [M]
是指总文档数,在此之后的每一行都是一个文档。[documenti]
是数据集第 i 个文档且由 Ni
个词组成:
[documenti] = [word-i1] [word-i2] ... [wordi-Ni]
所有的 [Word-ij](i=1..M, j=1..Ni)
都是词并由空格隔开(这里不要求每行的词个数一致,根据对应文档的正式情况填写即可)
注意:这里的每行的词都应该是提取出来的(比如利用分词库提取)
输出
使用 JGibbLDA 进行吉布斯采样 LDA 推荐会输出以下五个文件:
<model_name>.others
<model_name>.phi
<model_name>.theta
<model_name>.tassign
<model_name>.twords
其中:
-
<model_name>
:LDA 模型的名字,对应于模型被保存在硬盘上的时间步骤。举例来说,在吉布斯采样第 400 次迭代的时候保存到磁盘的模型的名字为model-00400
,第 1200 次采样的名字为model-01200
,最后一次迭代对应的模型名字为model-final
-
<model_name>.others
:该文件训练 LDA 模型的各个参数,比如:
alpha=?
beta=?
ntopics=? # i.e., number of topics
ndocs=? # i.e., number of documents
nwords=? # i.e., the vocabulary size
liter=? # i.e., the Gibbs sampling iteration at which the model was saved
-
<model_name>.phi
:该文件包含 “词-主题” 分布,每行是一个 topic,每列是词汇表中的一个词 -
<model_name>.theta
:该文件包含 “主题-文档” 分布,每行是一个文档,每列是一个主题 -
<model_name>.tassign
:该文件包含训练数据中的词对应的主题,每行代表一个文档,由一组<word-ij>:<word-ij的 topic>
组成 -
<model_file>.twords
:包含每个 topic 最匹配的词,词个数在命令行参数中指定
JGibbLDA 还保存一个叫做 wordmap.txt,该文件保存了词及其对应的 id(整形)
案例
举例,我们希望以 models/casestudy/newdocs.dat
为训练数据推断出一个 LDA 模型,然后用该模型推断存储在 models/casestudy/newdocs.dat
中的文档的主题分布
设置主题数为100,alpha = 0.5 且 beta = 0.1,迭代 1000 次,每迭代 100 次保存一次模型至磁盘,每次保存模型时打印出与各个 topic 最相关的 20 个词。假设我们现在处于 JGibbLDA 的根目录,那么我们将执行以下命令:
java -mx512M -cp bin:lib/args4j-2.0.6.jar jgibblda.LDA -est -alpha 0.5 -beta 0.1 -ntopics 100 -niters 1000 -savestep 100 -twords 20 -dfile models/casestudy/newdocs.dat
训练完之后,在目录 models/casestudy
,我们可以看到上文中描述的 5 个输出文件
现在,我们需要在上一步 1000 次迭代之后再执行 800 次迭代,并设置每 100 次迭代保存一次模型,每次保存模型时打印出各个 topic 最相关的 30 个词,那么我们将执行下面的命令行:
java -mx512M -cp bin:lib/args4j-2.0.6.jar -estc -dir models/casestudy/ -model model-01000 -niters 800 -savestep 100 -twords 30
接下来,我们需要使用上一步训练出的模型对 newdocs.dat
(该文件存储在模型相同目录) 中的文档进行主题分布预测,我们可以使用这样的命令:
java -mx512M -cp bin:lib/args4j-2.0.6.jar -inf -dir models/casestudy/ -model model-01800 -niters 30 -twords 20 -dfile newdocs.dat
编码预测文档主题分布
初始化推断器
为了在一个未知的数据集上推断出一个 LDA 主题模型,我们首先需要一个推断器。由于加载一个模型的耗时较长,我们通常初始化一个推断器并在多次推断中使用。首先,我们需要创建一个 LDACmdOption
实例,并类似下面这样进行初始化:
LDACmdOption ldaOption = new LDACmdOption();
ldaOption.inf = true;
ldaOption.dir = "C:\\LDAModelDir";
ldaOption.modelName = "newdocs";
ldaOption.niters = 100;
其中,LDACmdOption
的 dir
成员是包含模型(比如:通过命令行训练而来)的目录;成员 modelName
是模型名;niters
表示在第几次迭代保存的模型。接下来,我们使用 ldaOption
来初始化推断器:
Inferencer inferencer = new Inferencer();
inferencer.init(option);
预测未知数据
- 预测文件中的数据
ldaOption.dfile = "input-lda-data.txt";
Model newModel = inferencer.inference();
其中,dfile
对应的文件格式与训练数据一致
- 预测一个字符串数组
String [] test = {"politics bill clinton", "law court", "football match"};
Model newModel = inferencer.inference(test);
欢迎关注我的微信公众号:FunnyBigData
FunnyBigData
网友评论