當前位置: 首頁>>機器學習>>正文


Spark機器學習庫指南[Spark 1.3.1版]——特征提取和轉換(Feature extraction and transformation)

下麵是章節特征提取和轉換的內容(其他內容參見全文目錄)

 

TF-IDF

TF-IDF(Term frequency-inverse document frequency ) 是文本挖掘中一種廣泛使用的特征向量化方法。TF-IDF反映了語料中單詞對文檔的重要程度。假設單詞用t表示,文檔用d表示,語料用D表示,那麽文檔頻度DF(t, D)是包含單詞t的文檔數。如果我們隻是使用詞頻度量重要性,就會很容易過分強調重負次數多但攜帶信息少的單詞,例如:”a”, “the”以及”of”。如果某個單詞在整個語料庫中高頻出現,意味著它沒有攜帶專門針對某特殊文檔的信息。逆文檔頻度(IDF)是單詞攜帶信息量的數值度量。

idf

其中 |D|是語料中的文檔總數。由於使用了log計算,如果單詞在所有文檔中出現,那麽IDF就等於0。注意這裏做了平滑處理(+1操作),防止單詞沒有在語料中出現時IDF計算中除0。TF-IDF度量是TF和IDF的簡單相乘:

tfidf

 

事實上詞頻和文檔頻度的定義有多重變體。在MLlib中,為了靈活性我們將TF和IDF分開處理。

MLlib中詞頻統計的實現使用了hashing trick(散列技巧),也就是使用哈希函數將原始特征映射到一個數字索引。然後基於這個索引來計算詞頻。這個方法避免了全局的單詞到索引的映射,全局映射對於大量語料有非常昂貴的計算/存儲開銷;但是該方法也帶來了潛在哈希衝突的問題,不同原始特征可能會被映射到相同的索引。為了減少衝突率,我們可以提升目標特征的維度,例如,哈希表中桶的數量。默認特征維度是220 = 1048576。

注意:MLlib沒有提供文本分段(例如分詞)的工具。用戶可以參考Stanford NLP Groupscalanlp/chalk

TF和IDF分別在類HashingTF and IDF中實現。HashTF以RDD[list]為輸入。鏈表中的每個元素是可遍曆的字符串或者其他類型。

from pyspark import SparkContext
from pyspark.mllib.feature import HashingTF

sc = SparkContext()

# Load documents (one per line).
documents = sc.textFile("...").map(lambda line: line.split(" "))

hashingTF = HashingTF()
tf = hashingTF.transform(documents)

IDF以及TFIDF的計算如下:

from pyspark.mllib.feature import IDF
# ... continue from the previous example 
tf.cache()
idf = IDF().fit(tf)
tfidf = idf.transform(tf)

MLlib中的IDF計算提供了忽略低頻詞的選項。被忽略的詞IDF置零。該特性可以通過將參數minDocFreq傳給IDF構造函數來使用。

# ... continue from the previous example
tf.cache()
idf = IDF(minDocFreq=2).fit(tf)
tfidf = idf.transform(tf)

 

Word2Vec

Word2Vec 計算單詞的向量表示。這種表示的主要優點是相似的詞在向量空間中離得近,這使得向新模式的泛化更容易並且模型估計更魯棒。向量表示在諸如命名實體識別、歧義消除、句子解析、打標簽以及機器翻譯等自然語言處理程序中比較有用。

模型

MLlib中的Word2Vec實現,使用的是skip-gram模型。skip-gram的目標函數是學習擅長預測同一個句子中詞的上下文的詞向量表示。用數學語言表達就是,給定一個訓練單詞序列:w1, w2, …, wT, skip-gram模型的目標是最大化平均log似然函數(log-likelihood):

avgloglikelihood

 

其中k是訓練窗口的大小,也就是給定一個詞,需要分別查看前後k個詞。

在skip-gram模型中,每個詞w跟兩個向量uw和vw關聯:uw是w的詞向量表示,是vw上下文。給定單詞wj,正確預測單詞wi的概率取決於softmax模型:

soft


 

其中V是單詞總數.

使用softmax的skip-gram模型開銷很大,因為log p(wi|wj)的計算量跟V成比例,而V很可能在百萬量級。為了加速Word2Vec的訓練,我們引入了層次softmax,該方法將計算log p(wi|wj)時間複雜度降低到了O(log(V))。

示例

在下麵的例子中,首先導入文本文件,然後將數據解析為RDD[Seq[String]],接著構造Word2Vec實例並使用輸入數據擬合出Word2VecModel模型。最後,顯示了指定單詞的40個同義詞。要運行這段程序,需要先下載text8數據並解壓到本地目錄。

from pyspark import SparkContext
from pyspark.mllib.feature import Word2Vec

sc = SparkContext(appName='Word2Vec')
inp = sc.textFile("text8_lines").map(lambda row: row.split(" "))

word2vec = Word2Vec()
model = word2vec.fit(inp)

synonyms = model.findSynonyms('china', 40)

for word, cosine_distance in synonyms:
    print "{}: {}".format(word, cosine_distance)

 

標準化(StandardScaler)

標準化是指:對於訓練集中的樣本,基於列統計信息將數據除以方差或(且)者將數據減去其均值(結果是方差等於1,數據在0附近)。這是很常用的預處理步驟。

