Python 基于分隔符拆分字符串列,并为Pyspark中的每个值创建列
我有1000个文件,其中包含以下格式的数据:Python 基于分隔符拆分字符串列,并为Pyspark中的每个值创建列,python,apache-spark,pyspark,apache-spark-sql,pyspark-dataframes,Python,Apache Spark,Pyspark,Apache Spark Sql,Pyspark Dataframes,我有1000个文件,其中包含以下格式的数据: a|b|c|clm4=1|clm5=3 a|b|c|clm4=9|clm6=60|clm7=23 我想阅读它并将其转换为数据帧,如下所示: clm1|clm2|clm3|clm4|clm5|clm6|clm7 a|b|c|1|3|null|null a|b|c|9|null|60|23 我尝试过以下方法: files = [f for f in glob.glob(pathToFile + "/**/*.txt.gz", re
a|b|c|clm4=1|clm5=3
a|b|c|clm4=9|clm6=60|clm7=23
我想阅读它并将其转换为数据帧,如下所示:
clm1|clm2|clm3|clm4|clm5|clm6|clm7
a|b|c|1|3|null|null
a|b|c|9|null|60|23
我尝试过以下方法:
files = [f for f in glob.glob(pathToFile + "/**/*.txt.gz", recursive=True)]
df = spark.read.load(files, format='csv', sep = '|', header=None)
但它给了我以下结果:
clm1, clm2, clm3, clm4, clm5
a, b, c, 1, 3
a, b, c, 9, null
对于Spark 2.4+,您可以将文件作为一列读取,然后按
将其拆分。您将得到一个数组列,可以使用以下方法进行转换:
我们使用transform
函数将从拆分clm
列得到的字符串数组转换为结构数组。
每个结构包含列名(如果存在)(检查字符串是否包含=
)或将其命名为clm+(i+1)
,其中i
是其位置
transform_expr = """
transform(split(clm, '[|]'), (x, i) ->
struct(
IF(x like '%=%', substring_index(x, '=', 1), concat('clm', i+1)),
substring_index(x, '=', -1)
)
)
"""
现在使用map\u from\u entries
将数组转换为map。最后,分解地图和轴以获得列
df.select("clm",
explode(map_from_entries(expr(transform_expr))).alias("col_name", "col_value")
) \
.groupby("clm").pivot('col_name').agg(first('col_value')) \
.drop("clm") \
.show(truncate=False)
给出:
+----+----+----+----+----+----+----+
|clm1|clm2|clm3|clm4|clm5|clm6|clm7|
+----+----+----+----+----+----+----+
|a |b |c |9 |null|60 |23 |
|a |b |c |1 |3 |null|null|
+----+----+----+----+----+----+----+
要使用此方法,我必须为每个列编写getItem(),这是不可能的,因为有100个列,其中大多数都是未知的帮助库。有没有办法在上面的代码中设置一个条件,只选择现有列名列表中存在的那些列?
+----+----+----+----+----+----+----+
|clm1|clm2|clm3|clm4|clm5|clm6|clm7|
+----+----+----+----+----+----+----+
|a |b |c |9 |null|60 |23 |
|a |b |c |1 |3 |null|null|
+----+----+----+----+----+----+----+