Spark Dataframe中`float`与`np.nan`的比较

avl*_*oss 6 python numpy nan apache-spark pyspark

这是预期的行为吗?我本来想提出Spark的问题,但这似乎是一种基本功能,很难想象这里有bug。我想念什么?

蟒蛇

import numpy as np

>>> np.nan < 0.0
False

>>> np.nan > 0.0
False
Run Code Online (Sandbox Code Playgroud)

PySpark

from pyspark.sql.functions import col

df = spark.createDataFrame([(np.nan, 0.0),(0.0, np.nan)])
df.show()
#+---+---+
#| _1| _2|
#+---+---+
#|NaN|0.0|
#|0.0|NaN|
#+---+---+

df.printSchema()
#root
# |-- _1: double (nullable = true)
# |-- _2: double (nullable = true)

df.select(col("_1")> col("_2")).show()
#+---------+
#|(_1 > _2)|
#+---------+
#|     true|
#|    false|
#+---------+
Run Code Online (Sandbox Code Playgroud)

use*_*362 7

这既是预期行为,也是有记录的行为。引用官方Spark SQL指南的NaN语义部分(重点是我的):

在处理与标准浮点语义不完全匹配的float或double类型时,对非数字(NaN)进行了特殊处理。特别:

  • NaN = NaN返回true。
  • 在聚合中,所有NaN值都分组在一起。
  • NaN在连接键中被视为普通值。
  • NaN值按升序排在最后,大于任何其他数值

与Python NaN相比,您看到的AdAs并不是唯一的订购行为。特别是Spark认为NaN等于:

spark.sql("""
    WITH table AS (SELECT CAST('NaN' AS float) AS x, cast('NaN' AS float) AS y) 
    SELECT x = y, x != y FROM table
""").show()
Run Code Online (Sandbox Code Playgroud)
spark.sql("""
    WITH table AS (SELECT CAST('NaN' AS float) AS x, cast('NaN' AS float) AS y) 
    SELECT x = y, x != y FROM table
""").show()
Run Code Online (Sandbox Code Playgroud)

而普通的Python

float("NaN") == float("NaN"), float("NaN") != float("NaN")
Run Code Online (Sandbox Code Playgroud)
+-------+-------------+
|(x = y)|(NOT (x = y))|
+-------+-------------+
|   true|        false|
+-------+-------------+
Run Code Online (Sandbox Code Playgroud)

和NumPy

np.nan == np.nan, np.nan != np.nan
Run Code Online (Sandbox Code Playgroud)
float("NaN") == float("NaN"), float("NaN") != float("NaN")
Run Code Online (Sandbox Code Playgroud)

别。

您可以检查eqNullSafedocstring以获取其他示例。

因此,要获得理想的结果,您必须明确检查NaN

from pyspark.sql.functions import col, isnan, when

when(isnan("_1") | isnan("_2"), False).otherwise(col("_1") > col("_2"))
Run Code Online (Sandbox Code Playgroud)