如何在PySpark数据帧中从结构数组转到每个结构的第一个元素的数组?
一个例子将使这更清楚。让我们说我的数据框定义如下:
scoresheet = spark.createDataFrame([("Alice", [("Math",100),("English",80)]),("Bob", [("Math", 90)]),("Charlie", [])],["name","scores"])
上面定义的模式和数据框如下所示:
root
|-- name: string (nullable = true)
|-- scores: array (nullable = true)
| |-- element: struct (containsNull = true)
| | |-- _1: string (nullable = true)
| | |-- _2: long (nullable = true)
+-------+--------------------------+
|name |scores |
+-------+--------------------------+
|Alice |[[Math,100], [English,80]]|
|Bob |[[Math,90]] |
|Charlie|[] |
+-------+--------------------------+
您可以看到主题标记包含在每个学生的(Subject,Marks)
类型的有序结构中。每个学生的科目数不是一成不变的,可能为零。
我想从这里开始创建一个新的数据框,其中只包含每个学生的数组中的主题,没有标记。对于没有科目的学生,它应该产生一个空数组。简而言之,它应该是这样的:
+-------+---------------+
|name |scores |
+-------+---------------+
|Alice |[Math, English]|
|Bob |[Math] |
|Charlie|[] |
+-------+---------------+
请注意,行数与之前相同;所以我不能使用爆炸,除非我之后重新组合,这似乎在计算上效率低下。
答案 0 :(得分:2)
你能做的最好的是udf:
from pyspark.sql.functions import udf
from pyspark.sql.types import ArrayType, StringType
take_first = udf(lambda rows: [row[0] for row in rows], ArrayType(StringType()))
scoresheet.withColumn("scores", take_first("scores"))
答案 1 :(得分:0)
作为参考,这是具有爆炸,分组依据和聚合的版本。
var result = db.Where(searchDetails.ColName + ".Contains(@0)", searchDetails.SearchVal);
由于这纯粹是在PySpark中进行的,因此在某些情况下如果它比UDF版本快,我不会感到惊讶,但是我没有进行任何分析。左联接是为了确保没有成绩的学生不会落在最终成绩中。