如何使用Scala在Spark中声明稀疏向量?

如何使用Scala在Spark中声明稀疏向量?,scala,apache-spark,seq,apache-spark-mllib,Scala,Apache Spark,Seq,Apache Spark Mllib,我试图创建一个稀疏向量(类,不是默认的),但我不知道如何使用Seq。我有一个小测试文件,每行有三个数字,我将其转换为rdd,将文本分成两部分,然后按第一列对行进行分组 测试文件 1 2 4 1 3 5 1 4 8 2 7 5 2 8 4 2 9 10 代码 这将导致分组具有这些值 (2.0,CompactBuffer([2.0,7.0,5.0], [2.0,8.0,4.0], [2.0,9.0,10.0])) (1.0,CompactBuffer([1.0,2.

我试图创建一个稀疏向量(类,不是默认的),但我不知道如何使用Seq。我有一个小测试文件,每行有三个数字,我将其转换为rdd,将文本分成两部分,然后按第一列对行进行分组

测试文件

1 2 4
1 3 5    
1 4 8    
2 7 5    
2 8 4    
2 9 10
代码

这将导致
分组
具有这些值

(2.0,CompactBuffer([2.0,7.0,5.0], [2.0,8.0,4.0], [2.0,9.0,10.0]))
(1.0,CompactBuffer([1.0,2.0,4.0], [1.0,3.0,5.0], [1.0,4.0,8.0]))
但我似乎不知道下一步该怎么做。我需要将
的每一行分组
并为其创建一个向量,以便新RDD的每一行都有一个向量,该向量在第二个值指定的索引中具有
CompactBuffer
的第三个值。简而言之,我的意思是,我希望示例中的数据是这样的

[0, 0, 0, 0, 0, 0, 5.0, 4.0, 10.0, 0]
[0, 4.0, 5.0, 8.0, 0, 0, 0, 0, 0, 0]

我知道我需要使用稀疏向量,有三种方法来构造它。我曾尝试使用带有tuple2(索引,值)的Seq,但我不明白如何创建这样的Seq。

一种可能的解决方案如下所示。首先,让我们将数据转换为预期类型:

import org.apache.spark.rdd.RDD

val pairs: RDD[(Double, (Int, Double))] = data.map(_.split(" ") match {
  case Array(label, idx, value) => (label.toDouble, (idx.toInt, value.toDouble))
})
接下来查找最大索引(向量大小):

分组并转换:

import org.apache.spark.mllib.linalg.SparseVector

def makeVector(xs: Iterable[(Int, Double)]) = {
  val (indices, values) = xs.toArray.sortBy(_._1).unzip
  new SparseVector(nCols, indices.toArray, values.toArray)
}

val transformed: RDD[(Double, SparseVector)] = pairs
  .groupByKey
  .mapValues(makeVector)
假设可以安全地将第一个元素转换为整数或从整数转换为整数,则处理此问题的另一种方法是使用
CoordinateMatrix

import org.apache.spark.mllib.linalg.distributed.{CoordinateMatrix, MatrixEntry}

val entries: RDD[MatrixEntry] = data.map(_.split(" ") match {
  case Array(label, idx, value) => 
    MatrixEntry(label.toInt, idx.toInt, value.toDouble)
})

val transformed: RDD[(Double, SparseVector)] = new CoordinateMatrix(entries)
  .toIndexedRowMatrix
  .rows
  .map(row => (row.index.toDouble, row.vector))

它完成了这项工作,但似乎有点复杂,它给我的印象是,有更简单的代码来完成这项工作。不管怎样,我对scala真的很陌生,我很容易被搞糊涂!
import org.apache.spark.mllib.linalg.SparseVector

def makeVector(xs: Iterable[(Int, Double)]) = {
  val (indices, values) = xs.toArray.sortBy(_._1).unzip
  new SparseVector(nCols, indices.toArray, values.toArray)
}

val transformed: RDD[(Double, SparseVector)] = pairs
  .groupByKey
  .mapValues(makeVector)
import org.apache.spark.mllib.linalg.distributed.{CoordinateMatrix, MatrixEntry}

val entries: RDD[MatrixEntry] = data.map(_.split(" ") match {
  case Array(label, idx, value) => 
    MatrixEntry(label.toInt, idx.toInt, value.toDouble)
})

val transformed: RDD[(Double, SparseVector)] = new CoordinateMatrix(entries)
  .toIndexedRowMatrix
  .rows
  .map(row => (row.index.toDouble, row.vector))