Aggreagte中的示例值

时间:2018-05-01 17:53:30

标签: apache-spark pyspark

我有一个数据集,我需要得到一些计数和最常见的值。

下面是一个示例数据框。

top

enter image description here

我有示例代码但不完整。

down

预期结果如下。

enter image description here

如何完成这项工作。

1 个答案:

答案 0 :(得分:0)

DataFrame中的null值导致聚合问题。一种选择是将这些值替换为非null的值,以便进行聚合。

例如:

new_df = test_df.withColumn(
    "Country",
    F.when(
        F.isnull("Country"),
        "None"
    ).otherwise(F.col("Country"))
)

这将返回一个DataFrame,其中null列的Country值已替换为字符串"None"。 (我故意避免使用字符串"null"来避免歧义。)

现在,您可以使用pyspark.sql.functions.rank()pyspark.sql.Window按频率计算每个国家/地区的排名并对其进行排名。

from pyspark.sql import Window
new_df.groupBy("Country")\
    .agg(
        F.count("Country").alias("Count"),
        F.rank().over(Window.orderBy(F.count("Country").desc())).alias("Rank")
    )\
    .show()
#+-------+-----+----+
#|Country|Count|Rank|
#+-------+-----+----+
#|    USA|    4|   1|
#|   None|    2|   2|
#|    MEX|    1|   3|
#|       |    1|   3|
#|    DEU|    1|   3|
#|    CAN|    1|   3|
#+-------+-----+----+

如您所见,由于替换,"None"显示在县列中。此时,您拥有计算所需聚合所需的一切。

  • 第一个输出列(count)只是Count列的总和。
  • 第二个输出列(distinct_country)的计算方式类似于您在帖子中的操作方式。
  • 可以使用pyspark.sql.functions.collect_list()计算最终输出列(top_2_countries),过滤rank <= 2的值。

例如:

new_df.groupBy("Country")\
    .agg(
        F.count("Country").alias("Count"),
        F.rank().over(Window.orderBy(F.count("Country").desc())).alias("Rank")
    )\
    .agg(
        F.sum("Count").alias("count"),
        F.countDistinct("Country").alias("distinct_country"),
        F.collect_list(F.when(F.col("rank")<=2, F.col("Country"))).alias("top_2_countries")
    )\
    .show()
#+-----+----------------+---------------+
#|count|distinct_country|top_2_countries|
#+-----+----------------+---------------+
#|   10|               6|    [USA, None]|
#+-----+----------------+---------------+

请注意这里的两件事。首先,计数是6而不是你的例子中的5。 5是nullcountDistinct()被忽略的结果。同样,top_2_countries列的值为[USA, None]

出于演示目的,如果您已将"None"值转换回null,将会发生以下情况:

new_df.groupBy("Country")\
    .agg(
        F.count("Country").alias("Count"),
        F.rank().over(Window.orderBy(F.count("Country").desc())).alias("Rank")
    )\
    .withColumn(
        "Country",
        F.when(F.col("Country") == "None", None).otherwise(F.col("Country"))
    )\
    .agg(
        F.sum("Count").alias("count"),
        F.countDistinct("Country").alias("distinct_country"),
        F.collect_list(F.when(F.col("rank")<=2, F.col("Country"))).alias("top_2_countries")
    )\
    .show()
#+-----+----------------+---------------+
#|count|distinct_country|top_2_countries|
#+-----+----------------+---------------+
#|   10|               5|          [USA]|
#+-----+----------------+---------------+

正如您所看到的那样,非重复计数为5,但top_2_countries列不包含null。这是因为null被排除在collect_list() 1 之外。 (见this example)。

1 请务必注意,我在调用collect_list()时利用了这一事实。来自pyspark.sql.functions.when()的文档:

  

如果未调用Column.otherwise(),则为不匹配的条件返回None。