我有一个包含数组类型列的输入Dataframe。数组中的每个条目都是一个结构,由一个键(大约四个值中的一个)和一个值组成。我想把它转换成一个Dataframe,每个可能的键对应一列,如果该值不在该行的数组中,则为空。任何数组中的键都不会重复,但它们可能会无序或丢失。
到目前为止,我得到的最好的是
val wantedCols =df.columns
.filter(_ != arrayCol)
.filter(_ != "col")
val flattened = df
.select((wantedCols.map(col(_)) ++ Seq(explode(col(arrayCol)))):_*)
.groupBy(wantedCols.map(col(_)):_*)
.pivot("col.key")
.agg(first("col.value"))
这正是我想要的,但它是可怕的,我不知道什么样的分支分组,每一列,但一个。正确的方法是什么?
编辑:输入/输出示例:
case class testStruct(name : String, number : String)
val dfExampleInput = Seq(
(0, "KY", Seq(testStruct("A", "45"))),
(1, "OR", Seq(testStruct("A", "30"), testStruct("B", "10"))))
.toDF("index", "state", "entries")
.show
+-----+-----+------------------+
|index|state| entries|
+-----+-----+------------------+
| 0| KY| [[A, 45]]|
| 1| OR|[[A, 30], [B, 10]]|
+-----+-----+------------------+
val dfExampleOutput = Seq(
(0, "KY", "45", null),
(1, "OR", "30", "10"))
.toDF("index", "state", "A", "B")
.show
+-----+-----+---+----+
|index|state| A| B|
+-----+-----+---+----+
| 0| KY| 45|null|
| 1| OR| 30| 10|
+-----+-----+---+----+
进一步编辑:
我自己提交了一个解决方案(见下文),只要您事先知道密钥(在我的例子中,我知道),就可以很好地处理这个问题。如果找到密钥是一个问题,另一个答案包含处理该问题的代码。
4条答案
按热度按时间66bbxpm51#
没有
groupBy
pivot
aggfirst
请检查下面的代码。最终输出
qncylg1j2#
我自己想出了一个解决办法:
例子:
产生:
此解决方案与其他答案稍有不同:
它一次只能对一个键起作用
它要求预先知道密钥名称和密钥数
它生成一列结构,而不是执行提取特定值的额外步骤
它作为一个简单的列到列操作工作,而不需要对整个df进行转换
它可以懒散地评估
前三个问题可以通过调用代码来处理,对于您已经知道键或者结构包含要提取的附加值的情况,可以让代码更加灵活。
hfyxw5xn3#
我不会太担心按几个列分组,只会让事情变得混乱。在这种情况下,如果有更简单、更易维护的方法,那就去做吧。如果没有示例输入/输出,我不确定这是否能让您达到您想要达到的目的,但也许它会有用:
根据您现在所说的内容,我得到的印象是,有许多类似“state”的列不是聚合所必需的,但需要在最终结果中。
作为参考,如果不需要透视,可以添加一个嵌套了所有此类字段的结构列,然后将其添加到聚合中,例如:
.agg(first($"myStruct"), first($"number"))
. 其主要优点是只在中引用实际的键列groubBy
. 但是当使用pivot时,事情变得有点奇怪,所以我们将把这个选项放在一边。在这个用例中,我能想到的最简单的方法是拆分Dataframe,并在聚合之后使用一些rowkey将其重新连接在一起。在这个例子中,我假设
"index"
适用于此目的:如果有的话,我怀疑你在表现上会看到很大的不同。可能在极端情况下,例如:非常多
meh
列,或者很多透视列,或者类似的,或者什么都没有。就我个人而言,我会用适当大小的输入来测试这两种方法,如果没有显著的差异,就用更容易维护的方法。vfhzx4xs4#
这是另一种方法,它是建立在假设的基础上,没有重复的
entries
列,即Seq(testStruct("A", "30"), testStruct("A", "70"), testStruct("B", "10"))
会导致错误。下一个解决方案结合了rdd和dataframe API来实现:注意:该解决方案需要一个额外的操作来检索唯一键,尽管它不会导致任何洗牌,因为它只基于窄变换。