转载自:http://hi.baidu.com/cesul/item/ae8a3fdca2a36252d73aae73
有些内容有所增改。
一、概述
JGibbLDA是一个java版本的LDA(Latent Dirichlet Allocation)实现,它使用Gibbs采样来进行快速参数估计和推断。
LDA是一种由基于概率模型的聚类算法。该算法能够对训练数据(训练数据是这样一种记录的集合,它的每一条记录都是一组离散的项的集合)中的关键项集之于类簇的概率参数拟合模型,进而利用该参数模型实施聚类或分类等操作。
如果你的数据记录是离散的项,想用概率模型进行拟合或“一对多聚类”,不妨尝试一下LDA。
LDA最早是在文本挖掘主题发现(topic discovery)中作为一种图模型而使用。由 David Blei, Andrew Ng, and Michael Jordan 在2002所提出。
[Blei, David M.; Ng, Andrew Y.; Jordan, Michael I (January2003). Lafferty, John. ed. "Latent Dirichlet allocation". Journal ofMachine Learning Research 3 (4–5): pp. 993–1022.doi:10.1162/jmlr.2003.3.4-5.993.]
本文假设你是一个了解LDA,并且打算把它用起来,并且像我一样暂时不打算用Mahout那个以MapReduce进行分布式实现的LDA算法(其实处理大数据量,还是试试Mahout的LDA吧),只是做原型实现的人。本文只说怎么把JGibbLDA在程序里跑起来,以及性能调优,不深入LDA原理。原理将在后续介绍。
二、Code
Code和更多信息请参考JGibbLDA的主页:http://jgibblda.sourceforge.net/#Griffiths04
我对JGibbLDA做了些许修改,包括:1,取消包依赖(原来是一个解析命令行的一个包),取消命令行执行。因为更多情况下不是执行完这一个程序就没事了。2,源代码对概率算到了小数点后N位然后保存,考虑文件规模(30万实验记录),概率保留小数点后3位,大大减小文件体积。3,数据结构上以及其他一些小的改进。4,我相信你一定会针对你的应用场景做修改的。
我的JGibbLDA修改版本可以点击这里进入网盘下载。【链接2013年04月28日已更新,百度网盘】
三、意义
JGibbLDA对于下列研究和应用领域都是比较有用的工具:
1,文本数据的潜语义分析、情感分析、主题聚类
2,文档聚类,文本摘要
3,协同过滤(用户聚类)
4,Content-basedImage Clustering, Object Recognition, and other applications of Computer Visionin general.
四、JGibbLDA的参数说明和设置
//Specify whether we want to estimate modelfrom scratch
boolean est= false; /////是否开始训练模型
//Specify whether we want to continue thelast estimation
决定是否是基于先前已有的模型基础上继续用新数据训练模型
boolean estc= false;
//Specify whether we want to do inference
boolean inf= true; /////是否使用先前已经训练好的模型进行推断
String dir= ""; //Specify directory ////数据结果(模型数据)保存位置
String dfile= ""; //Specify resource data filename /////训练数据或原始数据文件名
//Specify the model level to which you wantto applied. ///
String modelName= ""; ////选择使用哪一个迭代的模型结果来进行推断
int K= 100; //Specify the number of topics /////类簇数目,谨慎设置
double alpha= 0.2; //Specify alpha //////平滑系数
double beta= 0.1; //Specify beta
int niters= 1000; //Specify the number of iterations /////迭代数目,谨慎设置
//Specify the number of steps to save themodel since the last save.
//The step (counted by the number ofGibbssampling iterations)
//at which the LDA model is saved to harddisk.
//指定把迭代结果模型保存到硬盘上的迭代跨度,即每迭代10次保存一次。
int savestep= 100;
//Specify the number of most likely wordsto be printed for each topic
int twords= 100; /////对每一个类别(话题)选前多少个最大概率词项
//Specify whether we include raw data in theinput
public boolean withrawdata= false;
//Specify thewordmapfile
publicString wordMapFileName= "wordmap.txt"; /////生成的副产品的文件名
五、输入数据格式
数据输入格式统一如下所述:
[M]
[document1]
[document2]
...
[documentM]
其中:
第一行为该数据文件有多少条记录数。然后每一行记录按行排列。
这里的“记录”的格式又规定为:
[documenti]= [wordi1] [wordi2] ... [wordiNi]
其中:[wordiNi]为[documenti]的各个词项,以空格分隔。
众所周知,对词项集合进行预处理,如去除停用词、主干提取等,对结果精度的提升有较大帮助。在基于所属宝贝属性序列的用户聚类中,预处理这一步可以省略。因为提取属性序列的主干是一件较为困难的事。
六、输出数据
建立模型阶段,会输出5类以如下规则命名的文件类型:
model-XXXXX.others:
model-XXXXX.phi
model-XXXXX.theta
model-XXXXX.tassign
model-XXXXX.twords
XXXXX都以数字组成。最后一次迭代所保存的这些数字将会换成“final”。
其中:
这5个文件包括副产品wordmap.txt在有些应用场景下有时并不是完全需要的,是否生成可视情况而定。如果利用主题下topN词项来做基于距离的聚类,可能只需.twords即可。
七、推断新数据和关键代码
将产生如下文件,其组织和意义如前所述一致:
newdocs.dat.others
newdocs.dat.phi
newdocs.dat.tassign
newdocs.dat.theta
newdocs.dat.twords
关键代码:初始化一个模型:
LDACmdOptionldaOption = new LDACmdOption();
ldaOption.inf =true;
ldaOption.dir ="C:\\LDAModelDir";
ldaOption.modelName= "newdocs";
ldaOption.niters =100;
推断新数据:
Inferencerinferencer = new Inferencer();
inferencer.init(option);
ldaOption.dfile= "input-lda-data.txt";
Model newModel =inferencer.inference();
数据也可以是词项的一组数组:
String[] test = {"politics bill clinton", "lawcourt", "football match"};
Model newModel =inferencer.inference(test);
=============================================================
关于代码的一点补充[2012年05月01日]:
去掉LDACmdOption,是因为嵌入自己的代码不需要命令行的。参数设置全在Option里。其中,
设置:
option.dir = "D:\\.......\\model";
option.dfile = "doc.dat";
把数据文件doc.dat放在dir里。结果也写在里边。
[document] :每一行就是一个文档,不需要文档名。结果跟训练数据集顺序一致。一旦模型生成,可以来一个文档做一个lda分类:
Option option = new Option();
option.dir = "D:\\.......\\model"; option.est = false;
option.estc = false; option.inf = true; option.modelName = "model-final";
Inferencer inferencer = new Inferencer(); inferencer.init(option);
while(line){ String [] newData = new String[1]; newData[0] = line; Model newModel = inferencer.inference(newData);
for (int j = 0; j < newModel.theta[0].length; j++) { sysout(newModel.theta[0][j]); }
}
这里,看的是θ(theta),doc-topic关系。同样也可以看φ(phi),word-topic关系。都用文件保存,具体怎么用就看你用什么数据结构(比如HashMap)来存了。