Python 字符串中的Pyspark双字符替换避免某些单词而不映射到pandas或rdd
我继承了一个程序,它修改pyspark数据帧中的一些字符串。其中一个步骤涉及从字符串中的某些单词中删除双/三/etc字母,并添加一个例外列表,即使它们有重复的字母,也会被单独保留。目前,这是通过使用udf将数据帧转换为pandas来完成的,然后在读回pyspark之前,对生成的pandas数据帧中的字符串应用自定义函数。不幸的是,对需求的更改意味着代码在任何情况下都不能使用udf或映射到rdd。我需要直接在pyspark中执行相同的功能 连续字符删除函数逐字读取字符串,检查该单词是否在例外列表中,如果不在例外列表中,则逐字符移动,将其与前一个字符进行比较,如果存在匹配,则检查是否逐字符创建新单词,忽略重复 以下是pyspark数据帧转换为pandas后当前实现的MWEPython 字符串中的Pyspark双字符替换避免某些单词而不映射到pandas或rdd,python,pandas,apache-spark,pyspark,apache-spark-sql,Python,Pandas,Apache Spark,Pyspark,Apache Spark Sql,我继承了一个程序,它修改pyspark数据帧中的一些字符串。其中一个步骤涉及从字符串中的某些单词中删除双/三/etc字母,并添加一个例外列表,即使它们有重复的字母,也会被单独保留。目前,这是通过使用udf将数据帧转换为pandas来完成的,然后在读回pyspark之前,对生成的pandas数据帧中的字符串应用自定义函数。不幸的是,对需求的更改意味着代码在任何情况下都不能使用udf或映射到rdd。我需要直接在pyspark中执行相同的功能 连续字符删除函数逐字读取字符串,检查该单词是否在例外列表中
import pandas as pd
exception_list = ['ACCOUNTING', 'LOOK', 'FOOOOO']
cols = ['input']
data = [
["BOOK TOOK LOOK HOUSE SHOOK"],
["ACCOUNTING SHEEP"],
["FOO FOOO FOOOO FOOOOO FOOOOOO"]
]
df = pd.DataFrame(data, columns=cols)
df.head()
def drop_consecutive_chars(phrase, exception):
if phrase == '':
return phrase
else:
new_phrase = []
for word in phrase.split():
if word not in exception:
prev = word[0]
new_word = prev
for char in word[1:]:
if char != prev:
new_word += char
prev = char
else:
new_word = word
new_phrase += [new_word]
new_phrase = ' '.join(new_phrase)
return new_phrase
df['output'] = df['input'].apply(drop_consecutive_chars,
exception=exception_list)
df.head()
有没有办法在pyspark中做到这一点?我愿意使用RegexTokenizer之类的东西,稍后再加入它,并创建附加的真理列,这些列在之后会被删除。只需在数据帧没有离开pyspark或映射到其他任何东西的情况下完成即可。与我之前的回答类似,您可以使用高阶函数来表示Python代码的逻辑:
import pyspark.sql.functions as F
df2 = sdf.withColumn(
'exception_list',
F.array(*[F.lit(w) for w in exception_list])
).withColumn(
'output',
F.expr("""
concat_ws(' ',
transform(
split(input, ' '),
w -> case when array_contains(exception_list, w)
then w
else concat_ws('',
transform(
split(w, ''),
(c, i) -> case when i = 0 or c != split(w, '')[i-1]
then c
else ''
end
)
)
end
)
)
""")
).drop('exception_list')
df2.show(truncate=False)
+-----------------------------+-----------------------+
|input |output |
+-----------------------------+-----------------------+
|BOOK TOOK LOOK HOUSE SHOOK |BOK TOK LOOK HOUSE SHOK|
|ACCOUNTING SHEEP |ACCOUNTING SHEP |
|FOO FOOO FOOOO FOOOOO FOOOOOO|FO FO FO FOOOOO FO |
+-----------------------------+-----------------------+
与我前面的回答类似,您可以使用高阶函数来表示Python代码的逻辑:
import pyspark.sql.functions as F
df2 = sdf.withColumn(
'exception_list',
F.array(*[F.lit(w) for w in exception_list])
).withColumn(
'output',
F.expr("""
concat_ws(' ',
transform(
split(input, ' '),
w -> case when array_contains(exception_list, w)
then w
else concat_ws('',
transform(
split(w, ''),
(c, i) -> case when i = 0 or c != split(w, '')[i-1]
then c
else ''
end
)
)
end
)
)
""")
).drop('exception_list')
df2.show(truncate=False)
+-----------------------------+-----------------------+
|input |output |
+-----------------------------+-----------------------+
|BOOK TOOK LOOK HOUSE SHOOK |BOK TOK LOOK HOUSE SHOK|
|ACCOUNTING SHEEP |ACCOUNTING SHEP |
|FOO FOOO FOOOO FOOOOO FOOOOOO|FO FO FO FOOOOO FO |
+-----------------------------+-----------------------+
我有一种感觉,答案是相似的。不幸的是,我不知道表达式代码(我假设这是Scala?)。我试了一段时间想让这样的东西发挥作用,但却走错了方向。再次感谢你。现在将进行测试。这不是Scala,而是SQL。但是函数式编程方法(转换/过滤/聚合)非常像Scala,我得到了一个错误:AnalysisException:lambda函数参数“2”的数量与高阶函数“1”所需的参数数量不匹配。它指向表达式内部的某个地方,可能在w->array\u contains行,但我不能确定。你的spark版本是什么?2.4?我将代码更改为与spark 2.4兼容。我感觉答案会类似。不幸的是,我不知道表达式代码(我假设这是Scala?)。我试了一段时间想让这样的东西发挥作用,但却走错了方向。再次感谢你。现在将进行测试。这不是Scala,而是SQL。但是函数式编程方法(转换/过滤/聚合)非常像Scala,我得到了一个错误:AnalysisException:lambda函数参数“2”的数量与高阶函数“1”所需的参数数量不匹配。它指向表达式内部的某个地方,可能在w->array\u contains行,但我不能确定。你的spark版本是什么?2.4?我将代码更改为与spark 2.4兼容。