【问题标题】:Filter Pyspark dataframe column with None value使用 None 值过滤 Pyspark 数据框列
【发布时间】:2016-09-12 18:21:34
【问题描述】:

我正在尝试过滤具有 None 作为行值的 PySpark 数据框:

df.select('dt_mvmt').distinct().collect()

[Row(dt_mvmt=u'2016-03-27'),
 Row(dt_mvmt=u'2016-03-28'),
 Row(dt_mvmt=u'2016-03-29'),
 Row(dt_mvmt=None),
 Row(dt_mvmt=u'2016-03-30'),
 Row(dt_mvmt=u'2016-03-31')]

我可以用字符串值正确过滤:

df[df.dt_mvmt == '2016-03-31']
# some results here

但这失败了:

df[df.dt_mvmt == None].count()
0
df[df.dt_mvmt != None].count()
0

但每个类别肯定都有价值。怎么回事?

【问题讨论】:

  • 您实际上想要过滤具有空值的行,而不是具有无值的列。标题可能具有误导性。
  • 简而言之,涉及 null(或 None,在这种情况下)的比较总是返回 false。特别是,比较 (null == null) 返回 false。此外,比较 (None == None) 返回 false。

标签: python apache-spark dataframe pyspark apache-spark-sql


【解决方案1】:

isNull()/isNotNull() 将返回 dt_mvmt 为 Null 或 !Null 的相应行。

method_1 = df.filter(df['dt_mvmt'].isNotNull()).count()
method_2 = df.filter(df.dt_mvmt.isNotNull()).count()

两者都将返回相同的结果

【讨论】:

    【解决方案2】:

    None/Null 是 pyspark/python 中 NoneType 类的数据类型 因此,当您尝试将 NoneType 对象与字符串对象进行比较时,下面将不起作用

    错误的过滤方式

    df[df.dt_mvmt == None].count() 0 df[df.dt_mvmt != None].count() 0

    正确

    df=df.where(col("dt_mvmt").isNotNull()) 返回所有 dt_mvmt 为 None/Null 的记录

    【讨论】:

      【解决方案3】:

      有多种方法可以从 DataFrame 的列中删除/过滤空值。

      让我们用下面的代码创建一个简单的DataFrame:

      date = ['2016-03-27','2016-03-28','2016-03-29', None, '2016-03-30','2016-03-31']
      df = spark.createDataFrame(date, StringType())
      

      现在您可以尝试以下方法之一来过滤掉空值。

      # Approach - 1
      df.filter("value is not null").show()
      
      # Approach - 2
      df.filter(col("value").isNotNull()).show()
      
      # Approach - 3
      df.filter(df["value"].isNotNull()).show()
      
      # Approach - 4
      df.filter(df.value.isNotNull()).show()
      
      # Approach - 5
      df.na.drop(subset=["value"]).show()
      
      # Approach - 6
      df.dropna(subset=["value"]).show()
      
      # Note: You can also use where function instead of a filter.
      

      您还可以查看我的blog 上的“使用 NULL 值”部分了解更多信息。

      希望对你有帮助。

      【讨论】:

        【解决方案4】:

        如果您想继续使用 Pandas 语法,这对我有用。

        df = df[df.dt_mvmt.isNotNull()]
        

        【讨论】:

          【解决方案5】:

          如果列 = 无

          COLUMN_OLD_VALUE
          ----------------
          None
          1
          None
          100
          20
          ------------------
          

          使用 在数据框上创建一个临时表:

          sqlContext.sql("select * from tempTable where column_old_value='None' ").show()
          

          所以使用:column_old_value='None'

          【讨论】:

            【解决方案6】:

            如果您想过滤掉列中没有值的记录,请参见下面的示例:

            df=spark.createDataFrame([[123,"abc"],[234,"fre"],[345,None]],["a","b"])
            

            现在过滤掉空值记录:

            df=df.filter(df.b.isNotNull())
            
            df.show()
            

            如果您想从 DF 中删除这些记录,请参见下文:

            df1=df.na.drop(subset=['b'])
            
            df1.show()
            

            【讨论】:

              【解决方案7】:

              PySpark 提供基于算术、逻辑和其他条件的各种过滤选项。 NULL 值的存在可能会妨碍进一步的处理。删除它们或统计估算它们可能是一种选择。

              可以考虑以下一组代码:

              # Dataset is df
              # Column name is dt_mvmt
              # Before filtering make sure you have the right count of the dataset
              df.count() # Some number
              
              # Filter here
              df = df.filter(df.dt_mvmt.isNotNull())
              
              # Check the count to ensure there are NULL values present (This is important when dealing with large dataset)
              df.count() # Count should be reduced if NULL values are present
              

              【讨论】:

                【解决方案8】:

                要获取dt_mvmt 列中的值不为空的条目,我们有

                df.filter("dt_mvmt is not NULL")
                

                对于为空的条目,我们有

                df.filter("dt_mvmt is NULL")
                

                【讨论】:

                  【解决方案9】:

                  你可以使用Column.isNull/Column.isNotNull:

                  df.where(col("dt_mvmt").isNull())
                  
                  df.where(col("dt_mvmt").isNotNull())
                  

                  如果您想简单地删除 NULL 值,您可以使用 na.dropsubset 参数:

                  df.na.drop(subset=["dt_mvmt"])
                  

                  NULL 的基于相等的比较将不起作用,因为在SQL 中NULL 未定义,因此任何将其与另一个值进行比较的尝试都会返回NULL

                  sqlContext.sql("SELECT NULL = NULL").show()
                  ## +-------------+
                  ## |(NULL = NULL)|
                  ## +-------------+
                  ## |         null|
                  ## +-------------+
                  
                  
                  sqlContext.sql("SELECT NULL != NULL").show()
                  ## +-------------------+
                  ## |(NOT (NULL = NULL))|
                  ## +-------------------+
                  ## |               null|
                  ## +-------------------+
                  

                  NULL 比较值的唯一有效方法是IS / IS NOT,它们等效于isNull / isNotNull 方法调用。

                  【讨论】:

                  • 太棒了,谢谢。我认为 PySpark 数据帧上的这些过滤器会更“pythonic”,但唉,事实并非如此。我正在考虑向开发人员询问这个问题。
                  • 其实它很 Pythonic。你永远不应该检查 __eq__ 和 None ;) 并且 is 不起作用,因为它的行为方式不同。
                  • 奇怪的是,这仅适用于字符串列...似乎df.filter("dt_mvmt is not NULL") 处理两者。
                  【解决方案10】:

                  尝试只使用isNotNull 函数。

                  df.filter(df.dt_mvmt.isNotNull()).count()
                  

                  【讨论】:

                    猜你喜欢
                    • 2019-03-07
                    • 1970-01-01
                    • 2020-09-22
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-08-19
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多