鉴于以下数据框,我想将数字列拆分为一个数组,其中数组中原始数字的每个元素包含3个字符
给出数据框:
+---+------------------+
| id| numbers|
+---+------------------+
|742| 000000000|
|744| 000000|
|746|003000000000000000|
+---+------------------+
预期的数据框:
+---+----------------------------------+
| id| numbers |
+---+----------------------------------+
|742| [000, 000, 000] |
|744| [000, 000] |
|746| [003, 000, 000, 000, 000, 000] |
+---+----------------------------------+
我在使用下面给出的split
函数和正则表达式时尝试了不同的正则表达式,我觉得应该在第一次尝试时就可以使用:
import pyspark.sql.functions as f
df = spark.createDataFrame(
[
[742, '000000000'],
[744, '000000'],
[746, '003000000000000000'],
],
["id", "numbers"]
)
df = df.withColumn("numbers", f.split("numbers", "[0-9]{3}"))
df.show()
结果是
+---+--------------+
| id| numbers|
+---+--------------+
|742| [, , , ]|
|744| [, , ]|
|746|[, , , , , , ]|
+---+--------------+
我想了解我在做什么错。是否可以设置用于获取所有匹配项的全局标志,或者我完全错过了正则表达式中的某些内容?
答案 0 :(得分:2)
split
将删除字符串被分割的模式;您需要为此创建一个udf:
from pyspark.sql.functions import udf
from pyspark.sql.types import ArrayType, StringType
import re
# create a udf with re.findall
split_by_three = f.udf(lambda s: re.findall(r'\d{3}', s), ArrayType(StringType()))
df.withColumn('numbers', split_by_three('numbers')).show(3, False)
#+---+------------------------------+
#|id |numbers |
#+---+------------------------------+
#|742|[000, 000, 000] |
#|744|[000, 000] |
#|746|[003, 000, 000, 000, 000, 000]|
#+---+------------------------------+
df.withColumn('numbers', split_by_three('numbers')).printSchema()
#root
# |-- id: long (nullable = true)
# |-- numbers: array (nullable = true)
# | |-- element: string (containsNull = true)
答案 1 :(得分:2)
以下是不使用udf
的方法:
df = df.withColumn(
"numbers",
f.split(f.regexp_replace("numbers", "([0-9]{3})(?!$)", r"$1,"), ",")
)
df.show(truncate=False)
#+---+------------------------------+
#|id |numbers |
#+---+------------------------------+
#|742|[000, 000, 000] |
#|744|[000, 000] |
#|746|[003, 000, 000, 000, 000, 000]|
#+---+------------------------------+
首先使用pyspark.sql.functions.regexp_replace
将3位数的序列替换为后跟逗号的序列。然后用逗号分割结果字符串。
替换模式"$1,"
表示第一个捕获组,后跟一个逗号。
在匹配模式中,我们还为字符串的末尾(?!$)
加上了一个负号,以避免在字符串的末尾添加逗号。
答案 2 :(得分:1)
@pault和@Psidom方式都很棒!这是另一种选择;
>>> split_udf = F.udf(lambda x: ','.join([''.join(i) for i in zip(*[iter(x)]*3)]))
>>> df.withColumn('numbers', F.split(split_udf('numbers'),',')).show(truncate=False)
+---+------------------------------+
|id |numbers |
+---+------------------------------+
|742|[000, 000, 000] |
|744|[000, 000] |
|746|[003, 000, 000, 000, 000, 000]|
+---+------------------------------+