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

问题描述

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

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

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

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

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

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

谢谢

解决方法

尝试使用 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),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|
+-----+------+------+
,

我将创建一列来对您的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