在Pyspark的dataframe中将每个组的总计作为新行添加

在Pyspark的dataframe中将每个组的总计作为新行添加,pyspark,apache-spark-sql,pyspark-dataframes,Pyspark,Apache Spark Sql,Pyspark Dataframes,参考我前面的问题,如果我试图计算并添加每个品牌、家长和周数(使用总量)的总行数 以下是虚拟示例: df0=spark.createDataFrame( [ (2,“A”、“A2”、“A2web”,2500), (2,“A”,“A2”,“A2TV”,3500), (4,“A”、“A1”、“A2app”,5500), (4"A","AD","ADapp",2000),, (4,“B”,“B25”,“B25app”,7600), (4,“B”、“B26”、“B26app”,5600), (5,“C”、

参考我前面的问题,如果我试图计算并添加每个品牌、家长和周数(使用总量)的总行数

以下是虚拟示例:

df0=spark.createDataFrame(
[
(2,“A”、“A2”、“A2web”,2500),
(2,“A”,“A2”,“A2TV”,3500),
(4,“A”、“A1”、“A2app”,5500),
(4"A","AD","ADapp",2000),,
(4,“B”,“B25”,“B25app”,7600),
(4,“B”、“B26”、“B26app”,5600),
(5,“C”、“c25”、“c25app”,2658),
(5,“C”、“c27”、“c27app”,1100),
(5,“C”、“c28”、“c26app”,1200),
],
[“周数”、“家长”、“品牌”、“渠道”、“使用量”],
)
此代码段为每个通道添加总计行

#分组并求和以获得总数
总计=(
df0.groupBy([“周数”、“家长”、“品牌])
.agg(f.sum(“用法”).别名(“用法”))
.带柱(“通道”,f.lit(“总计”))
)
#创建一个临时变量进行排序
总计=总计。带列(“排序id”,f.lit(2))
df0=df0.withColumn(“排序id”,f.lit(1))
#联合数据帧、drop temp变量和show
df1=df0.unionByName(总计)。排序([“周数”、“父项”、“品牌”、“排序id”))
df1.show()
结果:

+--------+------+-----+-------+-----+
|week_num|parent|brand|channel|usage|
+--------+------+-----+-------+-----+
|       2|     A|   A2|  A2web| 2500|
|       2|     A|   A2|   A2TV| 3500|
|       2|     A|   A2|  Total| 6000|
|       4|     A|   A1|  A2app| 5500|
|       4|     A|   A1|  Total| 5500|
|       4|     A|   AD|  ADapp| 2000|
|       4|     A|   AD|  Total| 2000|
|       4|     B|  B25| B25app| 7600|
|       4|     B|  B25|  Total| 7600|
|       4|     B|  B26| B26app| 5600|
|       4|     B|  B26|  Total| 5600|
|       5|     C|  c25| c25app| 2658|
|       5|     C|  c25|  Total| 2658|
|       5|     C|  c27| c27app| 1100|
|       5|     C|  c27|  Total| 1100|
|       5|     C|  c28| c26app| 1200|
|       5|     C|  c28|  Total| 1200|
+--------+------+-----+-------+-----+
+--------+------+-----+-------+-----+
|week_num|parent|brand|channel|usage|
+--------+------+-----+-------+-----+
|       2|     A|   A2|   A2TV| 3500|
|       2|     A|   A2|  A2web| 2500|
|       2|     A|   A2|  Total| 6000|
|       2|     A|Total|       | 6000|
|       2| Total|     |       | 6000|
|       4|     A|   A1|  A2app| 5500|
|       4|     A|   A1|  Total| 5500|
|       4|     A|   AD|  ADapp| 2000|
|       4|     A|   AD|  Total| 2000|
|       4|     A|Total|       | 7500|
|       4|     B|  B25| B25app| 7600|
|       4|     B|  B25|  Total| 7600|
|       4|     B|  B26| B26app| 5600|
|       4|     B|  B26|  Total| 5600|
|       4|     B|Total|       |13200|
|       4| Total|     |       |20700|
|       5|     C|Total|       | 4958|
|       5|     C|  c25|  Total| 2658|
|       5|     C|  c25| c25app| 2658|
|       5|     C|  c27|  Total| 1100|
+--------+------+-----+-------+-----+
对于channelcolumn来说,这是可以的,为了得到下面这样的结果,我只需重复第一个过程groupby+sum,然后将结果合并回来

+--------+------+-----+-------+-----+ 
|week_num|parent|brand|channel|usage|
+--------+------+-----+-------+-----+
|       2|     A|   A2|  A2web| 2500|
|       2|     A|   A2|   A2TV| 3500|
|       2|     A|   A2|  Total| 6000|
|       2|     A|Total|       | 6000|
|       2| Total|     |       | 6000|
这里有两个步骤

#添加品牌总数行
df2=(
df0.groupBy([“周数”,“父项”])
.agg(f.sum(“用法”).别名(“用法”))
.带栏(“品牌”,f.lit(“总计”)
.带柱(“通道”,f.lit(“”)
)
df2=df1.unionByName(df2).排序([“周数”、“父项”、“品牌”、“频道])
#添加周数总计行
df3=(
df0.groupBy([“周数])
.agg(f.sum(“用法”).别名(“用法”))
.带列(“父项”,f.lit(“总计”))
.带栏(“品牌”,f.lit(“”)
.带柱(“通道”,f.lit(“”)
)
df3=df2.unionByName(df3).排序([“周数”、“父项”、“品牌”、“频道])
结果:

+--------+------+-----+-------+-----+
|week_num|parent|brand|channel|usage|
+--------+------+-----+-------+-----+
|       2|     A|   A2|  A2web| 2500|
|       2|     A|   A2|   A2TV| 3500|
|       2|     A|   A2|  Total| 6000|
|       4|     A|   A1|  A2app| 5500|
|       4|     A|   A1|  Total| 5500|
|       4|     A|   AD|  ADapp| 2000|
|       4|     A|   AD|  Total| 2000|
|       4|     B|  B25| B25app| 7600|
|       4|     B|  B25|  Total| 7600|
|       4|     B|  B26| B26app| 5600|
|       4|     B|  B26|  Total| 5600|
|       5|     C|  c25| c25app| 2658|
|       5|     C|  c25|  Total| 2658|
|       5|     C|  c27| c27app| 1100|
|       5|     C|  c27|  Total| 1100|
|       5|     C|  c28| c26app| 1200|
|       5|     C|  c28|  Total| 1200|
+--------+------+-----+-------+-----+
+--------+------+-----+-------+-----+
|week_num|parent|brand|channel|usage|
+--------+------+-----+-------+-----+
|       2|     A|   A2|   A2TV| 3500|
|       2|     A|   A2|  A2web| 2500|
|       2|     A|   A2|  Total| 6000|
|       2|     A|Total|       | 6000|
|       2| Total|     |       | 6000|
|       4|     A|   A1|  A2app| 5500|
|       4|     A|   A1|  Total| 5500|
|       4|     A|   AD|  ADapp| 2000|
|       4|     A|   AD|  Total| 2000|
|       4|     A|Total|       | 7500|
|       4|     B|  B25| B25app| 7600|
|       4|     B|  B25|  Total| 7600|
|       4|     B|  B26| B26app| 5600|
|       4|     B|  B26|  Total| 5600|
|       4|     B|Total|       |13200|
|       4| Total|     |       |20700|
|       5|     C|Total|       | 4958|
|       5|     C|  c25|  Total| 2658|
|       5|     C|  c25| c25app| 2658|
|       5|     C|  c27|  Total| 1100|
+--------+------+-----+-------+-----+
第一个问题,是否有其他方法或更有效的方法不重复? 第二,如果我想在每组中显示total始终位于顶部,而不考虑父/品牌/频道的字母名称,我该如何排序。像这样:(这是虚拟数据,但我希望它足够清楚)

我想你需要的只是方法

agg_df=(
df.汇总([“周数”、“家长”、“品牌”、“频道”])
.agg(F.sum(“用法”).alias(“用法”)、F.grouping_id().alias(“lvl”))
.orderBy(agg_cols)
)
agg_df.show()
+--------+------+-----+-------+-----+---+
|周数|家长|品牌|渠道|使用|等级|
+--------+------+-----+-------+-----+---+
|空|空|空|空| 31658 | 15|
|2 |零|零|零| 6000 | 7|
|2 | A | null | null | 6000 | 3|
|2 | A | A2 |空| 6000 | 1|
|2 | A | A2 | A2TV | 3500 | 0|
|2 | A | A2 | A2web | 2500 | 0|
|4 |零|零|零| 20700 | 7|
|4 | A | null | null | 7500 | 3|
|4 | A | A1 |空| 5500 | 1|
|4 | A | A1 | A2app | 5500 | 0|
|4 | A | AD | null | 2000 | 1|
|4 | A | AD | ADapp | 2000 | 0|
|4 | B | null | null | 13200 | 3|
|4 | B | B25 |空| 7600 | 1|
|4 | B | B25 | B25app | 7600 | 0|
|4 | B | B26 |空| 5600 | 1|
|4 | B | B26 | B26app | 5600 | 0|
|5 |零|零|零| 4958 | 7|
|5 | C | null | null | 4958 | 3|
|5 | C | c25 | null | 2658 | 1|
+--------+------+-----+-------+-----+---+
仅显示前20行
其余的都是纯化妆品。使用
spark
可能不是一个好主意。最好在以后使用的restition工具中这样做

agg_-df=agg_-df.withColumn(“lvl”,F.densite_-rank().over(Window.orderBy(“lvl”))
TOTAL=“总计”
agg_df=(
带柱的总方向图(
“父级”,F.when(F.col(“lvl”)==4,总计)。否则(F.col(“父级”))
)
.withColumn(
“品牌”,
F.when(F.col(“lvl”)==3,总计)。否则(
F.联合(F.col(“品牌”)、F.lit(“”)
),
)
.withColumn(
“频道”,
F.when(F.col(“lvl”)==2,总计)。否则(
F.合并(F.col(“通道”)、F.lit(“”)
),
)
)
总方向图,其中(F.col(“lvl”)!=5)。订购人(
“周数”,F.col(“lvl”).desc(),“母公司”,“品牌”,“渠道”
).下降(“lvl”).显示(500)
+--------+------+-----+-------+-----+
|周数|家长|品牌|渠道|使用情况|
+--------+------+-----+-------+-----+
|2 |总计| | 6000|
|2 | A |总计| 6000|
|2 | A | A2 |总计| 6000|
|2 | A | A2 | A2TV | 3500|
|2 | A | A2 | A2web | 2500|
|4 |总计| | 20700|
|4 | A |总计| 7500|
|4 | B |总计| 13200|
|4 | A | A1 |总计| 5500|
|4 | A | AD | Total | 2000|
|4 | B | B25 |总计| 7600|
|4 | B | B26 |总计| 5600|
|4 | A | A1 | A2app | 5500|
|4 | A | AD | ADapp | 2000|
|4 | B | B25 | B25app | 7600|
|4 | B | B26 | B26app | 5600|
|5 |总计| | 4958|
|5 | C |总计| 4958|
|5 | C | c25 |总计| 2658|
|5 | C | c27 |总计| 1100|
|5 | C | c28 |总计| 1200|
|5 | C | c25 | c25app | 2658|
|5 | C | c27 | c27app | 1100|
|5 | C | c28 | c26app | 1200|
+--------+------+-----+-------+-----+

我不确定您是如何订购数据的。@Steven谢谢,伙计,我完全同意您的意见,最好不要在spark中这样做。我没有以编程方式对其排序,您的方法是正确的