Spark分佈式機器學習源碼分析:特徵提取與轉換

 Spark是一個極爲優秀的大數據框架,在大數據批處理上基本無人能敵,流處理上也有一席之地,機器學習則是當前正火熱AI人工智能的驅動引擎,在大數據場景下如何發揮AI技術成爲優秀的大數據挖掘工程師必備技能。本文結合機器學習思想與Spark框架代碼結構來實現分佈式機器學習過程,希望與大家一起學習進步~

    本文采用的組件版本爲:Ubuntu 19.10、Jdk 1.8.0_241、Scala 2.11.12、Hadoop 3.2.1、Spark 2.4.5老規矩先開啓一系列Hadoop、Spark服務與Spark-shell窗口:

1

TF-IDF

    術語頻率逆文檔頻率(TF-IDF)是一種特徵向量化方法,廣泛用於文本挖掘中,以反映術語對語料庫中文檔的重要性。用t表示項,用d表示文檔,用D表示語料庫。術語頻率TF(t,d)是術語t在文檔d中出現的次數,而文檔頻率DF(t,D)是包含術語t的文檔數。

    如果術語經常出現在整個語料庫中,則表示該術語不包含有關特定文檔的特殊信息。反向文檔頻率是一個術語提供多少信息的數字度量:

    | D | 是語料庫中文檔的總數。由於使用對數,因此如果一個術語出現在所有文檔中,則其IDF值將變爲0。請注意,應用了平滑術語以避免對主體外的術語除以零。TF-IDF度量只是TF和IDF的乘積:

    術語頻率和文檔頻率的定義有多種變體。在spark.mllib中,我們將TF和IDF分開以使其具有靈活性。TF和IDF在HashingTF和IDF中實現。HashingTF將RDD [Iterable [_]]作爲輸入。每個記錄可以是字符串或其他類型的迭代。

import org.apache.spark.mllib.feature.{HashingTF, IDF}
import org.apache.spark.mllib.linalg.Vector
import org.apache.spark.rdd.RDD
// 加載文檔
val documents: RDD[Seq[String]] = sc.textFile("data/mllib/kmeans_data.txt").map(_.split(" ").toSeq)
val hashingTF = new HashingTF()
val tf: RDD[Vector] = hashingTF.transform(documents)
// 應用HashingTF只需要一次傳遞,應用IDF需要兩次傳遞
// 首先計算IDF向量,其次通過IDF縮放項頻率。
tf.cache()
val idf = new IDF().fit(tf)
val tfidf: RDD[Vector] = idf.transform(tf)
// spark.mllib IDF實現提供了一個選項,用於忽略少於最少數量的文檔中出現的術語。在這種情況下,這些術語的IDF設置爲0。
//可以通過將minDocFreq值傳遞給IDF構造函數來使用此功能。
val idfIgnore = new IDF(minDocFreq = 2).fit(tf)
val tfidfIgnore: RDD[Vector] = idfIgnore.transform(tf)

2

word2vec

    Word2Vec計算單詞的分佈式矢量表示。分佈式表示的主要優點是向量空間中相似的詞很接近,這使得對新穎模式的泛化更加容易,模型估計也更加可靠。分佈式矢量表示被證明在許多自然語言處理應用程序中很有用,例如命名實體識別,歧義消除,解析,標記和機器翻譯。

    在Word2Vec的實現中,我們使用了跳過語法模型。跳過語法的訓練目標是學習擅長在同一句子中預測其上下文的詞向量表示。從數學上講,給定一系列訓練詞w1,w2,…,wT,跳躍語法模型的目標是使平均對數似然性最大化

    其中k是訓練窗口的大小。在跳過語法模型中,每個單詞w與兩個向量uw和vw相關聯,這兩個向量分別是w作爲單詞和上下文的向量表示。給定單詞wj正確預測單詞wi的概率由softmax模型確定,該模型爲

    其中V是詞彙量。具有softmax的跳過語法模型很昂貴,因爲計算logp(wi | wj)的成本與V成正比,這很容易達到數百萬個的數量級。爲了加快Word2Vec的訓練速度,我們使用了層次化softmax,將logp(wi | wj)的計算複雜度降低爲O(log(V))

    下面的示例演示如何加載文本文件,將其解析爲Seq [String]的RDD,構造Word2Vec實例,然後使用輸入數據擬合Word2VecModel。最後,我們顯示指定單詞的前40個同義詞。要運行該示例,請首先下載text8數據並將其提取到您的首選目錄中。在這裏,我們假設提取的文件是text8,並且與運行spark shell的目錄位於同一目錄中。

