Pyspark DataFrame:将具有多个值的列拆分为行
Pyspark DataFrame: Split column with multiple values into rows
我有一个数据框(有更多行和列),如下所示。
样本 DF:
from pyspark import Row
from pyspark.sql import SQLContext
from pyspark.sql.functions import explode
sqlc = SQLContext(sc)
df = sqlc.createDataFrame([Row(col1 = 'z1', col2 = '[a1, b2, c3]', col3 = 'foo')])
# +------+-------------+------+
# | col1| col2| col3|
# +------+-------------+------+
# | z1| [a1, b2, c3]| foo|
# +------+-------------+------+
df
# DataFrame[col1: string, col2: string, col3: string]
我想要的:
+-----+-----+-----+
| col1| col2| col3|
+-----+-----+-----+
| z1| a1| foo|
| z1| b2| foo|
| z1| c3| foo|
+-----+-----+-----+
我尝试复制此处提供的 RDD
解决方案:
(df
.rdd
.flatMap(lambda row: [(row.col1, col2, row.col3) for col2 in row.col2)])
.toDF(["col1", "col2", "col3"]))
但是,它没有给出所需的结果
编辑:explode
选项不起作用,因为它当前存储为字符串,而 explode
函数需要一个数组
您可以使用 explode
但首先您必须将数组的字符串表示形式转换为数组。
一种方法是在 ", "
上使用 regexp_replace
to remove the leading and trailing square brackets, followed by split
。
from pyspark.sql.functions import col, explode, regexp_replace, split
df.withColumn(
"col2",
explode(split(regexp_replace(col("col2"), "(^\[)|(\]$)", ""), ", "))
).show()
#+----+----+----+
#|col1|col2|col3|
#+----+----+----+
#| z1| a1| foo|
#| z1| b2| foo|
#| z1| c3| foo|
#+----+----+----+
Pault 的解决方案应该可以很好地工作,尽管这是另一个使用 regexp_extract
的解决方案(在这种情况下您实际上不需要替换任何东西)并且它可以处理任意数量的空格:
from pyspark.sql.functions import col, explode, regexp_extract,regexp_replace, split
df.withColumn("col2",
explode(
split(
regexp_extract(
regexp_replace(col("col2"), "\s", ""), "^\[(.*)\]$", 1), ","))) \
.show()
解释:
- 最初
regexp_replace(col("col2"), "\s", "")
将用空字符串替换所有空格。
- 接下来
regexp_extract
将提取以[
开始并以]
结束的列的内容。
- 然后我们对逗号分隔值执行
split
,最后执行 explode
.
我有一个数据框(有更多行和列),如下所示。
样本 DF:
from pyspark import Row
from pyspark.sql import SQLContext
from pyspark.sql.functions import explode
sqlc = SQLContext(sc)
df = sqlc.createDataFrame([Row(col1 = 'z1', col2 = '[a1, b2, c3]', col3 = 'foo')])
# +------+-------------+------+
# | col1| col2| col3|
# +------+-------------+------+
# | z1| [a1, b2, c3]| foo|
# +------+-------------+------+
df
# DataFrame[col1: string, col2: string, col3: string]
我想要的:
+-----+-----+-----+
| col1| col2| col3|
+-----+-----+-----+
| z1| a1| foo|
| z1| b2| foo|
| z1| c3| foo|
+-----+-----+-----+
我尝试复制此处提供的 RDD
解决方案:
(df
.rdd
.flatMap(lambda row: [(row.col1, col2, row.col3) for col2 in row.col2)])
.toDF(["col1", "col2", "col3"]))
但是,它没有给出所需的结果
编辑:explode
选项不起作用,因为它当前存储为字符串,而 explode
函数需要一个数组
您可以使用 explode
但首先您必须将数组的字符串表示形式转换为数组。
一种方法是在 ", "
上使用 regexp_replace
to remove the leading and trailing square brackets, followed by split
。
from pyspark.sql.functions import col, explode, regexp_replace, split
df.withColumn(
"col2",
explode(split(regexp_replace(col("col2"), "(^\[)|(\]$)", ""), ", "))
).show()
#+----+----+----+
#|col1|col2|col3|
#+----+----+----+
#| z1| a1| foo|
#| z1| b2| foo|
#| z1| c3| foo|
#+----+----+----+
Pault 的解决方案应该可以很好地工作,尽管这是另一个使用 regexp_extract
的解决方案(在这种情况下您实际上不需要替换任何东西)并且它可以处理任意数量的空格:
from pyspark.sql.functions import col, explode, regexp_extract,regexp_replace, split
df.withColumn("col2",
explode(
split(
regexp_extract(
regexp_replace(col("col2"), "\s", ""), "^\[(.*)\]$", 1), ","))) \
.show()
解释:
- 最初
regexp_replace(col("col2"), "\s", "")
将用空字符串替换所有空格。 - 接下来
regexp_extract
将提取以[
开始并以]
结束的列的内容。 - 然后我们对逗号分隔值执行
split
,最后执行explode
.