Spark GraphX 學習筆記——LDA實戰:路透社電報新聞分類

1. 隱含狄利克雷分佈(Latent Dirichlet allocation,LDA)
	1)LDA 屬於無監督學習,所有的主題並不需要事先指定,是在聚類過程中逐漸形成的 。

	2)MLlib 的 LDA 使用了 GraphX 來提高計算效率,儘管它的輸入和輸出都不是圖。

	3)LDA 是基於隱含變量的,在這裏隱含變量指的是算法自動推斷出來的“主題”。這些主題由一些與之關聯的單詞描述,但並不具有明確的主題名稱 。

	4)一旦主題被推斷出來,每篇文檔在不同主題上會有不 同的分數。這是 LDA 的一個基本原則和假設:每篇文檔同時會在所有不同的主題上有所涉及,而不僅僅是其中一兩個。

2. LDA實戰——路透社電報新聞分類

	1)下載數據:
		在如下網址:
			https://archive.ics.uci.edu/ml/machine-learning-databases/
		下載數據:
			reuters21578.tar.gz

	2)使用命令解壓其中單個文件reut2-000.sgm
		tar -xzvf reuters21578.tar.gz reut2-000.sgm

	3)使用命令對文件數據進行清洗,文件名爲rcorpus
		cat reut2-000.sgm | tr '\n' ' ' | sed -e 's/<\/BODY>/\n/g' | sed -e 's/^.*<BODY>//' | tr -cd '[[:alpha:]] \n' >rcorpus

	4)生成詞袋
		(1)過濾停用詞(stop words)
			停用詞是指過於普遍,而攜帶的信息量有限
			一般使用停用詞詞表,但本次實驗中只是簡單地將一些較短(少於或等於 5 個字母〉的單詞過濾掉,同時也會過濾掉 “ Reuter”這個特殊單詞。

		(2)在函數 bagsFrornDocurnentPerLine()裏,所有內容經過 split()操作後會轉化成傳統的 Scala 集合(而不是 ROD )。因此,後續採用的是 groupBy()這種 Scala 集合上的操作方法,而不是 ROD 上的操作方法 groupByKey()

		(3)實現代碼:

import org.apache.spark.mllib.linalg._
import org.apache.spark.mllib.clustering._
import org.apache.spark.rdd._
def bagsFromDocumentPerLine(filename:String) =
	sc.textFile(filename)
	// 對每一行,按空格分割出每個單詞
	.map(_.split(" ")
		// 過濾操作,過濾掉長度小於等於5和等於reuter的單詞
		.filter(x => x.length > 5 && x.toLowerCase != "reuter")
		// 全部轉化爲小寫
		.map(_.toLowerCase)
		// 根據單詞進行分組
		.groupBy(x => x)
		.toList
		// 轉化得到一個(單詞,出現次數)的集合
		.map(x => (x._1, x._2.size)))

// 將文件rcorpus的路徑傳入
val rddBags:RDD[List[Tuple2[String,Int]]] =
	bagsFromDocumentPerLine("file:///usr/local/spark/input/rcorpus")

val vocab:Array[Tuple2[String,Long]] =
	rddBags.flatMap(x => x)
		.reduceByKey(_ + _)
		.map(_._1)
		// zipWithIndex 給每篇文檔附上文檔ID
		.zipWithIndex
		.collect

// 前半部分是將詞典裏字符串形式的單詞轉換成對應的索引下標
// 後半部分是將它轉換爲LDA可處理的稀疏向量(SparseVector)形式
// 後半部分:先將詞袋轉換成稀疏向量,然後使用zipWithIndex()給每篇文檔附上文檔ID
def codeBags(rddBags:RDD[List[Tuple2[String,Int]]]) =
	rddBags.map(x => (x ++ vocab).groupBy(_._1)
		.filter(_._2.size > 1)
		.map(x => (x._2(1)._2.asInstanceOf[Long].toInt, x._2(0)._2.asInstanceOf[Int].toDouble))
		.toList)
.zipWithIndex.map(x => (x._2, new SparseVector(
	vocab.size, x._1.map(_._1).toArray, x._1.map(_._2).toArray)
.asInstanceOf[Vector]))

// setK(5)是將文檔聚類到5個主題上
// run()返回的是一個機器學習模型,裏面提供了需要的多種信息:每個主題的描述單詞清單,每篇文檔屬於不同主題的程度。
val model = new LDA().setK(5).run(codeBags(rddBags))

// 查看每個主題的最相關的前6個單詞
model.describeTopics(6).map(_._1.map(vocab(_)._1))

執行結果:
	res1: Array[Array[String]] = Array(
		Array(billion, exchange, trading, market, system, credit), 
		Array(tonnes, billion, production, market, exports, january), 
		Array(billion, president, government, american, economic, analysts), 
		Array(company, shares, common, quarter, management, profit), 
		Array(billion, prices, agreement, report, coffee, september))

觀察第一篇文檔的主題分佈情況。由於 topicDistributions()函數會改變文檔的順序,所以需要用 filter()來獲得文檔 ID 爲 0 的文章:
	model.asInstanceOf[DistributedLDAModel].topicDistributions.filter(_._1 == 0).collect

執行結果:一個Array,前者是文檔ID,後者是和5個主題的相關性
	res2: Array[(Long, org.apache.spark.mllib.linalg.Vector)] = Array((0,[0.05294417725510889,0.1639072664938587,0.05902558780467674,0.026385449794035468,0.6977375186523203]))

3. 使用上述訓練好的模型對沒有見過的文章進行主題預測
	
	1)首先將存儲在集羣中的 DistributedLDAModel (分佈式 LDA 模型),轉換成完全存儲在driver上的 LocalLDAModel (本地 LDA 模型),因爲預測函數僅可使用LocalLDAModel 。

	2)選擇了reut2-001.sgm中的第一篇文章進行test。

	3)將模型轉換爲 LocalLDAModel 並進行主題預測 :
	model.asInstanceOf[DistributedLDAModel].toLocal.topicDistributions(codeBags(bagsFromDocumentPerLine("file:///usr/local/spark/input/test"))).collect

	執行結果:
		res3: Array[(Long, org.apache.spark.mllib.linalg.Vector)] = Array((0,[0.18995659732316772,0.24368239811339498,0.18208886519362716,0.21355056631476005,0.1707215730550501]))

4. 如何在LDA實現中使用圖(用圖來代替LDA中的稀疏舉證)
	
	1)在 Spark 1.6 中, LDA 可以使用兩個不同的算法來實現:默認的爲基於圖的最大期望( EM )算法 ,或者是在線變分貝葉斯算法。在這裏我們會着重討論 EM 算法 。EM 算法被用於解決存在有未知或隱藏變量的概率問題,正如 LDA 模型裏的隱含變量。 LDA 建立了一個概率方程組 , 如一個單詞屬於一個特定主題的概率和一個單詞在一篇特定文檔中 的概率。

	2)求解上述概率方程組時, EM 算法的兩個主要步驟是,期望和最大化,運作的方式與 K-Means 方法類似。在期望步驟中,我們會對一些變量進行猜測或估計。然後,在最大化步驟中 , 計算對應的誤差,這些變量會被相應地進行調整。這樣的過程經過多次迭代後,在期望步驟中做出的猜測會越來越接近真實的概率值 。

代碼語言:scala
參考書籍:Spark GraphX in Action

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章