我有一个包含2列的数据框,格式为
col1 col2
k1 'a'
k2 'b'
k1 'a'
k1 'c'
k2 'c'
k1 'b'
k1 'b'
k2 'c'
k1 'b'
我希望输出为
k1 ['b', 'a', 'c']
k2 ['c', 'b']
所以唯一的条目集,按每个条目发生的次数(按降序排序)排序。在上面的示例中,' b'与k1三次相关,' a'两次,' c'一旦。
我该怎么做?
groupBy($"col1").count()
仅查看col1
中的条目出现的次数,但这不是我正在寻找的内容。
答案 0 :(得分:0)
您可以执行以下操作:
就像那样(在Scala中):
import scala.collection.mutable
import org.apache.spark.sql.{Row}
val sort_by_count_udf = udf {
arr: mutable.WrappedArray[Row] =>
arr.map {
case Row(count: Long, col2: String) => (count, col2)
}.sortBy(-_._1).map { case (count, col2) => col2 }
}
val df = List(("k1", "a"),
("k1", "a"), ("k1", "c"), ("k1", "b"),
("k2", "b"), ("k2", "c"), ("k2", "c"),
("k1", "b"), ("k1", "b"))
.toDF("col1", "col2")
val grouped = df
.groupBy("col1", "col2")
.count()
.groupBy("col1")
.agg(collect_list(struct("count", "col2")).as("list"))
grouped.withColumn("list_ordered", sort_by_count_udf(col("list"))).show
答案 1 :(得分:0)
这里有一个(不太漂亮的解决方案)只使用内置函数:
df.groupBy($"col1" , $"col2")
.agg(count($"col2").alias("cnt") )
.groupBy($"col1")
.agg(sort_array(collect_list(struct(-$"cnt", $"col2"))).as("list"))
.withColumn("x" , $"list".getItem("col2") )
.show(false)
由于sort_array
根据元素的自然顺序按升序对元素进行排序-$"cnt"
有助于我们根据元素的数量按降序对元素进行排序。 getItem
用于从结构中获取col2
的值。
输出:
+----+------------------------+---------+
|col1|list |x |
+----+------------------------+---------+
|k2 |[[-2,c], [-1,b]] |[c, b] |
|k1 |[[-3,b], [-2,a], [-1,c]]|[b, a, c]|
+----+------------------------+---------+