首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >PySpark DataFrames -使用不同类型列之间的比较进行过滤

问PySpark DataFrames -使用不同类型列之间的比较进行过滤
EN

Stack Overflow用户
提问于 2019-01-31 10:07:35
回答 1查看 2.3K关注 0票数 2

假设您有一个具有各种类型列(string,double.)的dataframe以及在字符串类型列中表示“缺失值”的特殊值“想念”。

代码语言:javascript
复制
from pyspark.sql import SparkSession
import pandas as pd

spark = SparkSession.builder.getOrCreate()

pdf = pd.DataFrame([
    [1, 'miss'],
    [2, 'x'],
    [None, 'y']
], columns=['intcol', 'strcol'])

df = spark.createDataFrame(data=pdf)

我正在尝试计算每一列的未丢失值的数量,使用如下过滤:

代码语言:javascript
复制
col = df['strcol']
df.filter(col.isNotNull() & (col != 'miss')).show()

它适用于string列:

代码语言:javascript
复制
+------+------+
|intcol|strcol|
+------+------+
|   2.0|     x|
|   NaN|     y|
+------+------+

但是,对于数值列,它过滤掉所有行:

代码语言:javascript
复制
col = df['intcol']
df.filter(col.isNotNull() & (col != 'miss')).show()
代码语言:javascript
复制
+------+------+
|intcol|strcol|
+------+------+
+------+------+

这似乎是因为数值列与字符串值的跨类型比较导致了所有空值:

代码语言:javascript
复制
df.select(df['intcol'] != 'miss').show()
代码语言:javascript
复制
+---------------------+
|(NOT (intcol = miss))|
+---------------------+
|                 null|
|                 null|
|                 null|
+---------------------+

我觉得这有点出乎意料(例如,1 != ''是真的,在“普通”Python中不是空的)

我的问题实际上是几个问题:

  • 为什么跨类型比较会导致空值?
  • 在“期望方式”中测试不同类型之间的平等/不平等的最佳方法是什么?或者(在我的例子中),我是否需要包含根据列的类型切换的独立逻辑?
  • 似乎是df.filter(~df['intcol'].isin(['miss']))做了这项工作,但我不知道这是否会降低效率?
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-01-31 11:33:34

我们先来说说原因。SQL是一个适用于DataFrame和SQL计算规则的DSL。每当您对不同类型的对象应用运算符时,都会根据预定义的规则在优先级较低的操作数上应用CAST操作。因此,在一般的数值类型中,具有更高的优先级(按照执行计划df.select(df['intcol'] != 'miss').explain(True)):

代码语言:javascript
复制
== Parsed Logical Plan ==
'Project [NOT (intcol#0 = miss) AS (NOT (intcol = miss))#12]
+- LogicalRDD [intcol#0, strcol#1], false

被重写为

代码语言:javascript
复制
== Analyzed Logical Plan ==
(NOT (intcol = miss)): boolean
Project [NOT (intcol#0 = cast(miss as double)) AS (NOT (intcol = miss))#12]
+- LogicalRDD [intcol#0, strcol#1], false

其中'miss'是CASTED到double,然后转换为NULL

代码语言:javascript
复制
== Optimized Logical Plan ==
Project [null AS (NOT (intcol = miss))#22]
+- LogicalRDD [intcol#0, strcol#1], false

此操作数的强制转换是未定义的。

由于与NULL的等式也是未定义的- Difference between === null and isNull in Spark DataDrame - filter将产生一个空结果。

现在该如何解决这个问题。两种显式铸造:

代码语言:javascript
复制
df.filter(df['intcol'].cast("string") != 'miss')

以及无效的安全相等:

代码语言:javascript
复制
df.filter(~df['intcol'].cast("string").eqNullSafe('miss'))

应该能起作用。

另外,请注意,NaN值不是NULL,通过Pandas的转换是有损的- Pandas dataframe to Spark dataframe, handling NaN conversions to actual null?。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54458070

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档