[英]Spark Scala Dataframe - replace/join column values with values from another dataframe (but is transposed)
[英]Spark Scala: How to replace null with values from an array or another dataframe
我有一个如下的数据框
+-----+------+
|empID|deptid|
+-----+------+
| 163| null|
| 843| null|
+-----+------+
而且我有长数字range = [20,21]
,或者您可以将其转换为另一个数据帧
+--------+
| deptid|
+--------+
| 20|
| 21|
+--------+
我想替换那些空值并将输出作为
+-----+------+
|empID|deptid|
+-----+------+
| 163| 20|
| 843| 21|
+-----+------+
我试过了
emp.na.fill(range, Array("deptid")
但是 na.fill 需要第一个参数是 String Boolean Long double 等,而不是数组。
我试图加入两个数据框以获得输出,但没有一个连接给我解决方案。
我尝试的一切都给了我
+-----+------+
|empID|deptid|
+-----+------+
| 163| null|
| 843| null|
| null| 5|
| null| 6|
+-----+------+
任何想法?
编辑:从范围数组中获取哪个 empId 并不重要。
是的,我确保数组长度与空值的数量相匹配。
所以我确实有一个解决方案,但它是如此复杂和hacky,我仍然希望有人给出更好的答案。
基本上加入两个数据框,将所有数据收集为数组 zip(删除所有空值),然后作为映射值展开。
val p = newRecords.as("L")
.join(range.as("R"), newRecords("deptid") =!= range("deptid"), "full")
.groupBy()
.agg(collect_list($"R.deptid").as("D"), collect_list($"empID").as("E"))
.withColumn("zip",arrays_zip(col("D"),col("E"))).drop("D", "E")
.select(explode($"zip").as("zip1"))
.withColumn("empid", $"zip1".getItem("E"))
.withColumn("deptid", $"zip1".getItem("D"))
.drop($"zip1")
.show()
+-----+------+
|empid|deptid|
+-----+------+
| 163| 20|
| 843| 21|
+-----+------+
您可以使用或不使用将数组转换为数据框来执行此操作。 可能值得尝试两者,看看哪个更有效(通常 udfs 会更慢)。
如果您不将数组转换为数据框,则可以使用 udf。 您将为初始数据帧生成行号并将其用作数组的索引:
val testDF = Seq((163, null), (843, null)).toDF("empID", "deptID")
val range = List(20, 21)
val myUDF = udf((i: Int) => {
range(i)
})
testDF.withColumn("rn", row_number().over(Window.orderBy("empID")) - 1)
.withColumn("deptID", myUDF(col("rn")))
.select("empID", "deptID").show
输出:
+-----+------+
|empID|deptID|
+-----+------+
| 163| 20|
| 843| 21|
+-----+------+
如果您确实将数组转换为数据框,则可以为这两个数据框生成行号并在连接条件中使用它:
val testDF = Seq((163, null), (843, null)).toDF("empID", "deptID")
val rangeDF = Seq(20, 21).toDF("deptID")
testDF.withColumn("rn", row_number().over(Window.orderBy("empID")))
.join(rangeDF.withColumn("rn", row_number().over(Window.orderBy("deptID"))), Seq("rn"))
.select(testDF.col("empID"), rangeDF.col("deptID")).show
输出:
+-----+------+
|empID|deptID|
+-----+------+
| 163| 20|
| 843| 21|
+-----+------+
请注意,这两种解决方案都涉及使用未定义分区的Window
函数。 如果您有大量数据并且最终被洗牌到单个节点,这可能会很糟糕。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.