Как восстановить исходную матрицу из компонентов SVD с помощью Spark
Я хочу восстановить (приближение) исходную матрицу, разложенную в SVD. Есть ли способ сделать это без необходимости конвертировать V factor
местный Matrix
в DenseMatrix
?
Вот декомпозиция на основе документации (обратите внимание, что комментарии взяты из примера документа)
import org.apache.spark.mllib.linalg.Matrix
import org.apache.spark.mllib.linalg.SingularValueDecomposition
import org.apache.spark.mllib.linalg.Vector
import org.apache.spark.mllib.linalg.distributed.RowMatrix
val data = Array(
Vectors.dense(1.0, 0.0, 7.0, 0.0, 0.0),
Vectors.dense(2.0, 0.0, 3.0, 4.0, 5.0),
Vectors.dense(4.0, 0.0, 0.0, 6.0, 7.0))
val dataRDD = sc.parallelize(data, 2)
val mat: RowMatrix = new RowMatrix(dataRDD)
// Compute the top 5 singular values and corresponding singular vectors.
val svd: SingularValueDecomposition[RowMatrix, Matrix] = mat.computeSVD(5, computeU = true)
val U: RowMatrix = svd.U // The U factor is a RowMatrix.
val s: Vector = svd.s // The singular values are stored in a local dense vector.
val V: Matrix = svd.V // The V factor is a local dense matrix.
Чтобы восстановить исходную матрицу, мне нужно вычислить U * diagonal(s) * transpose(V).
Первым делом нужно преобразовать вектор сингулярного значения. s
в диагональную матрицу S
,
import org.apache.spark.mllib.linalg.Matrices
val S = Matrices.diag(s)
Но когда я пытаюсь вычислить U * diagonal(s) * transpose(V): я получаю следующую ошибку.
val dataApprox = U.multiply(S.multiply(V.transpose))
Я получаю следующую ошибку:
ошибка: несоответствие типов; найдено: org.apache.spark.mllib.linalg.Matrix требуется: org.apache.spark.mllib.linalg.DenseMatrix
Это работает, если я конвертирую Matrix
V
к DenseMatrix
Vdense
import org.apache.spark.mllib.linalg.DenseMatrix
val Vdense = new DenseMatrix(V.numRows, V.numCols, V.toArray)
val dataApprox = U.multiply(S.multiply(Vdense.transpose))
Есть ли способ получить аппроксимацию оригинальной матрицы dataApprox
из вывода свд без этого преобразования?
1 ответ
Следующий код работал на меня
//numTopSingularValues=Features used for SVD
val latentFeatureArray=s.toArray
//Making a ListBuffer to Make a DenseMatrix for s
var denseMatListBuffer=ListBuffer.empty[Double]
val zeroListBuffer=ListBuffer.empty[Double]
var addZeroIndex=0
while (addZeroIndex < numTopSingularValues )
{
zeroListBuffer+=0.0D
addZeroIndex+=1
}
var addDiagElemIndex=0
while(addDiagElemIndex<(numTopSingularValues-1))
{
denseMatListBuffer+=latentFeatureArray(addDiagElemIndex)
denseMatListBuffer.appendAll(zeroListBuffer)
addDiagElemIndex+=1
}
denseMatListBuffer+=latentFeatureArray(numTopSingularValues-1)
val sDenseMatrix=new DenseMatrix(numTopSingularValues,numTopSingularValues,denseMatListBuffer.toArray)
val vMultiplyS=V.multiply(sDenseMatrix)
val postMulWithUDenseMat=vMultiplyS.transpose
val dataApprox=U.multiply(postMulWithUDenseMat)