import org.apache.spark.mllib.feature.{Word2Vec, Word2VecModel}
val input = sc.textFile("data/mllib/sample_lda_data.txt").map(line => line.split(" ").toSeq)
val word2vec = new Word2Vec()
val model = word2vec.fit(input)
val synonyms = model.findSynonyms("1", 5)
for((synonym, cosineSimilarity) <- synonyms) {
  println(s"$synonym $cosineSimilarity")
}
// Save and load model
model.save(sc, "myModelPath")
val sameModel = Word2VecModel.load(sc, "myModelPath")

3

特徵縮放

    通過縮放到單位方差和/或使用訓練集中樣本上的列摘要統計信息來去除均值來對特徵進行標準化。這是非常常見的預處理步驟。例如,當所有特徵均具有單位方差和/或均值爲零時,支持向量機的RBF內核或L1和L2正則化線性模型通常會更好地工作。

    標準化可以提高優化過程中的收斂速度,並且還可以防止差異很大的特徵在模型訓練期間產生過大的影響。下面的示例演示瞭如何以libsvm格式加載數據集並標準化功能,以便新功能具有單位標準差和/或零均值。

import org.apache.spark.mllib.feature.{StandardScaler, StandardScalerModel}
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.util.MLUtils
val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")
val scaler1 = new StandardScaler().fit(data.map(x => x.features))
val scaler2 = new StandardScaler(withMean = true, withStd = true).fit(data.map(x => x.features))
// scaler3是與scaler2相同的模型,並將產生相同的轉換
val scaler3 = new StandardScalerModel(scaler2.std, scaler2.mean)
// 是單位方差
val data1 = data.map(x => (x.label, scaler1.transform(x.features)))
// data2將是單位方差和零均值。
val data2 = data.map(x => (x.label, scaler2.transform(Vectors.dense(x.features.toArray))))

4

歸一化

    歸一化將單個樣本縮放爲具有單位Lp範數。這是文本分類或聚類的常用操作。例如,兩個L2歸一化TF-IDF向量的點積是向量的餘弦相似度。規範化器在構造函數中具有以下參數:p空間中的歸一化,默認情況下p = 2。

    歸一化實現了VectorTransformer,可以將規範化應用於Vector以產生轉換後的Vector或在RDD [Vector]上產生轉換的RDD [Vector]。請注意,如果輸入範數爲零,則它將返回輸入向量。

    下面的示例演示如何以libsvm格式加載數據集,並使用L2範數和L∞範數對特徵進行歸一化。

import org.apache.spark.mllib.feature.Normalizer
import org.apache.spark.mllib.util.MLUtils
val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")
val normalizer1 = new Normalizer()
val normalizer2 = new Normalizer(p = Double.PositiveInfinity)
// data1中的每個樣本都將使用$ L ^ 2 $範數進行歸一化。
val data1 = data.map(x => (x.label, normalizer1.transform(x.features)))
// data2中的每個樣本都將使用$ L ^ \ infty $範數進行標準化。
val data2 = data.map(x => (x.label, normalizer2.transform(x.features)))

5

