首页 > 代码库 > 利用LDA进行文本聚类(hadoop, mahout)

利用LDA进行文本聚类(hadoop, mahout)

项目原理概述

利用sqoop将数据从MySQL导入到HDFS中,利用mahout的LDA的cvb实现对输入数据进行聚类,并将结果更新到数据库中。数据流向图如下

 

mahout算法分析


输入数据格式
为<IntegerWritable, VectorWritable>的matrix矩阵,key为待聚类文本的数字编号,value为待聚类文本的单词向量Vector, Vector的index为单词在字典中的编号, value为TFIDF值。


算法相关参数详解(不包含hadoop运行参数)
项目中所有参数设置均与mahout-0.9目录下的examples/bin/cluster-reuters.sh的147-172行设置一样,即
$SCOUT cvb -i ${WORK_DIR}/${ROWID_MATRIX_DIR}/matrix -o ${WORK_DIR}/${LDA_DIR} -k 20 -ow -x 20 -dict ${WORK_DIR}/${DICTIONARY_FILES} -dt ${WORK_DIR}/${LDA_TOPICS_DIR} -mt ${WORK_DIR}/${LDA_MODEL_DIR}


input -- 输入数据的hdfs路径,这里是/home/hadoop-user/scout_workspace/scout/dataset/reuters-out-matrix-debug/matrix
dt -- 文档主题输出路径,保存了每个文档的相应topic的概率,这里是/home/hadoop-user/scout_workspace/scout/dataset/reuters-lda-topics
mt -- model的路径,这里是/home/hadoop-user/scout_workspace/scout/dataset/reuters-lda-debug
k -- number of topics to learn,这里设置成20
x -- 模型迭代次数,也就是需要多少次迭代来生成最后的Model,默认值20
seed -- Random seed,生成初始readModel时的种子,默认值System.nanoTime() % 10000
dict -- 字典路径,这里是/home/hadoop-user/scout_workspace/scout/dataset/reuters-out-seqdir-sparse-lda/dictionary.file-*
a -- Smoothing for document/topic distribution, document/topic分布的平滑系数,默认为1.0E-4
e -- Smoothing for topic/term distribution, topic/term分布的平滑系数,默认为1.0E-4
关于a和e,根据https://mahout.apache.org/users/clustering/latent-dirichlet-allocation.html描述,a和e的合适取值为k/50(k为topic数量),但是这个网页还保留着mahout ldatopics的命令介绍,而mahout 0.8,0.9均没有该命令,推测应该是比较陈旧的内容,因此还是根据cluster-reuters.sh中的设置来,也就是采取默认值。
mipd -- 这个参数非常重要,对于每个文档程序是先用RandomSeed来生成一个初始的readModel然后进行mipd次迭代,算出最终的model进行更新,这里选默认值10次


LDA算法程序分析

算法的大致流程如下


1.解析参数与Configuration设置


2.读取Model(第一次运行时没有这个过程)
如果hfds上面已经有部分model,那么程序将读取最后一个model,并以这个model作为初始readModel来继续进行算法迭代,也就是说有类似于断电-重启的机制


3.运行算法迭代(Mapper过程)生成LDA模型
这个过程是最为复杂的阶段,许多地方我也不是很明白,我将尽最大努力进行解释

首先分析Mapper,即CachingCVB0Mapper,顾名思义就是能够缓存的Mapper,表现在其readModel的选取上面,如果目录里面不存在任何model则用RandomSeed初始化一个readModel,否则读取最近的一个model。程序将model划分为readModel和writeModel,这两个都是TopicModel类,并由ModelTrainer来进行调度和管理



CachingCVB0Mapper整个过程如下图所示

 

 

在上面这个整体框架下,mahout程序应用了CVB0 Algorithm来计算LDA模型, 在map过程中通过对向量docTopic和矩阵docTopicModel的反复迭代求解,算出每个document的docTopicModel并且在update writeModel阶段将docTopicModel矩阵进行向量的相加操作,经历完所有的map过程后得到整个corpus的docTopicModel矩阵,最终在cleanup过程中将topic的index作为key,矩阵docTopicModel作为value写入reduce。该过程涉及到的算法如下所示

 

