首页 > 解决方案 > 检查pyspark中是否有NA的有效方法

问题描述

我有一个 pyspark 数据框,名为df. 我想知道他的列是否包含 NA,我不在乎它只是一行还是全部。问题是,我目前知道是否有 NA 的方法是:

from pyspark.sql import functions as F

if (df.where(F.isnull('column_name')).count() >= 1):
    print("There are nulls")
else:
    print("Yey! No nulls")

我在这里看到的问题是,我需要计算整列中的空值数量,这会浪费大量时间,因为我希望进程在找到第一个空值时停止。

我考虑过这个解决方案,但我不确定它是否有效(因为我在一个有很多其他人的集群中工作,所以执行时间取决于其他人在集群中运行的多个作业,所以我无法比较这两种方法在均匀的条件下):

(df.where(F.isnull('column_name')).limit(1).count() == 1)

添加限制有帮助吗?有没有更有效的方法来实现这一目标?

标签: pyspark

解决方案


对于不存在的东西,没有非穷尽的搜索。

对于具有值的记录存在的情况(见下文),我们可能可以从您的查询中挤出更多的性能null,但是当它不存在时呢?如果您计划多次运行此查询,并且每次都更改答案,那么您应该知道(我并不是暗示您不是)如果答案是“null整个数据帧”,那么您将不得不扫描整个数据帧才能知道这一点,并且没有快速的方法可以做到这一点。如果您经常需要此类信息并且答案可能经常为“否”,那么您几乎肯定会希望将此类信息保存在某个地方,并在您插入可能具有null值的记录时通过仅检查该记录来更新它。

不要使用计数()。

count() 可能会让事情变得更糟。

  • 在 count 案例中,Spark 使用了广泛的转换,实际上在每个分区上应用了 LocalLimit 并打乱部分结果以执行 GlobalLimit。
  • 在这种情况下,Spark 使用窄转换并仅在第一个分区上评估 LocalLimit。

换句话说,可能会.limit(1).count()先从数据集的每个分区中选择一个示例,然后再从该示例列表中选择一个示例。您的意图是在找到一个示例后立即中止,但不幸的是,它似乎不够聪明,无法自行实现。count()

但是,正如同一个示例所暗示的,您可以使用take()first()head()来实现您想要的用例。这将更有效地限制检查的分区数量:

如果不需要 shuffle(不需要聚合、连接或排序),这些操作将被优化以检查足够的分区来满足操作 - 可能是数据集整体分区的一个小得多的子集。

请注意,在其他情况下count() 可能会更高效。正如另一个 SO 问题正确指出的那样,

一般来说,两者都不能保证更好的性能。

你可以做的可能更多。

根据您的存储方法和架构,您可能能够从查询中获得更多性能。

  • 由于您甚至对在这种情况下选择的行的值不感兴趣,因此您可以select(F.lit(True))在 yourisnull和 your之间添加一个take. 从理论上讲,这应该会减少集群中的工作人员需要传输的信息量。如果您只有几列简单类型,这不太重要,但如果您有复杂的数据结构,这会有所帮助并且不太可能造成伤害。
  • 如果您知道您的数据是如何分区的,并且您知道您对哪个分区感兴趣,或者对哪个分区(如果有)可能包含null值有很好的猜测,那么您绝对应该通过以下方式过滤您的数据框该分区以加快您的查询速度。

推荐阅读