使用Pyspark将不同的行值转换为具有相应行的不同列

使用Pyspark将不同的行值转换为具有相应行的不同列,pyspark,pivot,rdd,transpose,flatmap,Pyspark,Pivot,Rdd,Transpose,Flatmap,我是Pyspark的新手,正在尝试转换数据 给定数据帧 Col1 A=id1a A=id2a B=id1b C=id1c B=id2b D=id1d A=id3a B=id3b C=id2c A=id4a C=id3c 所需: A B C id1a id1b id1c id2a id2b id2c id3a id3b id3b id4a null null 我尝试过pivot,但它给出了第一个值。可

我是Pyspark的新手,正在尝试转换数据

给定数据帧

Col1
A=id1a A=id2a B=id1b C=id1c B=id2b
D=id1d A=id3a B=id3b C=id2c
A=id4a C=id3c
所需:

A         B        C
id1a     id1b     id1c
id2a     id2b     id2c
id3a     id3b     id3b
id4a     null     null

我尝试过pivot,但它给出了第一个值。

可能是因为我不知道全部情况,但数据格式似乎很奇怪。如果无法在数据源上执行任何操作,则需要进行一些收集、数据透视和连接。试试这个

import pyspark.sql.functions as F
test = sqlContext.createDataFrame([('A=id1a A=id2a B=id1b C=id1c B=id2b',1),('D=id1d A=id3a B=id3b C=id2c',2),('A=id4a C=id3c',3)],schema=['col1','id'])
tst_spl = test.withColumn("item",(F.split('col1'," ")))
tst_xpl = tst_spl.select(F.explode("item"))
tst_map = tst_xpl.withColumn("key",F.split('col','=')[0]).withColumn("value",F.split('col','=')[1]).drop('col')
#%%
tst_pivot = tst_map.groupby(F.lit(1)).pivot('key').agg(F.collect_list(('value'))).drop('1')
#%%
tst_arr = [tst_pivot.select(F.posexplode(coln)).withColumnRenamed('col',coln) for coln in tst_pivot.columns]  

tst_fin = reduce(lambda df1,df2:df1.join(df2,on='pos',how='full'),tst_arr).orderBy('pos')

tst_fin.show()
+---+----+----+----+----+
|pos|   A|   B|   C|   D|
+---+----+----+----+----+
|  0|id3a|id3b|id1c|id1d|
|  1|id4a|id1b|id2c|null|
|  2|id1a|id2b|id3c|null|
|  3|id2a|null|null|null|
+---+----+----+----+----

可能有更好的方法,但一种方法是在空格上拆分列以创建条目数组,然后使用高阶函数(spark 2.4+)在拆分数组中的每个条目上拆分
'='
。然后分解并创建两列,一列带有id,另一列带有值。然后我们可以为每个分区和组分配一个行号,然后pivot:

import pyspark.sql.functions as F
df1 = (df.withColumn("Col1",F.split(F.col("Col1"),"\s+")).withColumn("Col1",
             F.explode(F.expr("transform(Col1,x->split(x,'='))")))
        .select(F.col("Col1")[0].alias("cols"),F.col("Col1")[1].alias("vals")))

from pyspark.sql import Window
w = Window.partitionBy("cols").orderBy("cols")
final = (df1.withColumn("Rnum",F.row_number().over(w)).groupBy("Rnum")
         .pivot("cols").agg(F.first("vals")).orderBy("Rnum"))


这就是变换后df1的样子:

df1.show()
+----+----+
|cols|vals|
+----+----+
|   A|id1a|
|   A|id2a|
|   B|id1b|
|   C|id1c|
|   B|id2b|
|   D|id1d|
|   A|id3a|
|   B|id3b|
|   C|id2c|
|   A|id4a|
|   C|id3c|
+----+----+

你能提供一个可复制的数据样本吗?
df1.show()
+----+----+
|cols|vals|
+----+----+
|   A|id1a|
|   A|id2a|
|   B|id1b|
|   C|id1c|
|   B|id2b|
|   D|id1d|
|   A|id3a|
|   B|id3b|
|   C|id2c|
|   A|id4a|
|   C|id3c|
+----+----+