如何检测pyspark中的空列

Mèh*_*ida 2 apache-spark apache-spark-sql pyspark spark-dataframe pyspark-sql

我有一个用一些空值定义的数据框。一些列是完全空值。

>> df.show()
+---+---+---+----+
|  A|  B|  C|   D|
+---+---+---+----+
|1.0|4.0|7.0|null|
|2.0|5.0|7.0|null|
|3.0|6.0|5.0|null|
+---+---+---+----+
Run Code Online (Sandbox Code Playgroud)

就我而言,我想返回一个填充了空值的列名称列表。我的想法是检测常量列(因为整个列包含相同的空值)。

我是这样做的:

nullCoulumns = [c for c, const in df.select([(min(c) == max(c)).alias(c) for c in df.columns]).first().asDict().items() if const] 
Run Code Online (Sandbox Code Playgroud)

但这并不将空列视为常量,它仅适用于值。那我该怎么做呢?

小智 5

将条件扩展为

from pyspark.sql.functions import min, max

((min(c).isNull() & max(c).isNull()) | (min(c) == max(c))).alias(c) 
Run Code Online (Sandbox Code Playgroud)

或使用eqNullSafe(PySpark 2.3):

(min(c).eqNullSafe(max(c))).alias(c) 
Run Code Online (Sandbox Code Playgroud)

  • 这适用于列中所有值都为空的情况。但请考虑列值为“[null, 1, 1, null]”的情况。在这种情况下,最小值和最大值都等于“1”。因此,将被错误地识别为全部为空。 (4认同)
  • @desertnaut:这是一个相当快的,只需要十分之一秒:D (2认同)

des*_*aut 5

一种方法是隐式执行此操作:选择每一列,计算其 NULL 值,然后将其与总数或行数进行比较。根据您的数据,这将是:

spark.version
# u'2.2.0'

from pyspark.sql.functions import col

nullColumns = []
numRows = df.count()
for k in df.columns:
  nullRows = df.where(col(k).isNull()).count()
  if nullRows ==  numRows: # i.e. if ALL values are NULL
    nullColumns.append(k)

nullColumns
# ['D']
Run Code Online (Sandbox Code Playgroud)

但还有一种更简单的方法:事实证明countDistinct,当该函数应用于包含所有 NULL 值的列时,会返回零 (0):

from pyspark.sql.functions import countDistinct

df.agg(countDistinct(df.D).alias('distinct')).collect()
# [Row(distinct=0)]
Run Code Online (Sandbox Code Playgroud)

所以for现在的循环可以是:

nullColumns = []
for k in df.columns:
  if df.agg(countDistinct(df[k])).collect()[0][0] == 0:
    nullColumns.append(k)

nullColumns
# ['D']
Run Code Online (Sandbox Code Playgroud)

更新collect(评论后):在第二个解决方案中似乎可以避免;由于df.agg返回一个只有一行的数据帧,因此替换collecttake(1)将安全地完成这项工作:

nullColumns = []
for k in df.columns:
  if df.agg(countDistinct(df[k])).take(1)[0][0] == 0:
    nullColumns.append(k)

nullColumns
# ['D']
Run Code Online (Sandbox Code Playgroud)