数据类型
MLlib
既支持保存在单台机器上的本地向量和矩阵,也支持备份在一个或多个RDD
中的分布式矩阵。本地向量和本地矩阵是简单的数据模型,作为公共接口提供。底层的线性代数操作通过Breeze和jblas提供。 在MLlib
中,用于有监督学习的训练样本称为标注点(labeled point
)。 # 本地向量(Local vector)
一个本地向量拥有从0开始的integer
类型的索引以及double
类型的值,它保存在单台机器上面。MLlib
支持两种类型的本地向量:稠密(dense
)向量和稀疏(sparse
)向量。 一个稠密向量通过一个double
类型的数组保存数据,这个数组表示向量的条目值(entry values
);一个稀疏向量通过两个并行的数组(indices和values
)保存数据。例如,一个向量 (1.0, 0.0, 3.0)
可以以稠密的格式保存为[1.0, 0.0, 3.0]
或者以稀疏的格式保存为(3, [0, 2], [1.0, 3.0])
,其中3表示数组的大小。
本地向量的基类是Vector,Spark
提供了两种实现: DenseVector和SparseVector。 Spark
官方推荐使用Vectors中实现的工厂方法去创建本地向量。下面是创建本地向量的例子。
1 | import org.apache.spark.mllib.linalg.{Vector, Vectors} |
注意,Scala
默认引入scala.collection.immutable.Vector
,这里我们需要主动引入MLLib
中的org.apache.spark.mllib.linalg.Vector
来操作。我们可以看看Vectors
对象的部分方法。
1 | def dense(firstValue: Double, otherValues: Double*): Vector = |
标注点(Labeled point)
一个标注点就是一个本地向量(或者是稠密的或者是稀疏的),这个向量和一个标签或者响应相关联。在MLlib
中,标注点用于有监督学习算法。我们用一个double
存储标签,这样我们就可以在回归和分类中使用标注点。 对于二分类,一个标签可能是0或者是1;对于多分类,一个标签可能代表从0开始的类别索引。
在MLlib
中,一个标注点通过样本类LabeledPoint表示。
1 | "0.8.0") ( |
下面是使用LabeledPoint
的一个例子。
1 | import org.apache.spark.mllib.linalg.Vectors |
在现实的应用中,训练数据是稀疏的情况非常常见,MLlib
支持读取训练数据存储为LIBSVM
格式。它是LIBSVM和LIBLINEAR默认的格式。 它是一种文本格式,每一行表示一个标注的稀疏特征向量,如下所示:
1 | label index1:value1 index2:value2 ... |
本地矩阵(Local matrix)
一个本地矩阵拥有Integer
类型的行和列索引以及Double
类型的值。MLlib
支持稠密矩阵和稀疏矩阵两种。稠密矩阵将条目(entry
)值保存为单个double
数组,这个数组根据列的顺序存储。 稀疏矩阵的非零条目值保存为压缩稀疏列(Compressed Sparse Column ,CSC
)格式,这种格式也是以列顺序存储。例如下面的稠密矩阵:
这个稠密矩阵保存为一维数组[1.0, 3.0, 5.0, 2.0, 4.0, 6.0]
,数组大小为(3,2)
。
本地矩阵的基类是Matrix,它提供了两种实现:DenseMatrix和SparseMatrix。 推荐使用Matrices的工厂方法来创建本地矩阵。下面是一个实现的例子:
1 | import org.apache.spark.mllib.linalg.{Matrix, Matrices} |
稠密矩阵的存储很简单,不赘述。稀疏矩阵的存储使用CSC
。关于压缩矩阵的介绍,请参看文献【1】。
分布式矩阵(Distributed matrix)
一个分布式矩阵拥有long
类型的行和列索引,以及double
类型的值,分布式的存储在一个或多个RDD
中。选择正确的格式存储大型分布式矩阵是非常重要的。将一个分布式矩阵转换为另外一个格式可能需要一个全局的shuffle
,这是非常昂贵的。 到目前为止,已经实现了三种类型的分布式矩阵。
基本的类型是RowMatrix
,RowMatrix
是一个面向行的分布式矩阵,它没有有意义的行索引。它的行保存为一个RDD
,每一行都是一个本地向量。我们假设一个RowMatrix
的列的数量不是很巨大,这样单个本地向量可以方便的和driver
通信,也可以被单个节点保存和操作。 IndexedRowMatrix
和RowMatrix
很像,但是它拥有行索引,行索引可以用于识别行和进行join
操作。CoordinateMatrix
是一个分布式矩阵,它使用COO
格式存储。请参看文献【1】了解COO
格式。
RowMatrix
RowMatrix
是一个面向行的分布式矩阵,它没有有意义的行索引。它的行保存为一个RDD
,每一行都是一个本地向量。因为每一行保存为一个本地向量,所以列数限制在了整数范围。
一个RowMatrix
可以通过RDD[Vector]
实例创建。创建完之后,我们可以计算它的列的统计和分解。QR分解的形式为A=QR
,其中Q
是一个正交矩阵, R
是一个上三角矩阵。下面是一个RowMatrix
的例子。
1 | import org.apache.spark.mllib.linalg.Vector |
IndexedRowMatrix
IndexedRowMatrix
和RowMatrix
很像,但是它拥有行索引。索引的行保存为一个RDD[IndexedRow]
,其中IndexedRow
是一个参数为(Long, Vector)
的样本类,所以每一行通过它的索引以及一个本地向量表示。
一个IndexedRowMatrix
可以通过RDD[IndexedRow]
实例创建,并且一个IndexedRowMatrix
可以通过去掉它的行索引,转换成RowMatrix
。下面是一个例子:
1 | import org.apache.spark.mllib.linalg.distributed.{IndexedRow, IndexedRowMatrix, RowMatrix} |
IndexedRow
这个样本类的代码如下:
1 | case class IndexedRow(index: Long, vector: Vector) |
CoordinateMatrix
CoordinateMatrix
是一个分布式矩阵,它的条目保存为一个RDD
。每一个条目是一个(i: Long, j: Long, value: Double)
格式的元组,其中i
表示行索引,j
表示列索引,value
表示条目值。 CoordinateMatrix
应该仅仅在矩阵维度很大并且矩阵非常稀疏的情况下使用。
CoordinateMatrix
可以通过RDD[MatrixEntry]
实例创建,其中MatrixEntry
是(Long, Long, Double)
的包装。CoordinateMatrix
可以转换成IndexedRowMatrix
。下面是一个例子:
1 | import org.apache.spark.mllib.linalg.distributed.{CoordinateMatrix, MatrixEntry} |
MatrixEntry
这个样本类的代码如下:
1 | case class MatrixEntry(i: Long, j: Long, value: Double) |
BlockMatrix
BlockMatrix
是一个分布式矩阵,它的保存为一个MatrixBlocks
的RDD
。MatrixBlock
是一个((Int, Int), Matrix)
类型的元组,其中(Int, Int)
代表块的索引,Matrix
代表子矩阵。 BlockMatrix
支持诸如add
和multiply
等方法。BlockMatrix
还有一个帮助方法validate
,用来判断一个BlockMatrix
是否正确的创建。
可以轻松的通过调用toBlockMatrix
从一个IndexedRowMatrix
或者CoordinateMatrix
创建一个BlockMatrix
。toBlockMatrix
默认创建1024 * 1024
大小的块,用户可以手动修个块的大小。 下面是一个例子:
1 | import org.apache.spark.mllib.linalg.distributed.{BlockMatrix, CoordinateMatrix, MatrixEntry} |