构建稀疏矩阵scala-spark
我有一个表单的输入文件构建稀疏矩阵scala-spark,scala,apache-spark,Scala,Apache Spark,我有一个表单的输入文件 (id | column_name | value) ... 列名称可以有大约50个名称,ID列表可能非常庞大 我想构建一个又高又瘦的矩阵,其(I,j)系数对应于(id,column_name)处的值,id映射到I,column name映射到j 到目前为止,我的方法如下 我加载文件 val f = sc.textFile("example.txt") val data = f.map(_.split('|') match { case Arr
(id | column_name | value)
...
列名称可以有大约50个名称,ID列表可能非常庞大
我想构建一个又高又瘦的矩阵,其(I,j)系数对应于(id,column_name)处的值,id映射到I,column name映射到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)
}
)
然后我将构建列名称和ID列表
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,但我一直在思考如何使用它
谢谢你的帮助 坐标矩阵
太难看了,这不是一个像样的解决方案,但它应该给你一些开始的地方
首先,让我们创建列名和索引之间的映射:
val colIdxMap = sc.broadcast(data.
map({ case (row, col, value) => col }).
distinct.
zipWithIndex.
collectAsMap)
按行id对列进行分组,并将值映射到对(colIdx,value)
:
生成条目:
val entries = values.
zipWithIndex.
flatMap { case (vals, row) =>
vals.map {case (col, value) => MatrixEntry(row, col, value)}
}
创建最终矩阵:
val mat: CoordinateMatrix = new CoordinateMatrix(entries)
行矩阵
如果行ID根本不重要,您可以使用行矩阵
,如下所示:
首先让我们按行分组数据
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
来创建RDD[IndexedRow]
和IndexedRowMatrix
val mat: RowMatrix = new RowMatrix(rows)