让 Q
成为Spark中的分布式行矩阵,我想计算 Q
的叉积及其转置 Q'
但是,虽然行矩阵确实有 multiply()
方法,但它只能接受本地矩阵作为参数。
代码插图(Scala):
val phi = new RowMatrix(phiRDD) // phiRDD is an instance of RDD[Vector]
val phiTranspose = transposeRowMatrix(phi) // transposeRowMatrix()
// returns the transpose of a RowMatrix
val crossMat = ? // phi * phiTranspose
请注意,我想执行 2 分布式RowMatrix 的点积,而不是具有本地点的分布式产品。
一种解决方案是使用IndexedRowMatrix
,如下所示:
val phi = new IndexedRowMatrix(phiRDD) // phiRDD is an instance of RDD[IndexedRow]
val phiTranspose = transposeMatrix(phi) // transposeMatrix()
// returns the transpose of a Matrix
val crossMat = phi.toBlockMatrix().multiply( phiTranspose.toBlockMatrix()
).toIndexedRowMatrix()
但是,我想使用行矩阵方法,例如 tallSkinnyQR()
,这意味着我使用crossMat
将.toRowMatrix()
变换为RowMatrix方法:
val crossRowMat = crossMat.toRowMatrix()
最后我可以申请
crossRowMat.tallSkinnyQR()
但是这个过程包括分布式矩阵类型之间的许多转换,根据我从MLlib Programming Guide的理解,这很昂贵:
选择正确的格式来存储大型和分布式矩阵非常重要。将分布式矩阵转换为不同的格式可能需要全局混洗,这非常昂贵。
请有人详细说明。
答案 0 :(得分:2)
只有支持矩阵 - 矩阵乘法的分布式矩阵才是BlockMatrices
。你必须相应地转换你的数据 - 人工指数足够好了:
new IndexedRowMatrix(
rowMatrix.rows.zipWithIndex.map(x => IndexedRow(x._2, x._1))
).toBlockMatrix match { case m => m.multiply(m.transpose) }
答案 1 :(得分:1)
我使用了这个page上列出的算法,它通过使用向量外积来将乘法问题从点积转移到分布式标量积问题:
两个载体之间的外部产物是该标记的标量积 第二个向量与第一个向量中的所有元素,导致 矩阵
我自己创建的行矩阵的乘法函数(可以更优化)就像那样。
def multiplyRowMatrices(m1: RowMatrix, m2: RowMatrix)(implicit ctx: SparkSession): RowMatrix = {
// Zip m1 columns with m2 rows
val m1Cm2R = transposeRowMatrix(m1).rows.zip(m2.rows)
// Apply scalar product between each entry in m1 vector with m2 row
val scalar = m1Cm2R.map{
case(column:DenseVector,row:DenseVector) => column.toArray.map{
columnValue => row.toArray.map{
rowValue => columnValue*rowValue
}
}
}
// Add all the resulting matrices point wisely
val sum = scalar.reduce{
case(matrix1,matrix2) => matrix1.zip(matrix2).map{
case(array1,array2)=> array1.zip(array2).map{
case(value1,value2)=> value1+value2
}
}
}
new RowMatrix(ctx.sparkContext.parallelize(sum.map(array=> Vectors.dense(array))))
}
之后我测试了两种方法 - 我自己的功能和使用块矩阵 - 在一台机器上使用300 * 10矩阵
使用我自己的功能:
val PhiMat = new RowMatrix(phi)
val TphiMat = transposeRowMatrix(PhiMat)
val product = multiplyRowMatrices(PhiMat,TphiMat)
使用矩阵变换:
val MatRow = new RowMatrix(phi)
val MatBlock = new IndexedRowMatrix(MatRow.rows.zipWithIndex.map(x => IndexedRow(x._2, x._1))).toBlockMatrix()
val TMatBlock = MatBlock.transpose
val productMatBlock = MatBlock.multiply(TMatBlock)
val productMatRow = productMatBlock.toIndexedRowMatrix().toRowMatrix()
第一种方法跨越 1个工作, 5个阶段,并且 2s 总计完成。虽然第二种方法跨越<强> 4个工作,三个一个阶段和一个阶段两个阶段,并且 0.323s 总共。另外,第二种方法在Shuffle读/写大小方面优于第一种方法。
然而,我仍然对MLlib Programming指南声明感到困惑:
选择正确的格式存储大型和非常重要 分布式矩阵。将分布式矩阵转换为不同的矩阵 格式可能需要全局洗牌,这非常昂贵。