使用 JGibbLDA 进行 LDA 模型训练及主题分布预测

最近新闻个性化推荐项目中用到 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 ] [-beta ] [-ntopics ] [-niters ] [-savestep ] [-twords ] –dir  -dfile 

各参数含义:

  • -est:从头开始推断 LDA 模型
  • -alpha :alpha 的值,LDA 的超参数。默认值为 50/K(K 是 topics 个数)
  • -beta :beta 的值,同样是 LDA 的超参数。默认值为 0.1
  • -ntopics :topics 个数。默认值为100,需要根据输入数据集来定
  • -niters :吉布斯采样迭代次数。默认值为 2000
  • -savestep :LDA 模型在哪一步(以吉布斯采样迭代为单位)保存到磁盘。默认值为200
  • -twords :每个 topic 最匹配的词个数。默认值为0。如果将该值设为大于0,比如 20,JGibbLDA 将在每次将模型保存到磁盘的时候都会打印出每个 topic 最匹配的 20 个词
  • -dir :训练数据文件所在目录
  • -dfile :训练数据文件名

数据格式

训练数据和待预测数据具有相同的格式,如下:

[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 推荐会输出以下五个文件:

  • .others
  • .phi
  • .theta
  • .tassign
  • .twords

其中:

  • :LDA 模型的名字,对应于模型被保存在硬盘上的时间步骤。举例来说,在吉布斯采样第 400 次迭代的时候保存到磁盘的模型的名字为 model-00400,第 1200 次采样的名字为 model-01200,最后一次迭代对应的模型名字为 model-final
  • .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
  • .phi:该文件包含 “词-主题” 分布,每行是一个 topic,每列是词汇表中的一个词
  • .theta:该文件包含 “主题-文档” 分布,每行是一个文档,每列是一个主题
  • .tassign:该文件包含训练数据中的词对应的主题,每行代表一个文档,由一组 : 组成
  • .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;

其中,LDACmdOptiondir 成员是包含模型(比如:通过命令行训练而来)的目录;成员 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

你可能感兴趣的:(使用 JGibbLDA 进行 LDA 模型训练及主题分布预测)