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

How to transpose a long dataframe to wide dataframe

我的数据框如下所示:

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

每组的记录数相同,以及如何在转置时创建前后缀一致的列名?

你知道我可以使用哪个功能吗?

谢谢,

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

我会创建一个列来对您的 "rate" 列进行排名,然后 :

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

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 on the "rank" column. Since you need an aggregation, use first 分组。

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|
#+-----+------+------+

以上不依赖于提前知道每组的记录数

但是,如果(如您所说)您知道每个组中的记录数,则可以通过传入 values

来提高 pivot 的效率
num_records = 2
values = ["rate_" + str(i+1) for i in range(num_records)]
df.groupBy("group").pivot("rank", values=values).agg(first("rate")).show()
#+-----+------+------+
#|group|rate_1|rate_2|
#+-----+------+------+
#|    B|   0.1|   0.3|
#|    C|   0.1|   0.2|
#|    A|   0.1|   0.2|
#+-----+------+------+