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上調用。
我們說明這個簡單的文本文檔工作流。 下圖是管道的訓練時間用法。
上面,第一行表示具有三個階段的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。 這個管道模型在測試時使用;
下圖說明了這種用法。
在上圖中,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。