機器學習(十一) 機器學習工作流

機器學習工作流

【版權聲明】本文為原創,轉載請注明原地址 http://www.lxweimin.com/p/99ad946dbca1
同步更新在個人網站:http://www.wangpengcufe.com/machinelearning/ml-ml11/

一、概念

一個典型的機器學習過程從數據收集開始,要經歷多個步驟,才能得到需要的輸出。這非常類似于流水線式工作,即通常會包含源數據ETL(抽取、轉化、加載),數據預處理,指標提取,模型訓練與交叉驗證,新數據預測等步驟。

MLlib標準化了用于機器學習算法的API,從而使將多種算法組合到單個管道或工作流程中變得更加容易。 本節介紹了Pipelines API引入的關鍵概念,其中PipeLine(管道)概念主要受scikit-learn項目的啟發。

在介紹工作流之前,我們先來了解幾個重要概念:

DataFrame:使用Spark SQL中的DataFrame作為ML數據集,該數據集可以保存各種數據類型。 例如,DataFrame可以具有不同的列,用于存儲文本,特征向量,真實標簽和預測。

Transformer:翻譯成轉換器,是一種算法,可以將一個DataFrame轉換為另一個DataFrame。 例如,ML模型是一個Transformer,它將具有特征的DataFrame轉換為具有預測的DataFrame。

Estimator:翻譯成評估器,它是學習算法或在訓練數據上的訓練方法的概念抽象。在 Pipeline 里通常是被用來操作 DataFrame 數據并生產一個 Transformer。從技術上講,Estimator實現了一個方法fit(),它接受一個DataFrame并產生一個轉換器。例如,諸如LogisticRegression之類的學習算法是Estimator,調用fit()可以訓練LogisticRegressionModel,后者是Model,因此是Transformer。

Parameter:Parameter 被用來設置 Transformer 或者 Estimator 的參數。現在,所有轉換器和估計器可共享用于指定參數的公共API。ParamMap是一組(參數,值)對。

PipeLine:翻譯為工作流或者管道。管道將多個“變形器”和“估計器”鏈接在一起,以指定ML工作流程,并獲得結果輸出。 例如,簡單的文本文檔處理工作流程可能包括幾個階段:
1、將每個文檔的文本拆分為單詞。
2、將每個文檔的單詞轉換成數字特征向量。
3、使用特征向量和標簽學習預測模型。
MLlib將這樣的工作流表示為“管道”,它由要按特定順序運行的一系列PipelineStages(變壓器和估計器)組成。

二、工作原理

要構建一個 Pipeline工作流,首先需要定義 Pipeline 中的各個工作流階段PipelineStage,(包括轉換器和評估器),比如指標提取和轉換模型訓練等。有了這些處理特定問題的轉換器和 評估器,就可以按照具體的處理邏輯有序的組織PipelineStages 并創建一個Pipeline。比如:

Pipeline pipeline = new Pipeline().setStages(new  PipelineStage[]{tokenizer,hashingTF,lr});

然后就可以把訓練數據集作為輸入參數,調用 Pipeline 實例的 fit 方法來開始以流的方式來處理源訓練數據。這個調用會返回一個 PipelineModel 類實例,進而被用來預測測試數據的標簽。更具體的說,工作流的各個階段按順序運行,輸入的DataFrame在它通過每個階段時被轉換。 對于Transformer階段,在DataFrame上調用transform()方法。 對于估計器階段,調用fit()方法來生成一個轉換器(它成為PipelineModel的一部分或擬合的Pipeline),并且在DataFrame上調用該轉換器的transform()方法。


Pipeline1

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

值得注意的是,工作流本身也可以看做是一個估計器。在工作流的fit()方法運行之后,它產生一個PipelineModel,它是一個Transformer。 這個管道模型將在測試數據的時候使用。 下圖說明了這種用法。

Pipeline2

在上圖中,PipelineModel具有與原始流水線相同的級數,但是原始流水線中的所有估計器都變為變換器。 當在測試數據集上調用PipelineModel的transform()方法時,數據按順序通過擬合的工作流。 每個階段的transform()方法更新數據集并將其傳遞到下一個階段。工作流和工作流模型有助于確保培訓和測試數據通過相同的特征處理步驟。

三、代碼實現

以邏輯斯蒂回歸為例,構建一個典型的機器學習過程,來具體介紹一下工作流是如何應用的。我們的目的是查找出所有包含”spark”的句子,即將包含”spark”的句子的標簽設為1,沒有”spark”的句子的標簽設為0。

