如何按数量排序并保留价值中的唯一项目
How to sort by count and retain unique items in value
我有一个包含 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
中的条目出现的次数,但这不是我要找的。
您可以执行以下操作:
- 对于每个键和列值,计算计数
- 对于每个键,计算一个包含所有相关列值及其计数的列表
- 使用 udf 对列表进行排序并删除计数
就像那样(在 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
这是一个仅使用内置函数的(不太漂亮的解决方案):
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]|
+----+------------------------+---------+
我有一个包含 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
中的条目出现的次数,但这不是我要找的。
您可以执行以下操作:
- 对于每个键和列值,计算计数
- 对于每个键,计算一个包含所有相关列值及其计数的列表
- 使用 udf 对列表进行排序并删除计数
就像那样(在 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
这是一个仅使用内置函数的(不太漂亮的解决方案):
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]|
+----+------------------------+---------+