如何使用PySpark数据帧选择给定元组列表的行?

如何使用PySpark数据帧选择给定元组列表的行?,pyspark,Pyspark,假设我们有一个数据帧,如下所示: +--------+--------------+-----+--------------------+ |援助|出价|价值|时间| +--------+--------------+-----+--------------------+ | 1| 1| 81.0|2006-08-25 14:13:...| | 1| 1| 81.0|2006-08-25 14:27:...| |

假设我们有一个
数据帧
,如下所示:

+--------+--------------+-----+--------------------+
|援助|出价|价值|时间|
+--------+--------------+-----+--------------------+
|       1|             1| 81.0|2006-08-25 14:13:...|
|       1|             1| 81.0|2006-08-25 14:27:...|
|       1|             2| 81.0|2006-08-25 14:56:...|
|       1|             2| 81.0|2006-08-25 15:00:...|
|       1|             3| 81.0|2006-08-25 15:31:...|
|       1|             3| 81.0|2006-08-25 15:38:...|
|       1|             4|  0.0|2006-08-30 11:59:...|
|       1|             4|  0.0|2006-08-30 13:59:...|
|       2|             1|  0.0|2006-08-30 12:11:...|
|       2|             1|  0.0|2006-08-30 14:13:...|
|       2|             2|  0.0|2006-08-30 12:30:...|
|       2|             2|  0.0|2006-08-30 14:30:...|
|       2|             3|  0.0|2006-09-05 12:29:...|
|       2|             3|  0.0|2006-09-05 14:31:...|
|       3|             1|  0.0|2006-09-05 12:42:...|
|       3|             1|  0.0|2006-09-05 14:43:...|
+--------+--------------+-----+--------------------+
我知道我能做到:

df_数据。其中(col('bid'))
.isin([1,2,3]).show()
为了仅选择具有
[1,2,3]
之一的
bid
的行

但是,我希望能够基于两列
aid
bid
的元组列表
[(1,1)、(2,2)、(3,1)]
选择子集

所以基本上是“类似”

df_数据。其中(列(['aid','bid']))
.isin([(1,1)、(2,2)、(3,1)]).show()
有办法做到这一点吗

我可以想象这样的情况:

sql.sql('SELECT*FROM df_data,其中((1,1))中的(scope_id,measurement_id)'))
但这将导致:

AnalysisException:“由于数据类型不匹配,无法解析(struct(1,1))中的”(struct(df_data.`aid`,df_data.`bid`),参数必须是相同的类型;第1行位置55”

另一个选项是

>>> df.show()
+---+---+
|aid|bid|
+---+---+
|  1|  1|
|  1|  2|
|  1|  3|
|  2| 10|
|  2| 12|
+---+---+

>>> checkList = [(1,2),(2,12),(1,100)]
>>> df.rdd.filter(lambda (x,y): (x,y) in checkList).toDF().show()
+---+---+
|aid|bid|
+---+---+
|  1|  2|
|  2| 12|
+---+---+

我可以想出三种方法

方法1:使用
reduce
帮助检查所有条件 [(1,1)、(2,2)、(3,1)]中的伪码
(s,m)相当于:

(s==1和m==1)或(s==2和m==2)或(s==3和m==3)
您可以使用列表理解和
reduce
检查所有这些条件

导入pyspark.sql.f函数
检查表=[(1,1)、(2,2)、(3,1)]
在哪里(
减少(
λu,v:u | v,
[(f.col(“aid”)==x)和(f.col(“bid”)==y)检查表中的(x,y)]
)
)\
.选择(“援助”、“投标”、“价值”)\
.show()
#+---+---+-----+
#|援助|投标|价值|
#+---+---+-----+
#|  1|  1| 81.0|
#|  1|  1| 81.0|
#|  2|  2|  0.0|
#|  2|  2|  0.0|
#|  3|  1|  0.0|
#|  3|  1|  0.0|
#+---+---+-----+
方法2:将ID连接为字符串 创建一个临时列作为两个
id
列的字符串连接。然后检查该字符串是否与字符串列表匹配

check_list=[(1,1)、(2,2)、(3,1)]
检查列表\u str=[“,”。检查列表中项目的join([str(x)表示项目中的x])
df.带列(“组合id”、f.concat(f.col(“援助”)、f.lit(“,”)和f.col(“投标”))\
.其中(f.col(“组合id”).isin(检查列表)\
.选择(“援助”、“投标”、“价值”)\
.show()
#+---+---+-----+
#|援助|投标|价值|
#+---+---+-----+
#|  1|  1| 81.0|
#|  1|  1| 81.0|
#|  2|  2|  0.0|
#|  2|  2|  0.0|
#|  3|  1|  0.0|
#|  3|  1|  0.0|
#+---+---+-----+
方法3:使用自定义项 创建
udf
以检查布尔条件

check_list=[(1,1)、(2,2)、(3,1)]
check_id_isin=f.udf(lambda x,y:(x,y)在check_列表中,BooleanType())
df.where(检查识别码(f.col(“aid”)、f.col(“bid”))==True)\
.选择(“援助”、“投标”、“价值”)\
.show()
#+---+---+-----+
#|援助|投标|价值|
#+---+---+-----+
#|  1|  1| 81.0|
#|  1|  1| 81.0|
#|  2|  2|  0.0|
#|  2|  2|  0.0|
#|  3|  1|  0.0|
#|  3|  1|  0.0|
#+---+---+-----+
编辑作为@StefanFalk,可以将
udf更一般地写为:

check_id_isin=f.udf(检查列表中的lambda*idx:idx,BooleanType())

这将允许可变数量的输入参数。

Huh,不知何故,我的雷达上仍然没有
udf
s。我甚至认为可以编写
f.udf(lambda*tup:tup in check\u list,BooleanType())
——这应该允许
check\u id\u isin的参数数量可变。在这一点上,方法3是我最喜欢的:)@StefanFalk是的,那也行。我通常尽量避免使用
udf
,因为它们速度较慢,但有时这是实现复杂函数的唯一方法。检查我更新的方法1-我认为这可能是最好的。