使用Pyspark过滤包含None值的数据框列

177

我正在尝试过滤一个 PySpark 数据框,其中包含 None 作为行值:

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

但是每个类别肯定都有价值观。发生了什么?


2
您实际上想要过滤掉具有空值的行,而不是列中的无值。标题可能会误导人。 - Atorpat
简而言之,涉及到null(或在此情况下为None)的比较总是返回false。特别地,比较(null == null)返回false。同样,比较(None == None)也返回false。 - Richard Gomes
12个回答

313
你可以使用 Column.isNull/Column.isNotNull
df.where(col("dt_mvmt").isNull())

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

如果您想简单地删除 NULL 值,可以使用带有 subset 参数的 na.drop

Translated content:

如果您想简单地删除 NULL 值,可以使用带有 subset 参数的 na.drop

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 方法。


2
太棒了,谢谢。我本以为PySpark数据框架上的这些过滤器会更符合“Pythonic”的风格,但是它们并不是。我正在考虑向开发人员询问此事。 - Ivan
1
实际上这很符合Python的风格。你不应该使用__eq__来检查None ;) 而且is也不会起作用,因为它的行为方式不同。 - zero323
2
奇怪的是,这只适用于字符串列...似乎 df.filter("dt_mvmt is not NULL") 可以处理两者。 - David Arenburg

47

尝试仅使用 isNotNull 函数。

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

22
为了获取在dt_mvmt列中值不为null的条目,我们需要:
df.filter("dt_mvmt is not NULL")

对于那些为空的条目,我们有

df.filter("dt_mvmt is NULL")

9

您可以以多种方式从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.

你还可以查看我博客中的“处理NULL值”部分以获取更多信息。希望它能有所帮助。

7

isNull()/isNotNull()将返回具有dt_mvmt为Null或!Null的各自行。

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

两者将返回相同的结果


3

如果 column = None

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

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

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

那么请使用: column_old_value='None'

2

None/Null是PySpark/Python中NoneType类的数据类型。因此,以下代码将无法正常工作,因为你试图比较NoneType对象和字符串对象。

错误的筛选方式
df[df.dt_mvmt == None].count()

0

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

0

correct

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

返回所有具有 dt_mvmt 为 None/Null 的记录。


2
如果您希望保持Pandas语法,这对我很有效。
df = df[df.dt_mvmt.isNotNull()]

1

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

1
如果您想过滤掉列中的空值记录,请参考以下示例:
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()

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