在Spark中改组RDD [List [Double]]的元素

时间:2018-06-05 15:42:19

标签: scala apache-spark

在我使用Scala中的Spark 2.3开发的程序中,我有一个RDD[List[Double]]。每个List[Double]都有相同的大小。我无法弄清楚如何执行给定RDD

的转换
[1.0, 1.5, 4.0, 3.0],
[2.3, 5.6, 3.4, 9.0],
[4.5, 2.0, 1.0, 5.7]

RDD

中对其进行转换
[2.3, 2.0, 1.0, 3.0],
[1.0, 5.6, 4.0, 5.7],
[4.5, 1.5, 3.4, 9.0]

其中列表中的每个元素都在它们之间交换,保持相同的位置。

例如,第一个列表的第一个元素被移动到第二个列表的第一个位置,第一个列表的第二个元素被移动到第三个列表的第二个位置,依此类推。

非常感谢。

1 个答案:

答案 0 :(得分:1)

逐列混洗的一种方法是将数据集分解为单个单列DataFrame,每个DataFrame使用orderBy(rand)进行混洗,然后将它们组合在一起。

要加入混洗的DataFrame,RDD zipWithIndex将应用于每个数据框以创建行标识ID。请注意,monotonically_increasing_id不会删除它,因为它不保证生成最终join所需的相同ID列表。因此,由于RDD和DataFrame之间需要转换,这相当昂贵。

import org.apache.spark.sql.functions._
import org.apache.spark.sql.types._
import org.apache.spark.sql.Row

val rdd0 = sc.parallelize(Seq(
    List(1.0, 1.5, 4.0, 3.0),
    List(2.3, 5.6, 3.4, 9.0),
    List(4.5, 2.0, 1.0, 5.7)
  ))
//rdd0: org.apache.spark.rdd.RDD[List[Double]] = ...

val rdd = rdd0.map{ case x: Seq[Double] => (x(0), x(1), x(2), x(3)) }
val df = rdd.toDF("c1", "c2", "c3", "c4")

val shuffledDFs = df.columns.filter(_.startsWith("c")).map{ c =>
  val subDF = df.select(c)
  val subRDD = subDF.orderBy(rand).rdd.zipWithIndex.map{
    case (row: Row, id: Long) => Row.fromSeq(row.toSeq :+ id)
  }
  spark.createDataFrame( subRDD,
    StructType(subDF.schema.fields :+ StructField("idx", LongType, false))
  )
}

shuffledDFs.reduce( _.join(_, Seq("idx")) ).
  show
// +---+---+---+---+---+                                                           
// |idx| c1| c2| c3| c4|
// +---+---+---+---+---+
// |  0|2.3|2.0|4.0|9.0|
// |  1|1.0|5.6|3.4|3.0|
// |  2|4.5|1.5|1.0|5.7|
// +---+---+---+---+---+