Dataframe 为PySpark数据帧聚合重命名列
我正在用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
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|
+---+