Spark機器學習之Pipeline(Python)

機器學習庫(MLlib)指南
    MLlib是Spark的機器學習(ML)庫。 它的目標是使實用的機器學習可擴展和容易。它提供了一個高水平的工具,如:
    ML算法:常見的學習算法,如分類,迴歸,聚類和協同過濾
    特徵:特徵提取和選擇,變換,降維
    管道:用於構建,評估和調整ML管道的工具
    持久性:保存和加載算法,模型和管道
    工具:線性代數,統計,數據處理等
一、ML Pipelines:
    在本節中,我們介紹ML管線的概念。ML管道提供一套統一的高級API,它建立在DataFrames之上,幫助用戶創建和調整實用的機器學習管道。
    1、管道中的主要概念
        1.1 DataFrame
        1.2 管道組件
            1.2.1 Transformers
            1.2.2 Estimators
            1.2.3 管道組件的性能
        1.3 Pipeline
            1.3.1 How it works
            1.3.2 Details
        1.4 參數
        1.5 保存和加載管道
    2、代碼示例
        2.1 示例:Estimator, Transformer, and Param
        2.2 示例:Pipeline
        2.3 Model selection (hyperparameter tuning)

 1、管道中的主要概念
     MLlib爲機器學習算法標準化API,以便更容易將多個算法合併到單個管道或工作流中。 本部分涵蓋Pipelines API引入的關鍵概念,其中管道概念
 主要受scikit-learn項目的啓發。
     DataFrame:這個是ML的API使用Spark SQL中的DataFrame作爲ML數據集,它可以容納各種數據類型。 例如,DataFrame可以具有存儲文本,特徵向量,
                真實標籤和預測的不同列。
     變換器:變換器是一種可以將一個DataFrame轉換爲另一個DataFrame的算法。 例如,ML模型是將具有特徵的DataFrame轉換爲具有預測的DataFrame
            的Transformer。
     估計器:估計器是一種可以適合DataFrame以產生變換器的算法。 例如,學習算法是在DataFrame上訓練併產生模型的估計器。
     管道:管道將多個變換器和估計器鏈接在一起,以指定ML工作流。
     參數:所有變換器和估計器現在共享用於指定參數的公共API。
     
     
1.1 DataFrame
    機器學習可應用於各種各樣的數據類型,例如向量,文本,圖像和結構化數據。 此API採用Spark SQL中的DataFrame以支持各種數據類型。
DataFrame支持許多基本和結構化類型; 相關的支持類型,請參閱Spark SQL數據類型參考。 除了Spark SQL指南中列出的類型之外,
DataFrame還可以使用ML Vector類型。可以從常規RDD隱式或顯式創建DataFrame。 請參閱下面的代碼示例和Spark SQL編程指南的示例。
DataFrame中的列已命名。 下面的代碼示例使用名稱,如“text”,“功features”和“label”。


1.2 Pipeline components
1.2.1 Transformers
    Transformers是包括特徵變換和學習模型的一種抽象。 技術上,Transformer實現了一個方法transform(),它通過附加一個或多個列將一個DataFrame
轉換爲另一個DataFrame。 例如:
     特徵變換器可以採用DataFrame,讀取列(例如,文本),將其映射到新列(例如,特徵向量),並且輸出具有附加的映射列的新DataFrame。
     學習模型可以採用DataFrame,讀取包含特徵向量的列,預測每個特徵向量的標籤,並輸出新的DataFrame,其中預測的標籤作爲列添加。
     
1.2.2 Estimators
    Estimators是學習算法或任何算法對數據進行填充和訓練的概念。 從技術上講,Estimator實現了一個方法fit(),它接受一個DataFrame併產生一個Model,可以說是
    一個一個Transformer。例如,諸如LogisticRegression的學習算法是Estimators,並且調用fit()訓練LogisticRegressionModel,因爲LogisticRegressionModel
是一個模型,因此Estimators也是一個Transformers。


1.2.3 Properties of pipeline components
    Transformer.transform()和Estimator.fit()都是無狀態的。 在將來,可以經由替代概念來支持狀態算法。
    Transformer或Estimator的每個實例都有一個唯一的ID,在指定參數(下面討論)時很有用。


1.3 Pipeline
    在機器學習中,通常運行一系列算法來處理和學習數據。 例如,簡單的文本文檔處理工作流可以包括以下幾個階段:
    (1)將每個文檔的文本拆分爲單詞。
    (2)將每個文檔的單詞轉換爲數字特徵向量。
    (3)使用特徵向量和標籤瞭解預測模型。


    MLlib將包括以特定順序運行的PipelineStages(Transformers和Estimators)序列的工作流表示爲Pipeline。 
在本節中,我們將使用這個簡單的工作流程作爲一個運行的例子。


1.3.1 How it works
    Pipeline被指定爲階段序列,並且每個階段是Transfomer或Estimator。這些階段按順序運行,並且輸入DataFrame在其通過每個階段時被轉換。 對於Transformer階段,
在DataFrame上調用transform()方法。 對於Estimator階段,調用fit()方法以產生Transformer(它成爲PipelineModel的一部分或擬合的管道),並且
Transformer的transform()方法在DataFrame上調用。
    我們說明這個簡單的文本文檔工作流。 下圖是管道的訓練時間用法。


                  ML Pipeline Example


    上面,第一行表示具有三個階段的Pipeline。 前兩個(Tokenizer和HashingTF)是Transformers(藍色),第三個(LogisticRegression)
是Estimator(紅色)。 第二行表示流過Pipeline的數據,其中圓柱表示DataFrames。 在原始DataFrame上調用Pipeline.fit()方法,它具
有原始文本文檔和標籤。 Tokenizer.transform()方法將原始文本文檔拆分爲單詞,向DataFrame添加一個帶有單詞的新列。 
HashingTF.transform()方法將字列轉換爲特徵向量,向這些向量添加一個新列到DataFrame。 現在,由於LogisticRegression是一個Estimator,
Pipeline首先調用LogisticRegression.fit()產生一個LogisticRegressionModel。 如果流水線有更多的階段,則在將DataFrame傳遞到下一階段
之前,將在DataFrame上調用LogisticRegressionModel的transform()方法。


    Pipeline是一個Estimator。 因此,在Pipeline的fit()方法運行之後,它產生一個PipelineModel,它是一個Transformer。 這個管道模型在測試時使用;
下圖說明了這種用法。
            
            
          ML PipelineModel Example
             
    在上圖中,PipelineModel具有與原始流水線相同的級數,但是原始流水線中的所有Estimator都變爲Transformer。 當在test數據集上調用PipelineModel的transform()
方法時,數據按順序通過擬合Pipiline。 每個階段的transform()方法更新數據集並將其傳遞到下一個階段。
    Pipelines and PipelineModels有助於確保 training和test數據通過相同的特徵處理步驟。
    
1.3.2 Details
    DAG管道:Pipeline的階段被指定爲有序數組。這裏給出的示例全部用於線性Pipeline,即其中每個級使用由前一級產生的數據的Pipeline。只要數據流圖形形成定向非循環圖(DAG),
就可以創建非線性Pipeline。此圖形當前基於每個階段的輸入和輸出列名稱(通常指定爲參數)隱式指定。如果Pipeline形成DAG,則這個階段必須以拓撲順序指定。
    運行時檢查:由於Pipelines可以對不同類型的DataFrames進行操作,因此它們不能使用編譯時類型檢查。 Pipelines和PipelineModel而不是在實際運行管道之前進行運行時檢查。
此類型檢查是使用DataFrame模式完成的,DataFrame模式是DataFrame中列的數據類型的描述。
    獨特的流水線階段:流水線的階段應該是唯一的實例。例如,相同的實例myHashingTF不應該插入管道兩次,因爲管道階段必須具有唯一的ID。
然而,不同的實例myHashingTF1和myHashingTF2(兩者類型HashingTF)可以放入同一流水線,因爲不同的實例將創建與不同的ID。


1.4 參數
    MLlib的Estimators和Transformers使用統一的API來指定參數。Param是一個包含文檔的命名參數。 ParamMap是一組(parameter,value)對。
將參數傳遞給算法有兩種主要方法: 設置實例的參數。 例如,如果lr是LogisticRegression的一個實例,可以調用lr.setMaxIter(10)使lr.fit()最多使用10次迭代。
此API類似於spark.mllib包中使用的API。 將paramMap傳遞給fit()或transform()。 ParamMap中的任何參數都將覆蓋先前通過setter方法指定的參數。
參數屬於Estimators和Transformers的特定實例。 例如,如果我們有兩個LogisticRegression實例lr1和lr2,
那麼我們可以創建一個具有指定的maxIter參數的ParamMap:ParamMap(lr1.maxIter - > 10,lr2.maxIter - > 20)。 
如果在流水線中有兩個算法帶有maxIter參數,這是有用的。


1.5 保存和加載管道
    通常,值得將模型或管道保存到磁盤以備後用。 在Spark 1.6中,模型導入/導出功能已添加到Pipeline API。 支持大多數基本變壓器以及一些更基本的ML模型。
請參閱算法的API文檔,以瞭解是否支持保存和加載。


2、代碼示例
    本節給出了說明上述功能的代碼示例。 有關詳細信息,請參閱API文檔(Scala,Java和Python)。
2.1 示例:Estimator, Transformer, and Param

     此示例涵蓋Estimator,Transformer和Param的概念。

#Python版
from pyspark.ml.linalg import Vectors
from pyspark.ml.classification import LogisticRegression


#從(label,features)元組列表中準備訓練數據
training = spark.createDataFrame([
    (1.0, Vectors.dense([0.0, 1.1, 0.1])),
    (0.0, Vectors.dense([2.0, 1.0, -1.0])),
    (0.0, Vectors.dense([2.0, 1.3, 1.0])),
    (1.0, Vectors.dense([0.0, 1.2, -0.5]))], ["label", "features"])
#創建LogisticRegression實例。 此實例是一個估計器
lr = LogisticRegression(maxIter=10,regParam = 0.01)
#打印參數,文檔和任何默認值
print("LogisticRegression parameters:\n" + lr.explainParams() + "\n")


#學習LogisticRegression模型,使用存儲在lr中的參數
model = lr.fit(training)


#由於model是一個模型(即由Estimator生成的transformer),
#我們可以查看在fit()期間使用的參數。
#打印參數(名稱:值)對,其中名稱是唯一的ID
#LogisticRegression實例
print("Model 1 was fit using parameters: ")
print(model.extractParamMap())


#我們還可以使用Python字典作爲paramMap指定參數
paramMap = {lr.maxIter: 20}
paramMap[lr.maxIter] = 30  # 指定1 Param,覆蓋原始maxIter
paramMap.update({lr.regParam: 0.1, lr.threshold: 0.55})  # 指定多個參數


#你可以結合paramMaps,這是python詞典
paramMap2 = {lr.probabilityCol: "myProbability"}  # 改變輸出列的名稱
paramMapCombined = paramMap.copy()
paramMapCombined.update(paramMap2)


#現在使用paramMapCombined參數學習一個新模型
#paramMapCombined通過lr.set *方法覆蓋之前設置的所有參數
model2 = lr.fit(training, paramMapCombined)
print("Model 2 was fit using parameters: ")
print(model2.extractParamMap())


#準備測試數據
test = spark.createDataFrame([
    (1.0, Vectors.dense([-1.0, 1.5, 1.3])),
    (0.0, Vectors.dense([3.0, 2.0, -0.1])),
    (1.0, Vectors.dense([0.0, 2.2, -1.5]))], ["label", "features"])


#使用Transformer.transform()方法對測試數據進行預測。
#LogisticRegression.transform將只使用“features”列。
#請注意,model2.transform()輸出“myProbability”列,而不是通常的
#'probability'列,因爲我們以前重命名了lr.probabilityCol參數。
prediction = model2.transform(test)


result = prediction.select("features", "label", "myProbability", "prediction") \
    .collect()
for row in result:
    print("features=%s, label=%s -> prob=%s, prediction=%s"
          % (row.features, row.label, row.myProbability, row.prediction))


輸出:
features=[-1.0,1.5,1.3], label=1.0 -> prob=[0.0570730417103,0.94292695829], prediction=1.0
features=[3.0,2.0,-0.1], label=0.0 -> prob=[0.92385223117,0.0761477688296], prediction=0.0
features=[0.0,2.2,-1.5], label=1.0 -> prob=[0.109727761148,0.890272238852], prediction=1.0

2.2 示例:Pipeline
    #Python版
    from pyspark.ml import Pipeline
from pyspark.ml.classification import LogisticRegression
from pyspark.ml.feature import HashingTF, Tokenizer


#從(id,text,label)的元組列表準備訓練文檔
training = spark.createDataFrame([
    (0, "a b c d e spark", 1.0),
    (1, "b d", 0.0),
    (2, "spark f g h", 1.0),
    (3, "hadoop mapreduce", 0.0)
], ["id", "text", "label"])


#配置ML的Pipeline,包括三個階段:tokenizer,hashingTF和lr。
tokenizer = Tokenizer(inputCol="text", outputCol="words")
hashingTF = HashingTF(inputCol=tokenizer.getOutputCol(), outputCol="features")
lr = LogisticRegression(maxIter=10, regParam=0.001)
pipeline = Pipeline(stages=[tokenizer, hashingTF, lr])


#擬合數據
model = pipeline.fit(training)


#準備測試文檔,它們是未標記(id,text)元組。
test = spark.createDataFrame([
    (4, "spark i j k"),
    (5, "l m n"),
    (6, "spark hadoop spark"),
    (7, "apache hadoop")
], ["id", "text"])


#預測和打印
prediction = model.transform(test)
selected = prediction.select("id", "text", "probability", "prediction")
for row in selected.collect():
    rid, text, prob, prediction = row
    print("(%d, %s) --> prob=%s, prediction=%f" % (rid, text, str(prob), prediction))


輸出:
(4, spark i j k) --> prob=[0.159640773879,0.840359226121], prediction=1.000000
(5, l m n) --> prob=[0.837832568548,0.162167431452], prediction=0.000000
(6, spark hadoop spark) --> prob=[0.0692663313298,0.93073366867], prediction=1.000000
(7, apache hadoop) --> prob=[0.982157533344,0.0178424666556], prediction=0.000000


2.3 Model selection (hyperparameter tuning)
    使用ML管道的一個大好處是超參數優化。 有關自動模型選擇的更多信息,請參閱ML Tuning Guide。
    

發佈了141 篇原創文章 · 獲贊 36 · 訪問量 32萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章