SparkMllib基础及特征工程
1.Spark功能及应用场景
- SparkMllib的功能
- ML算法:包括了分类、回归、降维、协同过滤、聚类
- Featurization特征化:特征抽取、特征转换、特征降维、特征选择
- pipeline管道:tools for constructing,evaluating and tuning ML pipelines
- Persistence持久化 :模型的保存、读取、管道操作
- 工具Utilities:提供了线性代数、统计学以及数据处理工具
- SparkMllib的版本
- SparkCore数据抽象:RDD
- SparkSql数据抽象:dataframe
- SparkStreaming数据抽象化:DStream
- SparkMllib数据抽象:RDD和DataFrame的抽象
- DataFrame实现sql以及一些语言的统一的接口
- DataFrame提供了一套更加友好的API
- DataFrame可以实现PipeLine的管道操作。
- SparkMllib的架构
- MLlib是Spark机器学习库,它是MLBase的一部分,MLBase一共分为一下4部分:
- MLRunTime:
- 是基于Spark计算框架,将Spark的分布式计算应用到机器学习领域。
- MLlib:
- Spark实现一些常见的机器学习算法和实用程序。
- MLI:
- 是一个进行特征提取的和高级ML编程抽象的算法实现的API平台。
- ML Optimizer:
- 会选择它认为最适合的已经在内部实现好了的机器学习算法和相关参数来处理用户输入的数据,并返回模型或者其他的帮助分析结果。
- MLRunTime:
- 算法架构如下:
- 底层实现
- 主要包括Spark的运行库、矩阵库和向量库。其中向量接口和矩阵接口基于Nelib和BLAS/LAPACK开发的线性代数库Breeze。MLlib支持本地的密集向量和本地向量,并且支持标量向量;同时支持本地矩阵和分布式矩阵,分布式矩阵分为:RowMatrix、IndexedRowMatrix和CoordinateMatrix等。
- 算法库
- 包含广义线性模型、推荐系统、聚类、决策树和评估的算法;
- 底层实现
- MLlib是Spark机器学习库,它是MLBase的一部分,MLBase一共分为一下4部分:
- SparkMllib基于RDD的API和DataFrame的API的详解
- SparkMllib的环境搭建
- SParkSql实现RDD,DF,DS的转换
2.SparkMllib算法分类及应用场景
- 如何利用SparkMllib构建机器学习推荐架构
- 收集用户的行为数据信息和用户静态属性信息(人口统计学信息)
- 讲这些数据转化为特征(SparkMllib中特征工程的API进行转换)
- 模型训练,包括模型选择、训练、测试环节
- 将离线训练好的模型部署到在线模型服务中,用于离线和实时的处理
- 通过推荐得到结果在目标页面进行展示,并且返回的一些结果还可以使用其作为营销的重点。
- SparkMllib支持的哪些分类算法及应用
- 分类问题:离散值的预测的监督学习问题:垃圾邮件的分类、商品点击分类
- Logistic regression:逻辑回归
- Binomial logistic regression:二项逻辑回归
- Multinomial logistic regression:多项逻辑斯蒂回归
- Decision tree classifier:决策树分类算法
- Random forest classifier:随机森林分类算法
- Gradient-boosted tree classifier:GBDT算法(梯度增加树分类)
- Linear Support Vector Machine:线性支持向量机
- Naive Bayes:朴素贝叶斯
- Logistic regression:逻辑回归
- 分类问题:离散值的预测的监督学习问题:垃圾邮件的分类、商品点击分类
- SparkMllib支持的哪些回归算法及应用
- 回归问题:连续值的预测的监督学习问题:房价预测、成熟度的预测
- Lasso regression:Lasso 回归
- Ridge regression:Ridge 回归
- Linear Regression:线性回归
- Decision tree regression:决策树回归
- Random forest regression:随机森林回归
- Gradient-boosted tree regression:GDBT回归(梯度增加树回归)
- SparkMllib支持的哪些聚类算法及应用
- 聚类问题:将相似性较高的样本进行聚类,相似性较高的样本数据聚集在一个组或蔟中,相似性不高的样本数据聚集在不同的组或蔟中
- K-means:KMeans聚类
- Latent Dirichlet allocation:LDA聚类(潜在狄利克雷分布)
- Gaussian Mixture Model:GMM聚类(高斯混合模型)
- SparkMllib支持的哪些推荐系统算法及应用
- 关联分析:FPGrowth算法:啤酒和尿布的故事
- 推荐算法:基于模型的协同过滤算法ALS(alternating least squares:交替最小二乘法)算法
3.SparkMllib基础数据类型
-
标量:常量
-
本地向量
-
稀疏性向量:只存储非0值
-
稠密性向量:所有值都存储
-
用途:对比机器学习中特征向量
-
import org.apache.spark.mllib.linalg import org.apache.spark.mllib.linalg.Vectors /** * 本地向量主要两种类型构成----sparse稀疏性数据(只记录非0值,节省存储空间)------dense稠密性数据集 * (9,5,2,7)---(9,5,2,7) * (9,5,2,7)---(4,位置(0,1,2,3)(9,5,2,7)) * (9,5,0,2,7)---(5,位置(0,1,2,4)(9,5,2,7)) */ object localVector2 { def main(args: Array[String]): Unit = { val data: linalg.Vector = Vectors.dense(9,5,2,7) println(data) println(data(3)) val data1: linalg.Vector = Vectors.sparse(4,Array(0,1,2,3),Array(9,5,2,7)) println(data1) println(data1(0)) println(data1(2)) // 这个方法构造向量的时候需要注意的是,向量的值一定要是Double类型,否者会报错的哦。 val data2: linalg.Vector = Vectors.sparse(5,Seq((0,9.0),(1,5.0),(2,2.0),(4,7.0))) println(data2) println(data2(0)) println(data2(2)) } }
-
-
标签向量
-
import org.apache.spark.mllib.linalg import org.apache.spark.mllib.linalg.Vectors import org.apache.spark.mllib.regression.LabeledPoint /** * 机器学习中:特征(向量or矩阵)+类别标签列(标签向量labelpoint) * 要构造出下面两个标签向量 * (1.0,[2.0,0.0,6.0]):特征向量需要使用的是稠密性向量 * (2.0,(5,[0,1,2,3],[9.0,5.0,2.0,7.0])):特征向量的钩爪使用的是稀疏性向量 */ object labelpointVector2 { def main(args: Array[String]): Unit = { // 1. 创建出本地向量 val feature: linalg.Vector = Vectors.dense(2,0,6) // 2. 通过标签,本地向量构建标签向量 val label = LabeledPoint(1.0,feature) // 3. 打印标签向量 println(label) // 创建稀疏性向量 val vector2: linalg.Vector = Vectors.sparse(5,Array(0,1,2,3),Array(9,5,2,7)) // 通过标签,本地向量构建标签向量 val label2 = LabeledPoint(2,vector2) // 打印标签向量 println(label2) // 打印标签向量对应的类 println(label2.getClass) // 打印标签向量的标签 println(label2.label) // 获取标签向量的特征 val getFeature: linalg.Vector = label2.features // 打印特征 println(getFeature) // 获取特征向量中的索引是4对应的值 println(getFeature(4)) } }
-
libsvm:数据类型:存储稀疏性数据:引入SparkContext,使用的是
MLUtils.loadLibSVMFile
-
-
本地矩阵
-
import org.apache.spark.mllib.linalg.{Matrices, Matrix} /** * 矩阵---维度2维度----具有整数类型的行和列索引和double类型的数值,存储在单机上 * Mllib中支持密集型矩阵,存储方式以列为主 * 非0值的存储以列主要顺序并且以CSC的压缩方式进行压缩存放 */ object localmatrix1 { def main(args: Array[String]): Unit = { // 1. 构建稠密型矩阵,通过稠密性向量来构建 // (numRows: Int, numCols: Int, values: Array[Double])第一个参数表示矩阵的行数,第二个参数表示矩阵的列数 // 第三个参数表示稠密型向量,注意因为是稠密型向量,向量中元素的个数要等于矩阵中元素的个数 val dense: Matrix = Matrices.dense(3, 2, Array(1.0, 3.0, 5, 2, 4, 6)) // 构建稀疏型的矩阵,下面是我对稀疏性矩阵的理解。 // numRows: Int,第一个参数代表的是矩阵的行数,例子中一共是3行 // numCols: Int,第二个参数代表的是矩阵的列数,例子中一共是2列 // colPtrs: Array[Int],第三个参数,数组中的每一个元素代表每一列及其前几列总元素的个数,为什么2列,却有3个列值,因为默认第一个元素的值是0 // 第二个元素表示矩阵第一列中非0值的个数,这里第一列有一个元素是非0的,故第二个元素为1, // 第三个元素代表得是矩阵第二列非0值得个数+第一列非0值的个数,这个第二列非0的个数为2,所以第三个元素是3 // rowIndices: Array[Int],表示各个非0值元素所在行,下标从0开始,有多少个非0值元素,就有多少个小标。 // values: Array[Double]),表示各个元素的值。 val spare: Matrix = Matrices.sparse(3, 2, Array(0, 1, 3), Array(0, 2, 0), Array(9, 6, 8)) println(dense) /* 1.0 2.0 3.0 4.0 5.0 6.0 */ println(dense(2,0))//5 println(spare) /* 3 x 2 CSCMatrix (0,0) 9.0 (2,1) 6.0 (0,1) 8.0 */ //println(spare(2,1))//6 // 自己推导以下下面稀疏型矩阵的构成,是否跟上面的理解一致。 val spare1: Matrix = Matrices.sparse(3, 3, Array(0, 1, 3,4), Array(0, 2, 0,0), Array(9, 6, 8,33)) println(spare1) /* 3 x 3 CSCMatrix (0,0) 9.0 (2,1) 6.0 (0,1) 8.0 (0,2) 33.0 */ } }
-
-
分布式矩阵
-
分布式矩阵由长整型行列索引和双精度浮点型值数据组成,分布式存储在一个或多个RDD中,对于巨大的分布式矩阵来说,选择正确的存储格式非常重要,将一个分布式矩阵转化为另外一个不同格式需要混洗(shuffle),其代价很高。在MLlib实现了三类分布式矩阵存储格式,分别是行矩阵(RowMatrix)、行索引矩阵(IndexedRowMatrix)、三元组矩阵(CoordinateMatrix)和分块矩阵(BlockMatrix)等四种。
-
RowMatrix:行矩阵
- 行矩阵
RowMatrix
是最基础的分布式矩阵类型。每行是一个本地向量,行索引无实际意义(即无法直接使用)。数据存储在一个由行组成的RDD中,其中每一行都使用一个本地向量来进行存储。由于行是通过本地向量来实现的,故列数(即行的维度)被限制在普通整型(integer
)的范围内。在实际使用时,由于单机处理本地向量的存储和通信代价,行维度更是需要被控制在一个更小的范围之内。RowMatrix
可通过一个RDD[Vector]
的实例来创建。
- 行矩阵
-
IndexedRowMatrix:列矩阵
- 索引行矩阵
IndexedRowMatrix
与RowMatrix
相似,但它的每一行都带有一个有意义的行索引值,这个索引值可以被用来识别不同行,或是进行诸如join之类的操作。其数据存储在一个由IndexedRow
组成的RDD里,即每一行都是一个带长整型索引的本地向量。
- 索引行矩阵
-
import org.apache.spark.mllib.linalg import org.apache.spark.mllib.linalg.Vectors import org.apache.spark.mllib.linalg.distributed.{IndexedRow, IndexedRowMatrix, RowMatrix} import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /** * 基础的分布式矩阵--将矩阵存储起来了,不能按照行号访问 */ object RowMatrixTest2 { def main(args: Array[String]): Unit = { val conf: SparkConf = new SparkConf().setMaster("local[*]").setAppName("RowMatrixTest2") val sc: SparkContext = new SparkContext(conf) // 1. 创建稠密型向量 val vec1: linalg.Vector = Vectors.dense(1,2,3) val vec2: linalg.Vector = Vectors.dense(4,5,6) // 2.构建RowMatrix val rddvec: RDD[linalg.Vector] = sc.parallelize(Seq(vec2, vec2)) val rowMatrix = new RowMatrix(rddvec) // 3. 打印rowMatrix中的元素 rowMatrix.rows.foreach(println) // [4.0,5.0,6.0] // [4.0,5.0,6.0] // 4. 构建IndexedRow对象 val row1: IndexedRow = IndexedRow(1,vec1) val row2: IndexedRow = IndexedRow(2, vec2) // 5. 通过sc.parallelize构建rdd val input: RDD[IndexedRow] = sc.parallelize(Seq(row1, row2)) // 如果直接敲类名,idea没有提示导包,说明这个类没有apply方法,前面加上new后就能自动导包了。 // 构建IndexedRowMatrix val indexedMatrix = new IndexedRowMatrix(input) indexedMatrix.rows.foreach(println) // IndexedRow(1,[1.0,2.0,3.0]) // IndexedRow(2,[4.0,5.0,6.0]) } }
-
坐标矩阵:Coordinate Matrix
-
坐标矩阵
CoordinateMatrix
是一个基于矩阵项构成的RDD的分布式矩阵。每一个矩阵项MatrixEntry
都是一个三元组:(i: Long, j: Long, value: Double)
,其中i
是行索引,j
是列索引,value
是该位置的值。坐标矩阵一般在矩阵的两个维度都很大,且矩阵非常稀疏的时候使用。 -
CoordinateMatrix
实例可通过RDD[MatrixEntry]
实例来创建,其中每一个矩阵项都是一个(rowIndex, colIndex, elem)的三元组: -
import org.apache.spark.mllib.linalg.distributed.{CoordinateMatrix, MatrixEntry} import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} object CoorinaterMatrixTest1 { def main(args: Array[String]): Unit = { //三元组矩阵(coordinateMatrix):是一个分布式矩阵,其实体集合是一个RDD,每一个实体是一个(i:Long,j:Ling,value:Double)三元组 //其中i代表行索引,j代表列索引,value代表实体值 //三元组矩阵常用于表示稀疏性比较高的计算中,是由RDD[MatrixEntry]来构建的。 val conf = new SparkConf().setMaster("local[*]").setAppName("RowMatrixTest") val sc = new SparkContext(conf) // 创建两个矩阵项ent1和ent2,每一个矩阵项都是由索引和值构成的三元组 val ent1 = new MatrixEntry(0,1,0.5) val ent2 = new MatrixEntry(2,2,1.8) // 创建RDD[MatrixEntry] val entries : RDD[MatrixEntry] = sc.parallelize(Array(ent1,ent2)) // 通过RDD[MatrixEntry]创建一个坐标矩阵 val coordMat: CoordinateMatrix = new CoordinateMatrix(entries) //打印 coordMat.entries.foreach(println) // MatrixEntry(0,1,0.5) // MatrixEntry(2,2,1.8) // 将coordMat进行转置 val transMat: CoordinateMatrix = coordMat.transpose() transMat.entries.foreach(println) /* MatrixEntry(1,0,0.5) MatrixEntry(2,2,1.8)*/ // 将坐标矩阵转换成一个索引行矩阵 val indexedRowMatrix = transMat.toIndexedRowMatrix() indexedRowMatrix.rows.foreach(println) // IndexedRow(1,(3,[0],[0.5])) // IndexedRow(2,(3,[2],[1.8])) } }
-
-
分块矩阵(Block Matrix)
-
分块矩阵是基于矩阵块
MatrixBlock
构成的RDD的分布式矩阵,其中每一个矩阵块MatrixBlock
都是一个元组((Int, Int), Matrix)
,其中(Int, Int)
是块的索引,而Matrix
则是在对应位置的子矩阵(sub-matrix),其尺寸由rowsPerBlock
和colsPerBlock
决定,默认值均为1024。分块矩阵支持和另一个分块矩阵进行加法操作和乘法操作,并提供了一个支持方法validate()
来确认分块矩阵是否创建成功。 -
分块矩阵可由索引行矩阵
IndexedRowMatrix
或坐标矩阵CoordinateMatrix
调用toBlockMatrix()
方法来进行转换,该方法将矩阵划分成尺寸默认为1024×1024的分块,可以在调用toBlockMatrix(rowsPerBlock, colsPerBlock)
方法时传入参数来调整分块的尺寸。 -
import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} object BlockMatrixTest1 { def main(args: Array[String]): Unit = { //分块矩阵:BlockMatrix是支持矩阵分块RDD的分布式矩阵,其中矩阵分块由((int,int),matrix)元祖所构成 //(int,int)是该部分矩阵所处的矩阵的索引位置,Matrix表示该索引位置上的子矩阵 //分块矩阵支持矩阵加法和乘法,并设有辅助函数验证用于检查矩阵是否设置正确。 val conf = new SparkConf().setMaster("local[*]").setAppName("RowMatrixTest") val sc = new SparkContext(conf) import org.apache.spark.mllib.linalg.distributed.{BlockMatrix, CoordinateMatrix, MatrixEntry} // 创建8个矩阵项,每一个矩阵项都是由索引和值构成的三元组 val ent1 = new MatrixEntry(0,0,1) val ent2 = new MatrixEntry(1,1,1) val ent3 = new MatrixEntry(2,0,-1) val ent4 = new MatrixEntry(2,1,2) val ent5 = new MatrixEntry(2,2,1) val ent6 = new MatrixEntry(3,0,1) val ent7 = new MatrixEntry(3,1,1) val ent8 = new MatrixEntry(3,3,1) // 创建RDD[MatrixEntry] val entries : RDD[MatrixEntry] = sc.parallelize(Array(ent1,ent2,ent3,ent4,ent5,ent6,ent7,ent8)) // 通过RDD[MatrixEntry]创建一个坐标矩阵 val coordMat: CoordinateMatrix = new CoordinateMatrix(entries) // 将坐标矩阵转换成2x2的分块矩阵并存储,尺寸通过参数传入 val matA: BlockMatrix = coordMat.toBlockMatrix(2,2).cache() // 可以用validate()方法判断是否分块成功 matA.validate() println(matA.toLocalMatrix) // 1.0 0.0 0.0 0.0 // 0.0 1.0 0.0 0.0 // -1.0 2.0 1.0 0.0 // 1.0 1.0 0.0 1.0 // 查看其分块情况 println(matA.numColBlocks)//2 println(matA.numRowBlocks)//2 // 计算矩阵A和其转置矩阵的积矩阵 val ata = matA.transpose.multiply(matA) println(ata.toLocalMatrix) /* 3.0 -1.0 -1.0 1.0 -1.0 6.0 2.0 1.0 -1.0 2.0 1.0 0.0 1.0 1.0 0.0 1.0*/ } }
-
-