最近新聞個(gè)性化推薦項(xiàng)目中用到 LDA 來確定各個(gè)新聞的主題分布圃酵,我優(yōu)先使用了 Spark Mllib LDA柳畔,發(fā)現(xiàn)并不理想,主要表現(xiàn)在極吃內(nèi)存且計(jì)算慢辜昵,所以打算暫時(shí)放棄之荸镊。優(yōu)先使用 Spark LDA 的主要原因是希望和能和 Spark Streaming 結(jié)合在一起進(jìn)行實(shí)時(shí)預(yù)測(cè)。所以在考察新方案時(shí)優(yōu)先考慮 Java 實(shí)現(xiàn)的 LDA 開源版本堪置,之后發(fā)現(xiàn)了 JGibbLDA躬存,下面從使用角度進(jìn)行簡單介紹
JGibbLDA 是一個(gè)由 Java 語言實(shí)現(xiàn)的 LDA 庫,使用吉布斯采樣進(jìn)行參數(shù)估計(jì)和推斷
在命令行中訓(xùn)練 JGibbLDA 模型
本節(jié)舀锨,將介紹如何使用該工具岭洲。假設(shè)當(dāng)前工作目錄是在 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>
各參數(shù)含義:
-
-est
:從頭開始推斷 LDA 模型 -
-alpha <double>
:alpha 的值坎匿,LDA 的超參數(shù)盾剩。默認(rèn)值為50/K
(K 是 topics 個(gè)數(shù)) -
-beta <double>
:beta 的值雷激,同樣是 LDA 的超參數(shù)。默認(rèn)值為 0.1 -
-ntopics <int>
:topics 個(gè)數(shù)告私。默認(rèn)值為100屎暇,需要根據(jù)輸入數(shù)據(jù)集來定 -
-niters <int>
:吉布斯采樣迭代次數(shù)。默認(rèn)值為 2000 -
-savestep <int>
:LDA 模型在哪一步(以吉布斯采樣迭代為單位)保存到磁盤驻粟。默認(rèn)值為200 -
-twords <int>
:每個(gè) topic 最匹配的詞個(gè)數(shù)根悼。默認(rèn)值為0。如果將該值設(shè)為大于0蜀撑,比如 20挤巡,JGibbLDA 將在每次將模型保存到磁盤的時(shí)候都會(huì)打印出每個(gè) topic 最匹配的 20 個(gè)詞 -
-dir <string>
:訓(xùn)練數(shù)據(jù)文件所在目錄 -
-dfile <string>
:訓(xùn)練數(shù)據(jù)文件名
數(shù)據(jù)格式
訓(xùn)練數(shù)據(jù)和待預(yù)測(cè)數(shù)據(jù)具有相同的格式,如下:
[M]
[document1]
[document2]
...
[documentM]
第一行 [M]
是指總文檔數(shù)酷麦,在此之后的每一行都是一個(gè)文檔矿卑。[documenti]
是數(shù)據(jù)集第 i 個(gè)文檔且由 Ni
個(gè)詞組成:
[documenti] = [word-i1] [word-i2] ... [wordi-Ni]
所有的 [Word-ij](i=1..M, j=1..Ni)
都是詞并由空格隔開(這里不要求每行的詞個(gè)數(shù)一致,根據(jù)對(duì)應(yīng)文檔的正式情況填寫即可)
注意:這里的每行的詞都應(yīng)該是提取出來的(比如利用分詞庫提任秩摹)
輸出
使用 JGibbLDA 進(jìn)行吉布斯采樣 LDA 推薦會(huì)輸出以下五個(gè)文件:
<model_name>.others
<model_name>.phi
<model_name>.theta
<model_name>.tassign
<model_name>.twords
其中:
-
<model_name>
:LDA 模型的名字母廷,對(duì)應(yīng)于模型被保存在硬盤上的時(shí)間步驟。舉例來說绍坝,在吉布斯采樣第 400 次迭代的時(shí)候保存到磁盤的模型的名字為model-00400
徘意,第 1200 次采樣的名字為model-01200
,最后一次迭代對(duì)應(yīng)的模型名字為model-final
-
<model_name>.others
:該文件訓(xùn)練 LDA 模型的各個(gè)參數(shù)轩褐,比如:
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
:該文件包含 “詞-主題” 分布,每行是一個(gè) topic玖详,每列是詞匯表中的一個(gè)詞 -
<model_name>.theta
:該文件包含 “主題-文檔” 分布把介,每行是一個(gè)文檔,每列是一個(gè)主題 -
<model_name>.tassign
:該文件包含訓(xùn)練數(shù)據(jù)中的詞對(duì)應(yīng)的主題蟋座,每行代表一個(gè)文檔拗踢,由一組<word-ij>:<word-ij的 topic>
組成 -
<model_file>.twords
:包含每個(gè) topic 最匹配的詞,詞個(gè)數(shù)在命令行參數(shù)中指定
JGibbLDA 還保存一個(gè)叫做 wordmap.txt向臀,該文件保存了詞及其對(duì)應(yīng)的 id(整形)
案例
舉例巢墅,我們希望以 models/casestudy/newdocs.dat
為訓(xùn)練數(shù)據(jù)推斷出一個(gè) LDA 模型,然后用該模型推斷存儲(chǔ)在 models/casestudy/newdocs.dat
中的文檔的主題分布
設(shè)置主題數(shù)為100券膀,alpha = 0.5 且 beta = 0.1君纫,迭代 1000 次,每迭代 100 次保存一次模型至磁盤芹彬,每次保存模型時(shí)打印出與各個(gè) topic 最相關(guān)的 20 個(gè)詞蓄髓。假設(shè)我們現(xiàn)在處于 JGibbLDA 的根目錄,那么我們將執(zhí)行以下命令:
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
訓(xùn)練完之后舒帮,在目錄 models/casestudy
会喝,我們可以看到上文中描述的 5 個(gè)輸出文件
現(xiàn)在陡叠,我們需要在上一步 1000 次迭代之后再執(zhí)行 800 次迭代,并設(shè)置每 100 次迭代保存一次模型肢执,每次保存模型時(shí)打印出各個(gè) topic 最相關(guān)的 30 個(gè)詞枉阵,那么我們將執(zhí)行下面的命令行:
java -mx512M -cp bin:lib/args4j-2.0.6.jar -estc -dir models/casestudy/ -model model-01000 -niters 800 -savestep 100 -twords 30
接下來,我們需要使用上一步訓(xùn)練出的模型對(duì) newdocs.dat
(該文件存儲(chǔ)在模型相同目錄) 中的文檔進(jìn)行主題分布預(yù)測(cè)预茄,我們可以使用這樣的命令:
java -mx512M -cp bin:lib/args4j-2.0.6.jar -inf -dir models/casestudy/ -model model-01800 -niters 30 -twords 20 -dfile newdocs.dat
編碼預(yù)測(cè)文檔主題分布
初始化推斷器
為了在一個(gè)未知的數(shù)據(jù)集上推斷出一個(gè) LDA 主題模型岭妖,我們首先需要一個(gè)推斷器。由于加載一個(gè)模型的耗時(shí)較長反璃,我們通常初始化一個(gè)推斷器并在多次推斷中使用昵慌。首先,我們需要?jiǎng)?chuàng)建一個(gè) LDACmdOption
實(shí)例淮蜈,并類似下面這樣進(jìn)行初始化:
LDACmdOption ldaOption = new LDACmdOption();
ldaOption.inf = true;
ldaOption.dir = "C:\\LDAModelDir";
ldaOption.modelName = "newdocs";
ldaOption.niters = 100;
其中斋攀,LDACmdOption
的 dir
成員是包含模型(比如:通過命令行訓(xùn)練而來)的目錄;成員 modelName
是模型名梧田;niters
表示在第幾次迭代保存的模型淳蔼。接下來,我們使用 ldaOption
來初始化推斷器:
Inferencer inferencer = new Inferencer();
inferencer.init(option);
預(yù)測(cè)未知數(shù)據(jù)
- 預(yù)測(cè)文件中的數(shù)據(jù)
ldaOption.dfile = "input-lda-data.txt";
Model newModel = inferencer.inference();
其中裁眯,dfile
對(duì)應(yīng)的文件格式與訓(xùn)練數(shù)據(jù)一致
- 預(yù)測(cè)一個(gè)字符串?dāng)?shù)組
String [] test = {"politics bill clinton", "law court", "football match"};
Model newModel = inferencer.inference(test);