如何高效地在PySpark数据框中找到每列的Null和Nan值的数量?

108
import numpy as np

data = [
    (1, 1, None), 
    (1, 2, float(5)), 
    (1, 3, np.nan), 
    (1, 4, None), 
    (1, 5, float(10)), 
    (1, 6, float("nan")), 
    (1, 6, float("nan")),
]
df = spark.createDataFrame(data, ("session", "timestamp1", "id2"))

期望输出

每列nan/null计数的数据框

注意:我在Stack Overflow上发现的之前的问题只检查null而不是nan,这就是为什么我创建了一个新的问题。

我知道我可以使用Spark中的isnull()函数来查找Spark列中Null值的数量,但如何在Spark数据框中找到Nan值呢?


有没有关于 scala 的解决方案? - DachuanZhao
12个回答

200
你可以使用这里展示的方法,将isNull替换为isnan
from pyspark.sql.functions import isnan, when, count, col

df.select([count(when(isnan(c), c)).alias(c) for c in df.columns]).show()
+-------+----------+---+
|session|timestamp1|id2|
+-------+----------+---+
|      0|         0|  3|
+-------+----------+---+
或者
df.select([count(when(isnan(c) | col(c).isNull(), c)).alias(c) for c in df.columns]).show()
+-------+----------+---+
|session|timestamp1|id2|
+-------+----------+---+
|      0|         0|  5|
+-------+----------+---+

19
isNullisnan。这两个链接将对您有所帮助。 "isnan()" 是 pysparq.sql.function 包的一个函数,因此您必须设置要用作函数参数的列。 "isNull()" 属于 pyspark.sql.Column 包,因此您需要执行的操作是 "yourColumn.isNull()"。 - titiro89
我在使用df.select([count(when(isnan(c) | col(c).isNull(), c)).alias(c) for c in df.columns]).show()时遇到了错误 - 我需要导入任何库吗?我得到的错误是简单表达式的非法开始。 - user5751943
2
此解决方案不适用于时间戳列。 - Eric Bellet
3
@EricBellet 对于时间戳列,您可以使用 df.dtypesdf.select([f.count(f.when(f.isnan(c), c)).alias(c) for c, t in df.dtypes if t != "timestamp"]).show() - elcombato
Scala的等效写法:df.select(df.columns.map(c => count(when(isnan(col(c)), c)).alias(c)):_*) - Anthony Awuley
scala: df.select(df.columns.map(c => count(when(isnan(col(c)) || col(c).isNull, c)).alias(c)):_*).show() Scala:df.select(df.columns.map(c=>count(when(isnan(col(c))|| col(c)。isNull,c))。alias(c)):_*)。show() - Anthony Awuley

26

对于Pyspark数据框中的空值

Dict_Null = {col:df.filter(df[col].isNull()).count() for col in df.columns}
Dict_Null

# The output in dict where key is column name and value is null values in that column

{'#': 0,
 'Name': 0,
 'Type 1': 0,
 'Type 2': 386,
 'Total': 0,
 'HP': 0,
 'Attack': 0,
 'Defense': 0,
 'Sp_Atk': 0,
 'Sp_Def': 0,
 'Speed': 0,
 'Generation': 0,
 'Legendary': 0}

17
为了确保不会出现针对 stringdatetimestamp 列的失败情况:
import pyspark.sql.functions as F
def count_missings(spark_df,sort=True):
    """
    Counts number of nulls and nans in each column
    """
    df = spark_df.select([F.count(F.when(F.isnan(c) | F.isnull(c), c)).alias(c) for (c,c_type) in spark_df.dtypes if c_type not in ('timestamp', 'string', 'date')]).toPandas()

    if len(df) == 0:
        print("There are no any missing values!")
        return None

    if sort:
        return df.rename(index={0: 'count'}).T.sort_values("count",ascending=False)

    return df

如果你想根据NaN和null的数量降序排序列:

count_missings(spark_df)

# | Col_A | 10 |
# | Col_C | 2  |
# | Col_B | 1  | 
如果您不想排序并将它们视为单行:
count_missings(spark_df, False)
# | Col_A | Col_B | Col_C |
# |  10   |   1   |   2   |

2
这个函数在处理大数据集时计算成本很高。 - Rio
你为什么这样认为? - gench
1
将“boolean”和“binary”添加到您的非排除列表中。 - Pat Stroh
1
危险的,因为在任何排除类型中静默忽略了“Null”。 - ijoseph
在 PySpark 3 上失败,显示“'float'对象没有'tzinfo'属性”。 - Alexander Verner

6

除了已提供的方法之外,另一种方法是直接使用列过滤器,如下所示:

import pyspark.sql.functions as F
df = df.where(F.col('columnNameHere').isNull())

这有一个额外的好处,就是你不需要添加另一列进行过滤,并且对于大型数据集来说速度比较快。


2
覆盖了df,可能不是预期的结果。OP要求计数,应该使用x.where(col(colname).isNull()).count(),其中x是一个数据框,colname是一个字符串。 - pauljohn32
我可能漏掉了什么@pauljohn32,但在我看来,你的建议与我的回答完全相同,只是在最后添加了对count()的调用。我认为我的回答已经清楚地展示了如何进行过滤。在最后添加df.count()应该被视为一个微不足道的补充,不是吗? - Patrik Iselind

4

这是我的一行代码。 这里的“c”是列的名称。

from pyspark.sql.functions import isnan, when, count, col, isNull
    
df.select('c').withColumn('isNull_c',F.col('c').isNull()).where('isNull_c = True').count()

1
我更喜欢这个解决方案:

df = spark.table(selected_table).filter(condition)

counter = df.count()

df = df.select([(counter - count(c)).alias(c) for c in df.columns])

0

另一种选择(在Vamsi Krishna的解决方案上进行了改进):

def check_for_null_or_nan(df):
    null_or_nan = lambda x: isnan(x) | isnull(x)
    func = lambda x: df.filter(null_or_nan(x)).count()
    print(*[f'{i} has {func(i)} nans/nulls' for i in df.columns if func(i)!=0],sep='\n')

检查空值或NaN(df)


id2有5个NaN或null值


0
使用以下代码使用pyspark识别每个列中的null值:
def check_nulls(dataframe):
    '''
    Check null values and return the null values in pandas Dataframe
    
    INPUT: Spark Dataframe
    OUTPUT: Null values
    
    '''
    # Create pandas dataframe
    nulls_check = pd.DataFrame(dataframe.select([count(when(isnull(c), c)).alias(c) for c in dataframe.columns]).collect(),
                               columns = dataframe.columns).transpose()
    nulls_check.columns = ['Null Values']
    return nulls_check

#Check null values
null_df = check_nulls(raw_df)
null_df

如果数据大小为1TB会发生什么?不要转换为pandas,这样做违背了使用Spark的初衷。 - Aviad Rozenhek

0

这里有一个易读的解决方案,因为代码不仅是给计算机看的,也是给人看的 ;-)

df.selectExpr('sum(int(isnull(<col_name>) or isnan(<col_name>))) as null_or_nan_count'))

0
如果你正在编写Spark SQL,那么以下代码也可以用来查找空值并计数。 spark.sql('select * from table where isNULL(column_value)')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接