ChiSq選擇器

    ChiSqSelector實現Chi-Squared特徵選擇。它對具有分類特徵的標記數據進行操作。ChiSqSelector使用卡方獨立性檢驗來決定選擇哪些功能。它支持五種選擇方法:numTopFeatures,percentile,fpr,fdr,fwe。

    以下示例顯示了ChiSqSelector的基本用法。所使用的數據集具有一個由灰度值組成的特徵矩陣,每個值的灰度值從0到255不等。

import org.apache.spark.mllib.feature.ChiSqSelector
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.mllib.util.MLUtils
val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")
//由於ChiSqSelector需要分類特徵,因此將數據離散化爲16個相等的bin
//即使功能是雙精度的,ChiSqSelector也會將每個唯一值都視爲一個類別


val discretizedData = data.map { lp =>
  LabeledPoint(lp.label, Vectors.dense(lp.features.toArray.map { x => (x / 16).floor }))
}
// 創建將選擇692個特徵中前50個特徵的ChiSqSelector
val selector = new ChiSqSelector(50)
// 創建ChiSqSelector模型(選擇功能)
val transformer = selector.fit(discretizedData)
// 從每個特徵向量過濾前50個特徵
val filteredData = discretizedData.map { lp =>
  LabeledPoint(lp.label, transformer.transform(lp.features))
}

6

元素職能乘積

    ElementwiseProduct使用逐元素乘法將每個輸入向量乘以提供的“權重”向量。換句話說,它通過標量乘子縮放數據集的每一列。這表示輸入向量v和轉換向量scaleVec之間的Hadamard乘積,以產生結果向量。將scalingVec表示爲“ w”,此轉換可以寫爲:

    ElementwiseProduct在構造函數中具有參數scaleVec:轉換向量。ElementwiseProduct實現VectorTransformer,可以將權重應用於Vector來生成轉換後的Vector或在RDD [Vector]上生成轉換後的RDD [Vector]。

    下面的示例演示瞭如何使用轉換向量值轉換向量。

import org.apache.spark.mllib.feature.ElementwiseProduct
import org.apache.spark.mllib.linalg.Vectors
//創建一些矢量數據; 也適用於稀疏向量
val data = sc.parallelize(Array(Vectors.dense(1.0, 2.0, 3.0), Vectors.dense(4.0, 5.0, 6.0)))
val transformingVector = Vectors.dense(0.0, 1.0, 2.0)
val transformer = new ElementwiseProduct(transformingVector)
//批處理變換和逐行變換給出相同的結果:
val transformedData = transformer.transform(data)
val transformedData2 = data.map(x => transformer.transform(x))

    Spark 特徵提取與轉換的內容至此結束,有關Spark的基礎文章可參考前文:

    Spark分佈式機器學習源碼分析:矩陣向量

    Spark分佈式機器學習源碼分析:基本統計

    Spark分佈式機器學習源碼分析:線性模型

    Spark分佈式機器學習源碼分析:樸素貝葉斯

    Spark分佈式機器學習源碼分析:決策樹模型

    Spark分佈式機器學習源碼分析:集成樹模型

    Spark分佈式機器學習源碼分析:協同過濾

    Spark分佈式機器學習源碼分析:K-means

    Spark分佈式機器學習源碼分析:隱式狄利克雷分佈

    Spark分佈式機器學習源碼分析:奇異值分解與主成分分析

    參考鏈接:

    http://spark.apache.org/docs/latest/mllib-feature-extraction.html

    https://github.com/endymecy/spark-ml-source-analysis

歷史推薦

“高頻面經”之數據分析篇

“高頻面經”之數據結構與算法篇

“高頻面經”之大數據研發篇

“高頻面經”之機器學習篇

“高頻面經”之深度學習篇

爬蟲實戰:Selenium爬取京東商品

爬蟲實戰:豆瓣電影top250爬取

爬蟲實戰:Scrapy框架爬取QQ音樂

數據分析與挖掘

數據結構與算法

機器學習與大數據組件

歡迎關注,感謝“在看”,隨緣稀罕~

 

一個贊,晚餐加雞腿

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