我有一个
形式的输入文件(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,但我仍然坚持如何做到这一点。
感谢您的帮助!!
答案 0 :(得分:1)
太难看是一个不错的解决方案,但它应该给你一些起点。
首先让我们在列名和索引之间创建一个映射:
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)
如果行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
。