构建稀疏矩阵scala spark

时间:2015-07-10 18:56:22

标签: scala apache-spark

我有一个

形式的输入文件
(id | column_name | value)
...

column_name可以占用大约50个名称,id列表可能很大。

我想建立一个又高又瘦的矩阵,其(i,j)系数对应于在(id,column_name)找到的值,其中id映射到i,列名映射到j。

到目前为止,这是我的方法

我加载文件

val f = sc.textFile("example.txt") 
    val data = f.map(_.split('|') match {
        case Array(id, column_name, score) =>
        (id.toInt, column_name.toString, score.toDouble)
        }
    )

然后我将构建column_name和ids列表

    val column_name_list = data.map(x=>(x._2)._1).distinct.collect.zipWithIndex
    val ids_list = data.map(x=>x._1).distinct.collect.zipWithIndex
    val nCols = column_name_list.length
    val nRows = ids_list.length

然后我将构建一个坐标矩阵,使用我刚刚创建的映射来定义条目;

    val broadcastcolumn_name = sc.broadcast(column_name_list.toMap)
    val broadcastIds = sc.broadcast(ids_list.toMap)

    val matrix_entries_tmp = data.map{
            case(id, column_name, score) => (broadcastIds.value.getOrElse(id,0), broadcastcolumn_name.value.getOrElse(column_name,0), score)
    }   

    val matrix_entries = matrix_entries_tmp.map{
            e => MatrixEntry(e._1, e._2, e._3)
    }   

    val coo_matrix = new CoordinateMatrix(matrix_entries)

这个小例子很好用。但是,当id列表变得庞大时,我收到内存错误。问题似乎是:

val ids_list = data.map(x=>x._1).distinct.collect.zipWithIndex

导致内存错误

什么是解决方法?我实际上并不需要id映射。重要的是列名称,每行对应一些(丢失)id。我正在考虑使用IndexedRowMatrix,但我仍然坚持如何做到这一点。

感谢您的帮助!!

1 个答案:

答案 0 :(得分:1)

CoordinateMatrix

太难看是一个不错的解决方案,但它应该给你一些起点。

首先让我们在列名和索引之间创建一个映射:

val colIdxMap = sc.broadcast(data.
     map({ case (row, col, value) => col }).
     distinct.
     zipWithIndex.
     collectAsMap)

按行ID分组列,将值映射到对(colIdx, value)

val values = data.
    groupBy({ case (row, col, value) => row }).
    mapValues({ _.map { case (_, col, value) => (colIdxMap.value(col), value)}}).
    values

生成条目:

val entries = values.
     zipWithIndex.
     flatMap { case (vals, row) =>
         vals.map {case (col, value) => MatrixEntry(row, col, value)}
     }

创建最终矩阵:

val mat: CoordinateMatrix = new CoordinateMatrix(entries)

RowMatrix

如果行ID根本不重要,您可以使用RowMatrix,如下所示:

首先允许按行分组数据

val dataByRow = data.groupBy { case (row, col, value) => row }

为每一行生成稀疏向量:

val rows = dataByRow.mapValues((vals) => {
    val cols = vals.map {
        case (_, col, value) => (colIdxMap.value(col).toInt, value)
    }
    Vectors.sparse(colIdxMap.value.size, cols.toSeq)
}).values

创建一个矩阵:

val mat: RowMatrix = new RowMatrix(rows)

您可以zipWithIndex使用rows创建RDD[IndexedRow]IndexedRowMatrix