3.1、構建訓練數據集
import java.util.Arrays;
import java.util.List;
import org.apache.spark.ml.Pipeline;
import org.apache.spark.ml.PipelineModel;
import org.apache.spark.ml.PipelineStage;
import org.apache.spark.ml.classification.LogisticRegression;
import org.apache.spark.ml.feature.HashingTF;
import org.apache.spark.ml.feature.Tokenizer;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.RowFactory;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.Metadata;
import org.apache.spark.sql.types.StructField;
import org.apache.spark.sql.types.StructType;
SparkSession spark = SparkSession.builder().appName("MLPipelines").master("local").getOrCreate();
//構建訓練數據集
List<Row> data = Arrays.asList(RowFactory.create(0L, "a b c d e spark", 1.0),
                               RowFactory.create(1L, "b d", 0.0),
                               RowFactory.create(2L, "spark f g h", 1.0),
                               RowFactory.create(3L, "hadoop mapreduce", 0.0));
System.out.println(data);
/**
*控制臺輸出結果:
-------------------------------------------------------------------------------------
[[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]]
-------------------------------------------------------------------------------------
**/
StructType schema = new StructType(new StructField[] {
    new StructField("id",DataTypes.LongType,false,Metadata.empty()),
    new StructField("text", DataTypes.StringType, false, Metadata.empty()),
    new StructField("label", DataTypes.DoubleType, false, Metadata.empty()),
});
Dataset<Row> training = spark.createDataFrame(data,schema);
training.show(false);
/**
*控制臺輸出結果:
    +---+----------------+-----+
    |id |text            |label|
    +---+----------------+-----+
    |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  |
    +---+----------------+-----+
**/
3.2、定義 Pipeline 中的各個工作流階段PipelineStage

在這一步中我們要定義 Pipeline 中的各個工作流階段PipelineStage,包括轉換器和評估器,具體的,包含tokenizer, hashingTF和lr三個步驟。

Tokenizer tokenizer = new Tokenizer().setInputCol("text")
                                     .setOutputCol("words");

HashingTF hashingTF = new HashingTF().setNumFeatures(1000)
                                     .setInputCol(tokenizer.getOutputCol())
                                     .setOutputCol("features");

LogisticRegression lr = new LogisticRegression().setMaxIter(10).setRegParam(0.01);
3.3、創建一個Pipeline

有了這些處理特定問題的轉換器和評估器,接下來就可以按照具體的處理邏輯有序的組織PipelineStages 并創建一個Pipeline。

Pipeline pipeline = new Pipeline().setStages(new PipelineStage[]{tokenizer,hashingTF,lr});
3.4、創建模型

現在構建的Pipeline本質上是一個Estimator,在它的fit()方法運行之后,它將產生一個PipelineModel,它是一個Transformer。

PipelineModel model = pipeline.fit(training);

我們可以看到,model的類型是一個PipelineModel,這個管道模型將在測試數據的時候使用。所以接下來,我們先構建測試數據。

List<Row> testRaw = Arrays.asList(RowFactory.create(4L, "spark i j k"),
        RowFactory.create(5L, "l m n"),
        RowFactory.create(6L, "spark a"),
        RowFactory.create(7L, "apache hadoop")
        );
Dataset<Row> test = spark.createDataFrame(testRaw,schema);
test.select("id", "text").show(false);
/**
*控制臺輸出結果:
    +---+-------------+
    |id |text         |
    +---+-------------+
    |4  |spark i j k  |
    |5  |l m n        |
    |6  |spark a      |
    |7  |apache hadoop|
    +---+-------------+
**/
3.5、預測結果

然后,我們調用我們訓練好的PipelineModel的transform()方法,讓測試數據按順序通過擬合的工作流,生成我們所需要的預測結果。

model.transform(test).select("id",  "text", "probability",  "prediction").show(false);
/**
    *控制臺輸出結果:
   +---+--------------+----------------------------------------+----------+
   |id |text          |probability                             |prediction|
   +---+--------------+----------------------------------------+----------+
   |4  |spark i j k   |[0.540643354485232,0.45935664551476796] |0.0       |
   |5  |l m n         |[0.9334382627383527,0.06656173726164716]|0.0       |
   |6  |spark a       |[0.1504143004807332,0.8495856995192668] |1.0       |
   |7  |apache  hadoop|[0.9768636139518375,0.02313638604816238]|0.0       |
   +---+--------------+----------------------------------------+----------+
**/

通過上述結果,我們可以看到,第4句和第6句中都包含”spark”,其中第六句的預測是1,與我們希望的相符;而第4句雖然預測的依然是0,但是通過概率我們可以看到,第4句有46%的概率預測是1,而第5句、第7句分別只有7%和2%的概率預測為1,這是由于訓練數據集較少,如果有更多的測試數據進行學習,預測的準確率將會有顯著提升。

參考資料: http://spark.apache.org/docs/latest/ml-pipeline.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,397評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,347評論 2 377