如何按计数排序并保留值中的唯一项目

时间:2018-04-22 05:11:41

标签: scala apache-spark spark-dataframe

我有一个包含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中的条目出现的次数,但这不是我正在寻找的内容。

2 个答案:

答案 0 :(得分:0)

您可以执行以下操作:

  1. 为每个键和列值计算计数
  2. 对于每个键,计算包含所有相关列值及其计数的列表
  3. 使用udf对列表进行排序并删除计数
  4. 就像那样(在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]|
+----+------------------------+---------+