使用performant select操作重命名PySpark数据帧中的列
还有关于如何重命名PySpark数据框中的列的其他线程,请参阅和。我认为现有的解决方案没有足够的性能或通用性(我有一个应该更好的解决方案,我被边缘案例错误卡住了)。让我们首先回顾一下当前解决方案的问题:使用performant select操作重命名PySpark数据帧中的列,pyspark,Pyspark,还有关于如何重命名PySpark数据框中的列的其他线程,请参阅和。我认为现有的解决方案没有足够的性能或通用性(我有一个应该更好的解决方案,我被边缘案例错误卡住了)。让我们首先回顾一下当前解决方案的问题: 反复调用withColumnRename可能会遇到与多次调用withColumn相同的性能问题。看 依赖于模式推断,不一定保留列的nullable属性(在生产代码中应避免toDF)。我猜这种方法也很慢 ,但它不够通用,而且对于许多列来说,手动操作太多(例如,如果您尝试将2000个列名转换为sn
- 反复调用
可能会遇到与多次调用withColumnRename
相同的性能问题。看withColumn
- 依赖于模式推断,不一定保留列的nullable属性(在生产代码中应避免toDF)。我猜这种方法也很慢
- ,但它不够通用,而且对于许多列来说,手动操作太多(例如,如果您尝试将2000个列名转换为snake_大小写)
导入pyspark.sql.F函数
def带有_列_重命名(乐趣):
定义(df):
cols=列表(映射)(
lambda col_name:F.col(col_name)。别名(fun(col_name)),
df.columns
))
返回df.select(*cols)
返回_
假设您有以下数据帧:
+-------------+-----------+
|i like cheese|yummy stuff|
+-------------+-----------+
| jose| a|
| li| b|
| sam| c|
+-------------+-----------+
+-------------+-----------+
|i.like.cheese|yummy.stuff|
+-------------+-----------+
| jose| a|
| li| b|
| sam| c|
+-------------+-----------+
下面介绍如何用下划线替换列名中的所有空格:
def空格到下划线:
返回s.replace(“,”)
transform(带_列_重命名(空格_到_下划线)).show()
除了列名包含点之外,该解决方案工作正常
假设您有以下数据帧:
+-------------+-----------+
|i like cheese|yummy stuff|
+-------------+-----------+
| jose| a|
| li| b|
| sam| c|
+-------------+-----------+
+-------------+-----------+
|i.like.cheese|yummy.stuff|
+-------------+-----------+
| jose| a|
| li| b|
| sam| c|
+-------------+-----------+
此代码将出错:
def dots_to_underscores(s):
return s.replace(".", "_")
df.transform(quinn.with_columns_renamed(dots_to_underscores))
以下是错误消息:pyspark.sql.utils.AnalysisException:“无法解析给定输入列的“
i.like.cheese”[i.like.cheese,yummy.stuff];\n'Project['i.like.cheese AS i_like#cheese#242,'yummy.stuff AS yummy#243]\n+-LogicalRDD[i.like.cheese#231,yummy.stuff#232],false\n”
如何修改此解决方案以适用于带有点的列名?我还假设Catalyst优化器对多个
WithColumnRename
调用的优化问题与对多个withColumn
调用的优化问题相同。让我知道Catalyst是否因为某些原因能够更好地处理多个列重命名的调用。尝试使用`转义:
import pyspark.sql.functions as F
def with_columns_renamed(fun):
def _(df):
cols = list(map(
lambda col_name: F.col("`{0}`".format(col_name)).alias(fun(col_name)),
df.columns
))
return df.select(*cols)
return _
或者将列重命名后的与一起使用
from functools import reduce
reduce(lambda new_df, col: new_df.withColumnRenamed(col,col.replace('.','_')),df.columns,df)
你可以做一些像这样简单的事情
import pyspark.sql.functions as F
def with_columns_renamed(fun):
def _(df):
cols = list(map(
lambda col_name: F.col('`' + col_name + '`').alias(fun(col_name)),
df.columns
))
return df.select(*cols)
return _
@murtihash-使用reduce
和withColumnRenamed
是有效的,但我特别尝试避免这种方法。转义方法听起来很有希望,请随意用一段有效的代码段来写一个答案。我明白了,只要读一下那篇文章,这很有趣,这么多withColumn调用可能会导致瓶颈。您可以坚持使用“在地图中使用选择”进行转义