Spark數據挖掘-TF-IDF文檔矩陣

Spark數據挖掘-TF-IDF文檔矩陣

前言

獲得詞文檔矩陣每每都是文本挖掘算法的第一步,詞文檔矩陣中行表示語料庫中出現過的詞(實際代碼都是對詞進行整數編碼),列表示全部的文檔,矩陣中的每一個值就表明詞在文檔中的重要程度。目前已經有不少計算詞在文檔中權重的模型,不過最通用的模型應該就是 詞頻-逆文檔頻率(簡稱:TF-IDF) 矩陣。算法

TF-IDF

先看一下TF-IDF如何計算每一個詞在文檔中的重要程度,先假設獲得了下面幾個變量的值:數據庫

  • termFrequencyInDoc:Int 詞在文檔中出現的次數
  • totalTermsInDoc: Int 文檔中全部詞的個數
  • termFreqInCorpus: Int 語料庫中出現這個詞的不一樣文檔數
  • totalDocs: Int 整個語料庫包含的文檔數量

利用上面的幾個值就能夠計算一個詞在文檔中的重要程度,代碼以下:編程

def termDocWeight(termFrequencyInDoc: Int, totalTermsInDoc: Int,
  termFreqInCorpus: Int, totalDocs: Int): Double = {
  val tf = termFrequencyInDoc.toDouble / totalTermsInDoc
  val docFreq = totalDocs.toDouble / termFreqInCorpus
  val idf = math.log(docFreq)
  tf * idf
}

TF-IDF含義解讀

直觀理解,TF-IDF考慮了以下兩個方面:分佈式

  1. 首先,詞在某篇文檔中出現的越多越重要
  2. 其次,詞在其餘文檔中儘可能少出現,若是每篇文檔中它都出現的不少,它就沒有區分度了。因此這裏採用的是文檔頻率取逆,也就是取倒數。

可是有個問題,首先詞頻是近似服從指數分佈,一些通用詞出現的次數多是低頻詞幾十或者幾百倍,直接採用文檔頻率取逆會致使稀缺詞得到一個巨大的權重,實際上就會忽略其餘詞的影響,這樣顯然不妥,爲了去掉這個影響,算法採用對文檔頻率取逆以後再取對數,這樣就把乘法差別轉化爲加法差別。使得稀缺詞權重下降了。編碼

TF-IDF的侷限

這個算法本質仍是詞袋模型,它沒有考慮詞與詞之間的順序、語法結構以及語義。經過對每一個不一樣的詞計數,這個模型很難區別一詞多義、以及同義詞。實際編程中每每每篇文檔表示爲行向量,每一個元素表明詞對應的索引位置,這樣能夠適應語料庫中文檔變的愈來愈多,一般狀況下,語料庫文檔的增長速度確定大過詞的增加速度。並且這樣的行向量也是稀疏表示,節省空間。scala

TF-IDF實戰

TF-IDF原理很是簡單,實際工做中仍是有不少須要注意的地方,下面就用 Spark 實戰的方式講解如何將一個語料庫轉爲 TF-IDF 矩陣,首先給出具體的步驟:code

  1. 實際工做中對每篇文檔每每都有一個惟一的標識主鍵,這樣方便之後的統計
  2. 文檔清洗(去掉不符合要求的文檔:好比文檔內容爲空)
  3. 文檔分詞(去掉停用詞、按詞性過濾一下詞、過濾低頻詞、詞幹提取),其中詞幹提取指的是將好比:「大款、大款們」合併爲一個詞,中文實現這個難度很大。
  4. 數據加載,詞編碼、文檔編碼
  5. 將數據編碼以後轉爲文檔詞向量再合併爲矩陣
  6. 計算IF-IDF

數據清洗、停詞庫每一個項目都會有不一樣的要求,可是分詞、詞編碼、文檔編碼等工做仍是比較通用的,下面會對通用技術經過 Spark 實戰詳細講解(尤爲是分佈式編程須要注意的地方:)orm

分佈式文本分詞

分佈式文本分詞注意兩個地方:索引

  • 停詞庫須要廣播到全部機器
  • 每一個 executor 只需啓動一個分詞模型便可,分詞模型很耗資源,與鏈接數據庫同樣,每一個executor只需啓動一個實例

計算TF-IDF

val documents: RDD[Seq[String]] = sc.textFile("your_data_dir").map(_.split(" ").toSeq)

val hashingTF = new HashingTF()
val tf: RDD[Vector] = hashingTF.transform(documents)

tf.cache()
//沒有在兩個文檔中出現過的詞語不要
val idf = new IDF(minDocFreq = 2).fit(tf)
val tfidf: RDD[Vector] = idf.transform(tf)
相關文章
相關標籤/搜索