Dataframe 为PySpark数据帧聚合重命名列

Dataframe 为PySpark数据帧聚合重命名列,dataframe,pyspark,aggregate,Dataframe,Pyspark,Aggregate,我正在用PySpark数据帧分析一些数据。假设我有一个正在聚合的数据帧df: (df.groupBy("group") .agg({"money":"sum"}) .show(100)) 这将给我: group SUM(money#2L) A 137461285853 B 172185566943 C

我正在用PySpark数据帧分析一些数据。假设我有一个正在聚合的数据帧
df

(df.groupBy("group")
   .agg({"money":"sum"})
   .show(100))
这将给我:

group                SUM(money#2L)
A                    137461285853
B                    172185566943
C                    271179590646
聚合工作正常,但我不喜欢新的列名“SUM(money#2L)”。有没有办法通过
.agg
方法将此列重命名为人类可读的内容?也许是更类似于人们在
dplyr
中所做的事情:

df %>% group_by(group) %>% summarise(sum_money = sum(money))

withColumnRenamed
应该可以做到这一点。这里是链接到


尽管我仍然更喜欢dplyr语法,但此代码段可以:

import pyspark.sql.functions as sf

(df.groupBy("group")
   .agg(sf.sum('money').alias('money'))
   .show(100))

它变得冗长。

我为此制作了一个小助手函数,可能会帮助一些人

重新导入
从functools导入部分
def rename_cols(agg_df,ignore_first_n=1):
“”“更改默认的spark聚合名称`avg(colname)`
传递一个聚合的数据帧
以及要忽略的聚合列数。
"""
分隔符=“(”,”)
split_pattern='|'。join(映射(转义,分隔符))
拆分器=部分(重新拆分,拆分模式)
split_agg=lambda x:''.'.join(拆分器(x))[0:-先忽略\u\n]
重命名=映射(拆分聚集,聚集方向列[忽略第一列])
重命名=zip(agg_df.columns[忽略\u first\u n:],重命名)
对于中的旧版本和新版本,请重命名:
agg_-df=agg_-df.withColumnRename(旧、新)
返回agg_df
例如:

gb=(df.selectExpr(“id”、“rank”、“rate”、“price”、“clicks”)
.groupby(“id”)
.agg({“等级”:“平均值”,
“*”:“计数”,
“比率”:“平均值”,
“价格”:“平均值”,
“点击”:“平均值”,
})
)
>>>gb列
['id',
“平均价格”,
“计数(1)”,
“平均价格”,
"平均(职级)",,
“平均点击次数”]
>>>重命名_cols(gb).columns
['id',
“平均价格”,
“计数1”,
“平均价格”,
“平均排名”,
“平均点击次数”]
至少做一点,让人们不用打字这么多

df = df.groupby('Device_ID').agg(aggregate_methods)
for column in df.columns:
    start_index = column.find('(')
    end_index = column.find(')')
    if (start_index and end_index):
        df = df.withColumnRenamed(column, column[start_index+1:end_index])
上面的代码可以去掉“()”之外的任何内容。例如,“sum(foo)”将重命名为“foo”。

简单如下:

 val maxVideoLenPerItemDf = requiredItemsFiltered.groupBy("itemId").agg(max("playBackDuration").as("customVideoLength"))
maxVideoLenPerItemDf.show()

在agg中使用
.as
来命名创建的新行。

虽然前面给出的答案很好,但我认为它们缺少一种处理
.agg()中字典用法的简洁方法。

import findspark
findspark.init()

from pyspark.sql import SparkSession
from pyspark.sql.functions import *
from pyspark.sql.types import *

spark = SparkSession.builder.appName('test').getOrCreate()
data = [(1, "siva", 100), (2, "siva2", 200),(3, "siva3", 300),(4, "siva4", 400),(5, "siva5", 500)]
schema = ['id', 'name', 'sallary']

df = spark.createDataFrame(data, schema=schema)
df.show()
+---+-----+-------+
| id| name|sallary|
+---+-----+-------+
|  1| siva|    100|
|  2|siva2|    200|
|  3|siva3|    300|
|  4|siva4|    400|
|  5|siva5|    500|
+---+-----+-------+


**df.agg({"sallary": "max"}).withColumnRenamed('max(sallary)', 'max').show()**
+---+
|max|
+---+
|500|
+---+
如果您想使用dict,实际上它也可能是动态生成的,因为您有数百列,您可以使用以下命令,而无需处理几十行代码:

#使用.agg()函数的字典版本
#注意:提供的逻辑实际上也可以应用于非字典方法
df=df.groupBy(“集团”)\
阿格先生({
“钱”:“金额”
, "...":  "..."
})
#现在进行重命名
newColumnNames=[“组”、“钱”、“钱”]#提供新df的所有列的名称
df=df.toDF(*newColumnNames)#进行重命名
当然,
newColumnNames
-列表也可以动态生成。例如,如果只将聚合中的列附加到
df
中,则可以预先存储
newColumnNames=df.columns
,然后只附加其他名称。

无论如何,请注意,
newColumnNames
必须包含数据帧的所有列名,而不仅仅是要重命名的列名(因为
.toDF()
由于不可变的RDD创建了一个新的数据帧)

非常有用和及时。我正要问同样的问题。如果您能在
agg
dict(我是说在Spark中)中指定一个新列名,那就太好了。@EvanZamir谢谢!我可能会尝试在spark中做一个简单的PR。您可以简单地通过
df=df.toDF(*newColumnNames)
重命名,
newColumnNames
保存数据帧(df)的所有列名。对于已复制粘贴此
别名
部分但未看到其生效的任何其他人,请注意括号
alias('string')
存在于
agg
中,否则您将给整个数据帧添加别名,而不仅仅是列。从PySpark 2.4.0开始,
。As('new_name')
应该是
。alias('new_name')
。只需注意没有括号的列,它们将一起删除,例如groupby变量。可以添加if/continue检查。我有一个变量是我的groupby var,所以刚刚检查了它。
alias
是一个很好的指针,但这是正确的答案-有时有很好的理由使用
agg
中的字典,似乎唯一的方法是重命名聚合列来“别名”。
import findspark
findspark.init()

from pyspark.sql import SparkSession
from pyspark.sql.functions import *
from pyspark.sql.types import *

spark = SparkSession.builder.appName('test').getOrCreate()
data = [(1, "siva", 100), (2, "siva2", 200),(3, "siva3", 300),(4, "siva4", 400),(5, "siva5", 500)]
schema = ['id', 'name', 'sallary']

df = spark.createDataFrame(data, schema=schema)
df.show()
+---+-----+-------+
| id| name|sallary|
+---+-----+-------+
|  1| siva|    100|
|  2|siva2|    200|
|  3|siva3|    300|
|  4|siva4|    400|
|  5|siva5|    500|
+---+-----+-------+


**df.agg({"sallary": "max"}).withColumnRenamed('max(sallary)', 'max').show()**
+---+
|max|
+---+
|500|
+---+