如何将长数据帧转换为宽数据帧

时间:2020-08-19 16:03:02

标签: pyspark apache-spark-sql pyspark-dataframes

我有一个数据框,看起来像:

group, rate
A,0.1
A,0.2
B,0.3
B,0.1
C,0.1
C,0.2

如何将其转置为宽数据帧。这是我期望得到的:

group, rate_1, rate_2
A,0.1,0.2
B,0.3,0.1
C,0.1,0.2

每个组中的记录数相同,并且在转置时如何创建带有前缀或后缀的一致列名?

您知道我可以使用哪些功能吗?

谢谢

2 个答案:

答案 0 :(得分:0)

尝试使用 groupBy, collect_list ,然后动态将数组列拆分为新列。

Example:

df.show()
#+-----+----+
#|group|rate|
#+-----+----+
#|    A| 0.1|
#|    A| 0.2|
#|    B| 0.3|
#|    B| 0.1|
#+-----+----+

arr_size = 2
exprs=['group']+[expr('lst[' + str(x) + ']').alias('rate_'+str(x+1)) for x in range(0, arr_size)]

df1=df.groupBy("group").agg(collect_list(col("rate")).alias("lst"))
df1.select(*exprs).show()
#+-----+------+------+
#|group|rate_1|rate_2|
#+-----+------+------+
#|    B|   0.3|   0.1|
#|    A|   0.1|   0.2|
#+-----+------+------+

For Preserver Order in collect_list():

df=spark.createDataFrame([('A',0.1),('A',0.2),('B',0.3),('B',0.1)],['group','rate']).withColumn("mid",monotonically_increasing_id()).repartition(100)

from pyspark.sql.functions import *
from pyspark.sql import *

w=Window.partitionBy("group").orderBy("mid")
w1=Window.partitionBy("group").orderBy(desc("mid"))

df1=df.withColumn("lst",collect_list(col("rate")).over(w)).\
withColumn("snr",row_number().over(w1)).\
filter(col("snr") == 1).\
drop(*['mid','snr','rate'])

df1.show()
#+-----+----------+
#|group|       lst|
#+-----+----------+
#|    B|[0.3, 0.1]|
#|    A|[0.1, 0.2]|
#+-----+----------+

arr_size = 2
exprs=['group']+[expr('lst[' + str(x) + ']').alias('rate_'+str(x+1)) for x in range(0, arr_size)]

df1.select(*exprs).show()
+-----+------+------+
|group|rate_1|rate_2|
+-----+------+------+
|    B|   0.3|   0.1|
|    A|   0.1|   0.2|
+-----+------+------+

答案 1 :(得分:0)

我将创建一列来对您的a val2 val3 val4 b val3 c val3 val4 d val4 列进行排名,然后对pivot进行排名:

首先创建一个"rate"列,并将字符串"rank"连接到row_number

"rate_"

现在按from pyspark.sql.functions import concat, first, lit, row_number from pyspark.sql import Window df = df.withColumn( "rank", concat( lit("rate_"), row_number().over(Window.partitionBy("group")\ .orderBy("rate")).cast("string") ) ) df.show() #+-----+----+------+ #|group|rate| rank| #+-----+----+------+ #| B| 0.1|rate_1| #| B| 0.3|rate_2| #| C| 0.1|rate_1| #| C| 0.2|rate_2| #| A| 0.1|rate_1| #| A| 0.2|rate_2| #+-----+----+------+ 列和"group"列的pivot分组。由于您需要汇总,因此请使用first

"rank"

以上内容并不取决于提前知道每个组中的记录数。

但是,如果您(如您所说)知道每个组中的记录数,则可以通过传递df.groupBy("group").pivot("rank").agg(first("rate")).show() #+-----+------+------+ #|group|rate_1|rate_2| #+-----+------+------+ #| B| 0.1| 0.3| #| C| 0.1| 0.2| #| A| 0.1| 0.2| #+-----+------+------+

来提高pivot的效率
values