CVB0算法分析图解

 

4.利用生成的LDA模型推导出topic的概率分布

 

算法总结

可以看出算法本质上面就是bayes公式和EM算法的结合
E过程就是首先假定一个均匀分布且归一化的topic概率分布向量docTopics,利用该值通过贝叶斯公式算出单词 - 主题的概率分布矩阵 docTopicModel(见CVB0算法分析图解中的第一步)


M过程就是根据生成的docTopicModel进行CVB0算法分析图解中的2,3,4,5步重新计算得到新的docTopics


然后反复重复 E - M 过程n次,得到收敛后的docTopics和docTopicModel,其中docTopicModel可以用于lda模型的更新,而docTopics就是我们聚类需要的topic概率分布向量


算法后记
几点问题还没有得到解决
1.在mahout中是按照下面的式子计算docTopicModel的
double termTopicLikelihood =
   (topicTermRow.get(termIndex) + eta) * (topicWeight + alpha)/ (topicSum + eta * numTerms);
疑问就是该式子比贝叶斯公式添加了几个平滑系数项,这样写的理论依据在哪里,来源于哪篇著作或者论文,平滑系数eta和alpha分别是代表什么含义,如何选取这两个系数。
2.CVB0算法分析图解中第2步进行归一化的理论依据,即为什么要进行归一化
3.update writeModel过程中对于topicTermCounts的计算
即为什么要在每次map时候对p(topic | term)进行累加,还没有完全想明白

 

项目运行环境

hadoop-1.2.1

sqoop-1.4.4

mahout-0.9

关于环境的安装部署请参考相关文章,这里不多加赘述。上面三个软件在我本机的都是部署在/home/hadoop-user/mahout_workspace/目录下。另外自己写的scout项目部署在/home/hadoop-user/scout_workspace/目录下

 

项目代码

项目代码已经放到Github上https://github.com/ehomeshasha/scout,有兴趣的同学可以下载下来看下,重点查看bin目录下的脚本文件以及driver,export,analyzer等几个包下的java文件

 

整个项目架构分析
该项目的初始数据保存在MySQL中, 算法分析需要map/reduce过程以及hdfs文件系统的参与, 最后将结果更新至MySQL,整个过程如图所示

 

详细流程代码可以用vi /home/hadoop-user/scout_workspace/scout/bin/lda/cluster-dealsaccess-lda.sh查看,并可以用如下的图进行表示






其中数据迁移到hdfs可采用sqoop import命令来完成,实现此过程的sh文件在/home/hadoop-user/scout_workspace/scout/bin/sqooop_mysql_dumper.sh中,可用vi /home/hadoop-user/scout_workspace/scout/bin/sqooop_mysql_dumper.sh进行查看。Apache Sqoop的网址链接为http://sqoop.apache.org/docs/1.4.4/SqoopUserGuide.html#_literal_sqoop_import_literal


最后一步更新MySQL可以查看scout项目源码查看详细过程, 连接jdbc用到了Apache的DbUtils的包。DbUtils的网站链接为http://commons.apache.org/proper/commons-dbutils/


有用的脚本文件
scout/bin/lda/cluster-reuters-lda-debug.sh提取了mahout/examples/bin/cluster-reuters.sh的lda算法部分并进行了步骤拆分,适用于进行算法的调试, scout/bin/lda/cluster-reuters-lda-debug-dumper.sh文件是一个数据dumper脚本文件,可将lda算法产生的数据dump到本地并转换成文本格式

Scout项目架构分析

Scout的目录结构






该scout项目的包依赖为hadoop及其依赖包, mahout-examples-0.9-job.jar, mysql-connector-java-5.1.25.jar, google的gson-2.2.4.jar包
主要职责为将数据文件在MySQL以及HDFS之间进行转移,代码量不多,花少量时间即可看懂。