如何使用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-我认为这可能是最好的。