簡體   English   中英

將 null 值保留為 null 在 PySpark dense_rank()

[英]Keep null values as null in PySpark dense_rank()

我正在嘗試根據包含空值的列在分區內進行排序。

這個 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?

您所需要的只是一個以分區和實際排名為條件的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()但這可能更笨重,更難閱讀。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM