本文为销量预测第1篇PySpark与DataFrame简介
第2篇:PySpark时间序列数据统计描述,分布特性与内部特性
第3篇:缺失值填充与异常值处理
第4篇:时间序列特征工程
第5篇:特征选择
第6篇:简单预测模型
第7篇:线性回归与广义线性模型
第8篇:机器学习调参方法
第9篇:销量预测建模中常用的损失函数与模型评估指标
相对于MapReduce等其他大数据处理平台,Apache Spark拥有诸多优势。其中,比较突出的两项优势是快速运行和快速写入能力。Spark引擎可以执行更为常见的有向无环图(DAG),获得比在Hadoop平台上更好的批处理性能。Apache Spark拥有内存处理能力,并且使用了新的数据提取方法,即弹性分布式数据集(RDD),使得Apache Spark能够进行高度迭代计算和响应型编程,并且扩展了容错能力。同时,Apache Spark只需要几行简短的代码就可以使复杂任务以管道(pipeline)的方式进行处理,使得交互式数据挖掘和数据处理,变得更为容易。
在零售业的销量预测领域,销售小票数据动辄上一千万条,这个量级在单机版上进行机器学习颇具挑战性,所以,需要借助大数据利器——Spark,进行模型的分布式训练。
鉴于数据挖掘或分析人员,熟悉的编程语言为Python,所以本章介绍Spark的Python版——PySpark。本节先介绍必要的基础知识比如DataFrame和ML库,在后续章节中会给出基于Spark机器学习的特征生成/特征选择/超参数调优以及机器学习销量预测算法。
Spark作为一个快速通用的分布式计算平台,Spark核心和框架构建在 Scala 上,同时提供针对Scala、Java、Python和 R语言的API。用户编写的应用程序可充分利用Scala或Python语言进行实时交互编写的优势。不仅支持多语言,而且提供80+个高级API,包含了多种数据源的存储读取,计算,和成熟的类库支持,以及多种部署模式。用户可以轻松灵活的建构应用程序。Spark目前自带的分布式机器学习和数据挖掘工具包,其包括了常见的高质量、可扩展的算法计算任务,专为并行计算而设计。机器学习算法模型一般具有迭代式的特性,而这与Spark的设计目标一致。总的来说,目前市面上流行的并行计算的框架很多,Spark是其中为数不多,能兼顾速度、可扩展性、内存处理和容错性的同时,还提供丰富且灵活API的大数据并行计算架构。
Spark处理大数据具有以下优势:
1.计算速度快;
2.分布式并行处理大数据;
3.机器学习模块密切结合,从数据读取,计算,到存储,一体化集成解决;
4.灵活,支持多种数据源,可用多种语言,并且支持自定义udf函数。
在正式介绍Spark机器学习之前,先回顾一下Spark分布式计算架构的原理。
从图1的Spark架构图中可以看到,spark的执行过程:
用户程序创建 SparkContext 后,它会连接到集群资源管理器,集群资源管理器会为用户程序分配计算资源,并启动 Executor;
Dirver 将计算程序划分为不同的执行阶段和多个 Task,之后将 Task 发送给 Executor;
Executor 负责执行 Task,并将执行状态汇报给 Driver,同时也会将当前节点资源的使用情况汇报给集群资源管理器。
Spark 基于 Spark Core 扩展了四个核心组件,分别用于满足不同领域的计算需求。
其中,Spark SQL 主要用于结构化数据的处理,MLlib 是 Spark 的机器学习库,这二者是本章后面重点要讲解的内容。
从Spark 2.0开始,Spark机器学习API是基于DataFrame的Spark.ML ,而之前基于RDD的Spark.MLlib已进入维护模式,不再更新加入新特性。基于DataFrame的Spark.ML是在RDD的基础上进一步的封装,也是更强大且方便的机器学习API,对于已习惯Python机器学习库如sklearn等的读者,ML用起来会更加自然。
Spark.SQL 是 Spark 中的一个子模块,主要用于操作结构化数据,使得SQL 查询与 Spark 程序运行无缝结合,支持多达上百种的外部数据源,包括 Hive,Avro,Parquet,ORC,JSON 和 JDBC 等。
为了更好的支持并处理结构化数据,Spark SQL 提供了新的数据结构 DataFrame。DataFrame 是一个由具名列组成的数据集,内部有明确 Scheme 结构,即列名、列字段类型信息,在概念上等同于关系数据库中的表或 Python/R 语言中的 数据框(Data Frame)。其主要优点是Spark引擎在一开始就为其提供了性能优化。如果数据是结构化或半结构化,出于性能上的考虑,应优先使用DataFrame。
以上介绍了Spark.DataFrame的由来,那么如何得到一份Spark.DataFrame格式的数据呢?其实就是使用Spark读取数据的过程。接下来介绍几种常用的数据读取方法,并对每种数据读取方式的关键点加以说明。
from pyspark import SparkConf,SparkContext
from pyspark.sql import Row
conf = SparkConf().setMaster("local").setAppName("My App")
sc = SparkContext(conf = conf)
df = sc.parallelize([ \
Row(name='Alice', age=5, height=80), \
Row(name='Alice', age=5, height=80), \
Row(name='Alice', age=10, height=80)]).toDF()
#查看数据类型
df.dtypes
#[('age', 'bigint'), ('height', 'bigint'), ('name', 'string')]
查看df类型
type(df)
#class 'pyspark.sql.dataframe.DataFrame'>
可以将Spark.DataFrame视为关系数据表,在其上进行类似于SQL的操作,与平时建SQL表需要指定数据类型不同的是,Spark.DataFrame在新建时无需指定数据类型,此时数据列的类型是自动推断,这也是其强大之处。
from pyspark.sql import SparkSession
spark = SparkSession.builder \
.master("local") \
.appName("Test Create DataFrame") \
.config("spark.some.config.option", "some-value") \
.getOrCreate()
df = spark.read.csv('python/test_spark/ts_dataset.csv')
同理还可以读取parquet/json文件
df_parquet=spark.read.parquet('....')
df_json = spark.read.format('json').load('python/test_spark/ts_dataset.json')
以上两种方式中,第一种是Spark1.x版本中以RDD作为主要API的方式,第二种的SparkSession是随着spark2.x引入,封装了SparkContext、SparkConf、sqlContext等函数,为用户提供统一的接口使用Spark各项功能的更高级抽象的启动方式。
强调一点是,通过会话SparkSession读取出来的数据类型就是DataFrame,而第一种还需要在RDD的基础上使用toDF进行转换。如果当前读者使用的spark版本是2.0以上,推荐使用第二种方式。
from pyspark.sql import SparkSession
spark = SparkSession. \
Builder(). \
config("spark.sql.crossJoin.enabled", "true"). \
config("spark.sql.execution.arrow.enabled", "true"). \
enableHiveSupport(). \
getOrCreate()
df=spark.sql("""select regparam,fitIntercept, elasticNetParam from temp.model_best_param""")
这种类型和上文直接读取本地文件类似,Spark任务在创建时,默认支持Hive,可以直接访问现有的 Hive支持的存储格式。解释一下,Apache Hive是Hadoop上一种常见的结构化数据源,支持包含HDFS在内的多种存储系统上的表,由于实际工作中使用spark.sql读取数据操作的机会更多,也是spark最核心组件之一,所以这里重点讲解一些Spark.SQL。与Spark其他的组件一样,在使用的时候是需要提前引入Spark.SQL,但也无需依赖大量的包,如果需要把Spark.SQL连接到一个部署好的Hive上,则需要把hive-site.xml复制到spark的配置文件目录中,该部分内容请参考网络上其他的教程。以上代码中enableHiveSupport的调用使得SparkSession支持Hive。如果是Spark 1.x版本,则使用以下方式引用。
from pyspark.sql import HiveContext
hiveCtx=HiveContext(sc)
data=hiveCtx.sql("select regparam,fitIntercept, elasticNetParam from temp.model_best_para ")
既然使用python进行数据处理,尤其是结构化数据,那么pandas一定绕不开,所以学习和工作中经常会有把做过处理的pandas.DataFrame数据转换为Spark.DataFrame的诉求,Spark.DataFrame在设计之初就考虑到了这个问题,所以实现方式也相当简单。
import pandas as pd
df = pd.read_csv('python/test_spark/ts_dataset.csv')
#将pandas.Dataframe 转换成-->spark.dataFrame
spark_df=spark.createDataFrame(df)
#将spark.dataFrame 转换成--> pandas.Dataframe
pd_df = spark_df.toPandas()
以上将Spark.DataFrame 转换成–> pandas.Dataframe的过程,不建议对超过10G的数据执行该操作。一方面数据类型转换需要花费时间,另一方面,在单机版上把10G以上的数据读进内存并做处理是一件非常低效的事情。
本节开头介绍了Spark.DataFrame是从属于Spark.SQL的,Spark.SQL作为Spark最重要的组件,可以从各种结构化数据格式的数据源读取和写入,本节也展示了读取JSON/CSV等本地以及数据库中的数据。同时,Spark还允许用户通过Thrift的JDBC远程访问数据库。总的来说 Spark 通过Spark.SQL 、DataFrame更进一步用统一而简洁的API接口隐藏了分布式计算的复杂性。就开发速度和性能而言,DataFrame + SQL 无疑是大数据分析的最好选择。
通过Spark.DataFrame可以灵活的读取各种数据源,数据读取加载后就是对其进行处理了,下面介绍读取DataFrame格式的数据以后执行的一些简单的操作。
spark_df.show()
spark_df.printSchema()
spark_df.head(5)
df.count()
df.columns
ml_dataset=spark_df.select("features", "label")
from pyspark.sql.functions import *
#注意这个*号,这里是导入了sql.functions中所有的函数,所以下文的abs就是由此而来
df2 = spark_df.withColumn("abs_age", abs(df2.age))
df3= spark_df.drop("age")
df4= spark_df.where(spark_df["age"]>20)
以上只是简单的展示了一小部分最为常见的DataFrame操作,更详尽的内容请查阅官方文档或者其他参考资料。
以上介绍了与Spark.ML机器学习密切相关的数据类型和基本操作–Spark.DataFrame
犹如通过pandas.DataFrame对数据做加工,下面先大致介绍用这些处理过后的数据制作佳肴的过程–机器学习建模。
ML包括三个主要的抽象类:转换器(Transformer)、评估器(Estimator)和管道(Pipeline)。
转换器,顾名思义就是在原对象的基础上对DataFrame进行转换操作,比如常见的使用Spark.ml.feature对特征做归一化,分箱,降度,OneHot等处理,通过transform()
方法将一个DataFrame转换成另一个DataFrame。
评估器,评估器是用于机器学习诸如预测或分类等算法,训练一个DataFrame并生成一个模型。用fit方法拟合模型。
from pyspark.ml.feature import MinMaxScaler
#定义/引入转换类
max_min_scaler = MinMaxScaler(inputCol="age", outputCol="age_scaler")
#fit数据
max_min_age = max_min_scaler.fit(df)
#执行转换
max_min_age_=max_min_age.transform(spark_df)
管道(pipline)
管道这一概念同样受Python机器学习库Scikit-Learn的影响,采用一系列 API 定义并标准化机器学习工作流,可以将数据读取、特征加工、模型训练等一系列操作,构建一个管道pipline,实现端到端机器学习任务。
Spark机器学习部分其他的如特征生成,模型训练,模型保存,数据集划分/超参数调优,后面会以实际案例进行详细阐述。另外,随着Spark.3.0的发布,最新的ML相关简介请移步官网了解。