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。
    

你可能感兴趣的:(spark,Python,机器学习)