在我使用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]
其中列表中的每个元素都在它们之间交换,保持相同的位置。
例如,第一个列表的第一个元素被移动到第二个列表的第一个位置,第一个列表的第二个元素被移动到第三个列表的第二个位置,依此类推。
非常感谢。
答案 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|
// +---+---+---+---+---+