标量:常量
本地向量
稀疏性向量:只存储非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*/
}
}