我有一个元素列表,可能会启动RDD中记录的几个字符串。如果我有yes
和no
的元素列表,则它们应与yes23
和no3
匹配,但不能与35yes
或41no
匹配。使用pyspark,我如何在列表或元组中使用startswith
任何元素。
示例DF将是:
+-----+------+
|index| label|
+-----+------+
| 1|yes342|
| 2| 45yes|
| 3| no123|
| 4| 75no|
+-----+------+
当我尝试:
Element_List = ['yes','no']
filter_DF = DF.where(DF.label.startswith(tuple(Element_List)))
生成的df应该类似于:
+-----+------+
|index| label|
+-----+------+
| 1|yes342|
| 3| no123|
+-----+------+
相反,我得到错误:
Py4JError: An error occurred while calling o250.startsWith. Trace:
py4j.Py4JException: Method startsWith([class java.util.ArrayList]) does not exist
at py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.java:318)
at py4j.reflection.ReflectionEngine.getMethod(ReflectionEngine.java:326)
at py4j.Gateway.invoke(Gateway.java:272)
at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
at py4j.commands.CallCommand.execute(CallCommand.java:79)
at py4j.GatewayConnection.run(GatewayConnection.java:214)
at java.lang.Thread.run(Thread.java:745)
提示,因此看起来startsWith
无法与任何类型的列表一起使用。有一个简单的工作吗?
答案 0 :(得分:7)
像这样编写表达式:
from pyspark.sql.functions import col, lit
from functools import reduce
element_list = ['yes','no']
df = spark.createDataFrame(
["yes23", "no3", "35yes", """41no["maybe"]"""],
"string"
).toDF("location")
starts_with = reduce(
lambda x, y: x | y,
[col("location").startswith(s) for s in element_list],
lit(False))
df.where(starts_with).show()
# +--------+
# |location|
# +--------+
# | yes23|
# | no3|
# +--------+
答案 1 :(得分:0)
我觉得最好的方法是使用像“rlike()”这样的原生pyspark函数。 startswith() 用于过滤静态字符串。 不能接受动态内容。如果您想从列表中动态获取关键字;最好的办法是从下面的列表中创建一个正则表达式。
# List
li = ['yes', 'no']
# frame RegEx from the List
# in this case strings starting with yes/no i.e. "^(yes|no)"
reg_str = r"^("+ "|".join(li) + ")"
自定义 Udfs 或使用 RDD 函数可能很有效,但使用自定义 Udfs 可能会影响性能。
以下是完整的工作示例。
#Test Dataframe
df = spark.createDataFrame(
["yes23", "no3", "35yes"],
"string"
).toDF("label")
# List
li = ['yes', 'no']
# frame RegEx from the List
# in this case strings starting with yes/no i.e. "^(yes|no)"
reg_str = r"^("+ "|".join(li) + ")"
#Filter dataframe with RegEx
df.filter(df.label.rlike(reg_str)).show()
# +--------+
# |label |
# +--------+
# | yes23|
# | no3|
# +--------+