例如,當所有的特征具有值為1的方差且/或值為0的均值時,SVM的徑向基函數(RBF)核或者L1和L2正則化線性模型通常有更好的效果。

標準化可以提升模型優化階段的收斂速度,還可以避免方差很大的特征對模型訓練產生過大的影響。

模型擬合

StandardScaler的構造函數具有下列參數:

  • withMean 默認值False. 在尺度變換(除方差)之前使用均值做居中處理(減去均值)。這會導致密集型輸出,所以在稀疏數據上無效。
  • withStd 默認值True. 將數據縮放(尺度變換)到單位標準差。

StandardScaler.fit()方法以RDD[Vector]為輸入,計算匯總統計信息,然後返回一個模型,該模型可以根據StandardScaler配置將輸入數據轉換為標準差為1,均值為0的特征。

模型中還實現了VectorTransformer,這個類可以對Vector和RDD[Vector]做轉化。

注意:如果某特征的方差是0,那麽標準化之後返回默認的0.0作為特征值。

示例

在下麵的例子中,首先倒入libsvm格式的數據,然後做特征標準化,標準化之後新的特征值有單位長度的標準差和/或均值。

from pyspark.mllib.util import MLUtils
from pyspark.mllib.linalg import Vectors
from pyspark.mllib.feature import StandardScaler

data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")
label = data.map(lambda x: x.label)
features = data.map(lambda x: x.features)

scaler1 = StandardScaler().fit(features)
scaler2 = StandardScaler(withMean=True, withStd=True).fit(features)
# scaler3 is an identical model to scaler2, and will produce identical transformations
scaler3 = StandardScalerModel(scaler2.std, scaler2.mean)


# data1 will be unit variance.
data1 = label.zip(scaler1.transform(features))

# Without converting the features into dense vectors, transformation with zero mean will raise
# exception on sparse vector.
# data2 will be unit variance and zero mean.
data2 = label.zip(scaler1.transform(features.map(lambda x: Vectors.dense(x.toArray()))))

 

歸一化(Normalizer)

歸一化是指將每個獨立樣本做尺度變換從而是該樣本具有單位Lp範數。這是文本分類和聚類中的常用操作。例如,兩個做了L2歸一化的TF-IDF向量的點積是這兩個向量的cosine(餘弦)相似度。

Normalizer 的構造函數有以下參數:

  • 在Lp空間的p範數, 默認p=2。

Normlizer實現了VectorTransformer ,這個類可以對Vector和RDD[Vector]做歸一化。

注意:如果輸入的範數是0,會返回原來的輸入向量。

示例

在下麵的例子中,首先導入libsvm格式的數據,然後使用L2範數和L範數歸一化。

from pyspark.mllib.util import MLUtils
from pyspark.mllib.linalg import Vectors
from pyspark.mllib.feature import Normalizer

data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")
labels = data.map(lambda x: x.label)
features = data.map(lambda x: x.features)

normalizer1 = Normalizer()
normalizer2 = Normalizer(p=float("inf"))

# Each sample in data1 will be normalized using $L^2$ norm.
data1 = labels.zip(normalizer1.transform(features))

# Each sample in data2 will be normalized using $L^\infty$ norm.
data2 = labels.zip(normalizer2.transform(features))

 

特征選擇

Feature selection特征選擇是指為建模過程選擇最相關的特征。特征選擇降低了向量空間的大小,從而降低了後續向量操作的時間複雜度。選擇的特征的數量可以通過驗證集來調節。

卡方選擇(ChiSqSelector)

ChiSqSelector是指使用卡方(Chi-Squared)做特征選擇。該方法操作的是有標簽的類別型數據。ChiSqSelector基於卡方檢驗來排序數據,然後選出卡方值較大(也就是跟標簽最相關)的特征(topk)。

模型擬合

ChiSqSelector 的構造函數有如下特征:

  • numTopFeatures 保留的卡方較大的特征的數量。

ChiSqSelector.fit() 方法以具有類別特征的RDD[LabeledPoint]為輸入,計算匯總統計信息,然後返回ChiSqSelectorModel,這個類將輸入數據轉化到降維的特征空間。

模型實現了 VectorTransformer,這個類可以在Vector和RDD[Vector]上做卡方特征選擇。

注意:也可以手工構造一個ChiSqSelectorModel,需要提供升序排列的特征索引。

示例(Scala)

下麵的例子說明了ChiSqSelector的基本用法。

import org.apache.spark.SparkContext._
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.mllib.util.MLUtils

// Load some data in libsvm format
val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")
// Discretize data in 16 equal bins since ChiSqSelector requires categorical features
val discretizedData = data.map { lp =>
  LabeledPoint(lp.label, Vectors.dense(lp.features.toArray.map { x => x / 16 } ) )
}
// Create ChiSqSelector that will select 50 features
val selector = new ChiSqSelector(50)
// Create ChiSqSelector model (selecting features)
val transformer = selector.fit(discretizedData)
// Filter the top 50 features from each feature vector
val filteredData = discretizedData.map { lp => 
  LabeledPoint(lp.label, transformer.transform(lp.features)) 
}

本文由《純淨天空》出品。文章地址: https://vimsky.com/zh-tw/article/643.html,未經允許,請勿轉載。