阅读难度:★★★☆☆
阅读时长:10min
Python可以用来对较少样本进行机器学习建模,当需要训练大规模数据集时,单机配置已不可能满足大规模数据计算的内存要求。Spark采用分布式内存计算,能够高效快速地对大规模数据进行复杂运算,scala是Spark的原生语言,但同时也提供python API,即pyspark。
spark原本也有MLlib机器学习库,但是相比ML Pipeline操作繁琐的多,所以这里直接介绍ML Pipeline。
使用pyspark ML pipeline构建机器学习流程非常简单,初学可以先不急着建模,而是先捋清楚流程和概念。
构建ML Pipeline机器学习流程
(1)数据准备: 将特征值和预测变量整理成DataFrame
(2)建立机器学习流程Pipeline:
- StringIndexer:将文字分类特征转化为数字
- OneHotEncoder:将数字分类特征转化为稀疏向量
- VectorAssembler:将所有特征字段整合成一个Vector字段
- DecisionTreeClassfier:训练生成模型
(3)训练:训练集使用pipeline.fit()进行训练,产生pipelineModel
(4)预测:使用pipelineModel.transform()预测测试集,产生预测结果
Spark ML Pipeline名词理解
Pyspark中的一些组件跟Python中的同名组件有相似也有不同的地方,需要重新认识一下,以便于后面理解代码逻辑。
(1)DataFrame: 是Spark ML机器学习API处理的数据格式,可以由文本文件、RDD、或者Spark SQL创建,与python 的Dataframe概念相近但是方法完全不同。
(2)Transformer:是一个算法,可以使用.transform方法将一个DataFrame转换成另一个DataFrame。
(3)Estimator:是一个算法,可以使用.fit方法传入DataFrame,生成一个Transformer。
(4)pipeline:可以串联多个Transformer和Estimator建立ML机器学习的工作流。
(5)Parameter:以上Transformer和Estimator都可以共享的参数API。
好了,搓一搓小手,准备码代码来理解上面概念的涵义。
数据准备
1、导入数据生成Dataframe
这里原始数据是一个csv文件,直接读就好,如果数据存在于数仓,则使用Spark SQL直接拉取数据。
import pyspark
from pyspark.sql import SparkSession
from pyspark.sql import SQLContext
spark = SparkSession.builder.getOrCreate()
sc = spark.sparkContext
#代码逐行注释如下:
#指定为csv格式
#指定第一行是字段名
#指定字段的分隔符是\t
#指定要加载的文件
row_df=spark.read.format('csv')\
.option('header','true')\
.option('delimiter','\t')\
.load('data/train.tsv')
#备注:再企业线上环境可以用row_df=spark.sql("""select * from ***""")直接从数仓表中获取数据
输入row_df.count()
可以查看数据行数,
输入row_df.printSchema()
查看摘要,发现数据全部为string格式
输入以下代码获取前10行记录,发现有取值=“?”的。
row_df.select('url','alchemy_category','alchemy_category_score','is_news','label').show(10)
2、数据清洗与处理
row_df中存在取值为“?”,我们需要编写UDF把“?”转化成“0”:
(1)自定义python函数replace_question(x)将?转成0
(2)使用udf方法将replace_question转化成DataFrame UDF
(3)将string转化成double,以便于计算操作
from pyspark.sql.functions import udf
from pyspark.sql.functions import col
def replace_question(x):
return('0' if x=='?' else x)
replace_question=udf(replace_question)
df=row_df.select(
['url','alchemy_category']+
[replace_question(col(column)).cast('double').alias(column)
for column in row_df.columns[4:]]
)
# 输出可见所选列已经转化成double类型
df.printSchema()# 查看摘要
# 输出可见所选列已经转化成0
df.select('url','alchemy_category','alchemy_category_score','is_news','label').show(10)
看到已经数据类型已经转化为double啦~
选取列取值为“?”的地方也已经转成0啦~
3、将数据分成train_df和test_df
使用DataFrame的.randomSplit方法随机将数据集按照7:3切分,并且用.cache()暂存在内存中,以加快后续程序运行的速度。
train_df,test_df=df.randomSplit([0.7,0.3])
train_df.cache()
test_df.cache()
机器学习pipeline流程的组件
机器学习流程Pipeline过程中需要使用一些组件,为了弄清楚这些组件的含义和使用方法,不妨单独进行一番探索。
1、StringIndexer:将文字分类特征转化为数字
alchemy_category列的取值是网页的文章类别,无法直接转成数字类型,因此需要运用StringIndexer组件将类别进行编号。
使用方法:
(1)使用.fit方法传入参数DataFrame,产生一个Transformer
(2)针对生成的Transformer,使用.tranform方法将DataFrame转换为另一个DataFrame
from pyspark.ml.feature import StringIndexer
categoryIndexer=StringIndexer(
inputCol='alchemy_category',
outputCol='alchemy_category_index')
categoryTransformer=categoryIndexer.fit(df)
#使用categoryTransformer转换train_df
df1=categoryTransformer.transform(train_df)
df1.select('url','alchemy_category','alchemy_category_index','alchemy_category_score','is_news','label').show(10)
如图所示,alchemy_category_index列即为类别对应的编号值,取值范围从0开始。
2、OneHotEncoder:将数字分类特征进行独热编码
光把类别转换成对应的数字编号还不够,算法还要求将类别转成稀疏向量,需使用OneHotEncoder组件进行独热编码。
使用方法:
(1)创建OneHotEncoder,传入下列参数:
- dropLast设置为False
- inputCol是要转换的字段名
- outputCol是转换后产生的字段名
(2)使用.transform转换
from pyspark.ml.feature import OneHotEncoder
encoder=OneHotEncoder(dropLast=False,
inputCol='alchemy_category_index',
outputCol='alchemy_category_vec')
df2=encoder.transform(df1)
df2.select('url','alchemy_category','alchemy_category_index','alchemy_category_vec','alchemy_category_score','is_news','label').show(10)
表中(14,[3],[1.0]) 是一个稀疏向量,表示共14个字段,从0开始算起第3个是1,其余是0, 即:[0,0,0,1,0,0,0,0,0,0,0,0,0]
3、VectorAssembler:将多个特征字段整合成一个特征的Vector
Spark机器学习要求所有特征值必须整合成一个稀疏向量进入算法中, VectorAssembler组件就是按照列顺序,不论分类变量还是连续变量全部整合到一个稀疏向量。
使用方法:
(1)创建全部特征字段名的assemblerInputs
(2)创建VectorAssembler,传入下列参数:
- inputCols是要整合的所有字段名assemblerInputs
- outputCol是转换后产生的字段名features
(3)使用.transform方法转换
from pyspark.ml.feature import VectorAssembler
assemblerInputs=['alchemy_category_vec']+row_df.columns[4:-1]
assembler=VectorAssembler(
inputCols=assemblerInputs,
outputCol='features')
df3=assembler.transform(df2)
#查看发现新增了features字段
print(df3.columns)
#查看features特征的取值
df3.select('features').take(1)
df3相比之前多了一个feature列,features的取值是一个稀疏矩阵的数据格式,一共36个字段, 第0个字段是1,第15个字段是2.1852,……没有标注列序号的其他字段取值都是0。
从上面的代码我们也可以看到,StringIndexer是一个Estimator,OneHotEncoder和VectorAssembler是Transformer,前者可以使用.fit()生成Transformer,后者通过.transform()方法生成新的DataFrame。
至此,就已经得到了机器学习算法所需要的数据格式,我们可以小试牛刀跑一个决策树看看(不过之后不会用这个方法一一运行组件,我们会用更简洁的pipeline进行流式处理)。
4、构造决策树算法
在之前的步骤中,我们已经准备好了数据:feature与label字段。
接下来就可以使用DecisionTreeClassifier执行二元分类了。
DecisionTreeClassifier也是一个Estimator,所以使用上也有两个步骤:
(1).fit训练产生DecisionTree模型
(2).tranform进行转换预测结果
from pyspark.ml.classification import DecisionTreeClassifier
#生成模型
dt=DecisionTreeClassifier(labelCol='label',\
featuresCol='features',\
impurity='gini',\
maxDepth=10,maxBins=14)
dt_model=dt.fit(df3)
#使用生成的模型进行转换
df4=dt_model.transform(df3)
df4.printSchema()
输出的DataFrame摘要如下:
本篇初步认识Pyspark机器学习的基础概念和使用方法,为下一篇完整学习一个Pyspark ML Pipeline机器学习流程做知识准备。