【发布时间】:2018-09-27 19:40:50
【问题描述】:
标题可能不是很清楚。让我用一个例子来解释我想要实现的目标。 以 DataFrame 开头,如下所示:
val df = Seq((1, "CS", 0, (0.1, 0.2, 0.4, 0.5)),
(4, "Ed", 0, (0.4, 0.8, 0.3, 0.6)),
(7, "CS", 0, (0.2, 0.5, 0.4, 0.7)),
(101, "CS", 1, (0.5, 0.7, 0.3, 0.8)),
(5, "CS", 1, (0.4, 0.2, 0.6, 0.9)))
.toDF("id", "dept", "test", "array")
+---+----+----+--------------------+
| id|dept|test| array|
+---+----+----+--------------------+
| 1| CS| 0|[0.1, 0.2, 0.4, 0.5]|
| 4| Ed| 0|[0.4, 0.8, 0.3, 0.6]|
| 7| CS| 0|[0.2, 0.5, 0.4, 0.7]|
|101| CS| 1|[0.5, 0.7, 0.3, 0.8]|
| 5| CS| 1|[0.4, 0.2, 0.6, 0.9]|
+---+----+----+--------------------+
我想根据 id、dept 和 test 列中的信息删除/删除数组列的一些元素。具体来说,每个数组的4个元素对应CS部门的4个id,编号是按照id升序生成的(意思是1、5、7、101)。现在我想删除每个数组中对应于测试列为 1 的 id 的元素。在此示例中,将删除第 2 和第 4 个元素,最终结果将如下所示:
+---+----+----+----------+
| id|dept|test| array|
+---+----+----+----------+
| 1| CS| 0|[0.1, 0.4]|
| 4| Ed| 0|[0.4, 0.3]|
| 7| CS| 0|[0.2, 0.4]|
|101| CS| 1|[0.5, 0.3]|
| 5| CS| 1|[0.4, 0.6]|
+---+----+----+----------+
为了避免收集所有结果并在 Scala 中进行操作。如果可能,我想将操作保留在 Spark DataFrame 中。我解决这个问题的想法包括两个步骤:
- 找出需要删除的数组元素的索引
- 应用删除/删除操作
到目前为止,我想我已经弄清楚了第 1 步:
import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.functions._
val w = Window.partitionBy("dept").orderBy("id")
val studentIdIdx = df.select("id", "dept")
.withColumn("Index", row_number().over(w))
.where("dept = 'CS'").drop("dept")
studentIdIdx.show()
+---+-----+
| id|Index|
+---+-----+
| 1| 1|
| 5| 2|
| 7| 3|
|101| 4|
+---+-----+
val testIds = df.where("test = 1")
.select($"id".as("test_id"))
val testMask = studentIdIdx
.join(testIds, studentIdIdx("id") === testIds("test_id"))
.drop("id","test_id")
testMask.show()
+-----+
|Index|
+-----+
| 2|
| 4|
+-----+
所以我的两个相关问题是:
如何将删除/删除功能应用到每行中带有索引的每个数组? (我也愿意提出更好的方法来计算索引)
-
我想要的真正最终 DataFrame 应该在上述结果之上删除一些元素。具体来说,对于test=0 & dept=CS,应该去掉id的Index对应的数组元素。在这个例子中,id=1 的行中的第 1 个元素和 id=7 的行中的第 3 个元素(删除前的原始索引)应该被删除,真正的最终结果是:
+---+----+----+----------+ | id|dept|test| array| +---+----+----+----------+ | 1| CS| 0|[0.4] | | 4| Ed| 0|[0.4, 0.3]| | 7| CS| 0|[0.2] | |101| CS| 1|[0.5, 0.3]| | 5| CS| 1|[0.4, 0.6]| +---+----+----+----------+
我提到第二点,以防万一可以应用更有效的方法来同时实现两个删除操作。如果没有,我想一旦我知道如何使用索引信息进行删除操作,我应该能够弄清楚如何进行第二次删除。谢谢!
【问题讨论】:
-
在您的示例中,“array”列不是数组类型,而是结构类型
-
你说
the 3rd element (original index before any removal) in the row with id=7 should be removed那么| 7| CS| 0|[0.4]不应该是| 7| CS| 0|[0.2]吗?如果那是真的,那么我在下面的回答符合您的要求 -
是的,你是对的。我将编辑帖子。
标签: arrays scala apache-spark