7
votes

Comment calculer l'inverse d'une rowmatrix dans Apache Spark?

J'ai une matrice X, distribuée, dans la forme RowMatrix. J'utilise Spark 1.3.0. Je dois être capable de calculer x inverse.


1 commentaires

Un algorithme est décrit dans arxiv.org/pdf/1801.04723.pdf


3 Réponses :


8
votes
import org.apache.spark.mllib.linalg.{Vectors,Vector,Matrix,SingularValueDecomposition,DenseMatrix,DenseVector}
import org.apache.spark.mllib.linalg.distributed.RowMatrix

def computeInverse(X: RowMatrix): DenseMatrix = {
  val nCoef = X.numCols.toInt
  val svd = X.computeSVD(nCoef, computeU = true)
  if (svd.s.size < nCoef) {
    sys.error(s"RowMatrix.computeInverse called on singular matrix.")
  }

  // Create the inv diagonal matrix from S 
  val invS = DenseMatrix.diag(new DenseVector(svd.s.toArray.map(x => math.pow(x,-1))))

  // U cannot be a RowMatrix
  val U = new DenseMatrix(svd.U.numRows().toInt,svd.U.numCols().toInt,svd.U.rows.collect.flatMap(x => x.toArray))

  // If you could make V distributed, then this may be better. However its alreadly local...so maybe this is fine.
  val V = svd.V
  // inv(X) = V*inv(S)*transpose(U)  --- the U is already transposed.
  (V.multiply(invS)).multiply(U)
  }

0 commentaires

3
votes

J'ai eu des problèmes à l'aide de cette fonction avec l'option xxx pré>

Les rangées de Rowmatrix ont été mélangées. P>

Voici une mise à jour qui a fonctionné pour moi p>

import org.apache.spark.mllib.linalg.{DenseMatrix,DenseVector}
import org.apache.spark.mllib.linalg.distributed.IndexedRowMatrix

def computeInverse(X: IndexedRowMatrix)
: DenseMatrix = 
{
  val nCoef = X.numCols.toInt
  val svd = X.computeSVD(nCoef, computeU = true)
  if (svd.s.size < nCoef) {
    sys.error(s"IndexedRowMatrix.computeInverse called on singular matrix.")
  }

  // Create the inv diagonal matrix from S 
  val invS = DenseMatrix.diag(new DenseVector(svd.s.toArray.map(x => math.pow(x, -1))))

  // U cannot be a RowMatrix
  val U = svd.U.toBlockMatrix().toLocalMatrix().multiply(DenseMatrix.eye(svd.U.numRows().toInt)).transpose

  val V = svd.V
  (V.multiply(invS)).multiply(U)
}


0 commentaires

0
votes

matrice u retourné par x.computesvd a des dimensions mxk où m est le nombre de lignes de l'orthographe d'origine (distribué) RowMatrix X. On pourrait attendre m être grand (éventuellement plus grand que k ), il n'est donc pas conseillé de le recueillir dans le pilote si nous voulons que notre code augmente de très grandes valeurs de m .

Je dirais que les deux solutions ci-dessous souffrent de cette faille. La réponse donnée par @ alexander kharlamov appels val u = svd.u.toblockmatrix (). Tolocalmatrix () qui recueille la matrice du pilote. Il en va de même avec la réponse donnée par @ climbs_lika_spyder (BTW Vos Nick Rocks !!), qui appelle svd.u.rows.collect.flatmap (x => x.totarray) . Je préférerais suggérer de s'appuyer sur une multiplication de matrice distribuée telle que le code Scala posté ici .


2 commentaires

Je ne vois aucun calcul inverse sur le lien que vous avez ajouté.


@Climbs_lika_spyder Le lien est à propos de la multiplication de matrice distribuée pour remplacer la multiplication de matrice locale (v.multiphe (INVS)). Multipliez (u) dans la dernière ligne de votre solution, de sorte que vous n'avez pas besoin de Recueillir u dans le pilote. Je pense que v et invas ne sont pas assez gros pour causer des problèmes.