Возвращает null в сумме, если некоторые значения равны null

#python #apache-spark #pyspark #apache-spark-sql

#apache-spark #pyspark #apache-spark-sql #null #совокупный

Вопрос:

У меня есть случай, когда у меня могут быть нулевые значения в столбце, которые необходимо суммировать в группе.

Если я сталкиваюсь с null в группе, я хочу, чтобы сумма этой группы была равна null. Но PySpark по умолчанию, похоже, игнорирует нулевые строки и суммирует остальные ненулевые значения.

Например:

введите описание изображения здесь

 dataframe = dataframe.groupBy('dataframe.product', 'dataframe.price') 
                     .agg(f.sum('price'))
 

Ожидаемый результат:

введите описание изображения здесь

Но я получаю:

введите описание изображения здесь

Ответ №1:

sum функция возвращает NULL, только если все значения для этого столбца равны null, в противном случае null просто игнорируются.

Вы можете использовать условную агрегацию, если count(price) == count(*) это означает, что нет нулей, и мы возвращаемся sum(price) . В противном случае возвращается значение null:

 from pyspark.sql import functions as F

df.groupby("product").agg(
    F.when(F.count("price") == F.count("*"), F.sum("price")).alias("sum_price")
).show()

# ------- --------- 
#|product|sum_price|
# ------- --------- 
#|      B|      200|
#|      C|     null|
#|      A|      250|
# ------- --------- 
 

Начиная с Spark 3.0 , можно также использовать any функцию:

 df.groupby("product").agg(
    F.when(~F.expr("any(price is null)"), F.sum("price")).alias("sum_price")
).show()
 

Ответ №2:

Вы можете заменить NULL на NAN с помощью coalesce :

 df2 = df.groupBy('product').agg(
    F.sum(
        F.coalesce(F.col('price'), F.lit(float('nan')))
    ).alias('sum(price)')
).orderBy('product')

df2.show()
 ------- ---------- 
|product|sum(price)|
 ------- ---------- 
|      A|     250.0|
|      B|     200.0|
|      C|       NaN|
 ------- ---------- 
 

Если вы хотите сохранить целочисленный тип, вы можете преобразовать NAN обратно в null с помощью nanvl :

 df2 = df.groupBy('product').agg(
    F.nanvl(
        F.sum(
            F.coalesce(F.col('price'), F.lit(float('nan')))
        ),
        F.lit(None)
    ).cast('int').alias('sum(price)')
).orderBy('product')

df2.show()
 ------- ---------- 
|product|sum(price)|
 ------- ---------- 
|      A|       250|
|      B|       200|
|      C|      null|
 ------- ----------