【问题标题】:Keep null values as null in PySpark dense_rank()在 PySpark dense_rank() 中将空值保持为空
【发布时间】:2020-05-14 18:11:57
【问题描述】:

我正在尝试根据包含空值的列在分区内进行排序。

这个DataFrame可以这样创建:

df = spark.createDataFrame( 
                      [("2019-01-01", 5),
                       ("2019-01-01", 20),
                       ("2019-01-01", 10),
                       ("2019-01-03", 1),
                       ("2019-01-03", None),
                       ("2019-01-03", None),
                       ("2019-01-03", 2),
                       ("2019-01-05", 10)],
                       ("Date", "value")
)

看起来像:

+----------+-----+
|      Date|value|
+----------+-----+
|2019-01-01|    5|
|2019-01-01|   20|
|2019-01-01|   10|
|2019-01-03|    1|
|2019-01-03| null|
|2019-01-03| null|
|2019-01-03|    2|
|2019-01-05|   10|
+----------+-----+

现在我想对每个日期的每个值从 1 到 N 进行排名。我尝试使用以下代码:

w = Window.partitionBy("date").orderBy("value")
df = df.withColumn("rank", F.dense_rank().over(w))

但是,这显然将所有 null 值列为 1,而不管一列中有多少 null 值:

+----------+-----+----+
|      Date|value|rank|
+----------+-----+----+
|2019-01-03| null|   1|
|2019-01-03| null|   1|
|2019-01-03|    1|   2|
|2019-01-03|    2|   3|
|2019-01-05|   10|   1|
|2019-01-01|    5|   1|
|2019-01-01|   10|   2|
|2019-01-01|   20|   3|
+----------+-----+----+

如何更改dense_rank() 的行为,使其在排名时将null 的值保持在null,而不是给这些值任意排名1?

【问题讨论】:

  • @Menmo Van Dijk 下面的答案对你有用吗?

标签: python pyspark


【解决方案1】:

您所需要的只是一个isNull(),以分区和实际排名为条件。不幸的是,不能直接在pyspark 中修改dense_rank()。代码如下所示:

from pyspark.sql import Window

common_condition = f.col("value").isNull()

w = Window.partitionBy(
    f.col('Date'),
    f.when(common_condition, 1).otherwise(0)
).orderBy(f.col("value"))

df = df.withColumn(
    "rank", 
    f.when(common_condition, f.lit(None)).otherwise(f.dense_rank().over(w))  
)
df.show()

+----------+-----+----+
|      Date|value|rank|
+----------+-----+----+
|2019-01-03|    1|   1|
|2019-01-03|    2|   2|
|2019-01-03| null|null|
|2019-01-03| null|null|
|2019-01-05|   10|   1|
|2019-01-01|    5|   1|
|2019-01-01|   10|   2|
|2019-01-01|   20|   3|
+----------+-----+----+

或者,您可以使用pyspark.sql.functions.desc_nulls_last() 并随后过滤掉f.col("value").isNull() 和您的等级列f.col("rank") 等于分区f.max() 的位置,但这可能更笨重且难以阅读。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 2013-07-02
    • 2021-04-16
    • 2018-11-19
    • 2014-08-29
    • 2016-06-30
    相关资源
    最近更新 更多