在PySpark DataFrame中动态地重命名多个列

18

我在Pyspark中有一个包含15个列的数据框。

这些列的名称是idnameemp.dnoemp.salstateemp.cityzip等等。

现在我想将其中名称带有'.'的列名替换为'_'

例如将'emp.dno'替换为'emp_dno'

我希望能够动态地实现它

在Pyspark中我该如何做到这一点?

4个回答

41
你可以使用类似于@zero323的这个好方法
df.toDF(*(c.replace('.', '_') for c in df.columns))

或者说:

from pyspark.sql.functions import col

replacements = {c:c.replace('.','_') for c in df.columns if '.' in c}

df.select([col(c).alias(replacements.get(c, c)) for c in df.columns])

replacement 字典将会是这样的:

{'emp.city': 'emp_city', 'emp.dno': 'emp_dno', 'emp.sal': 'emp_sal'}

更新:

如果我有一个带有空格的列名的数据框,如何用'_'替换'.'和空格?

import re

df.toDF(*(re.sub(r'[\.\s]+', '_', c) for c in df.columns))

@Virureddy,这真的很奇怪...它怎么可能不同呢? - MaxU - stand with Ukraine
1
@Virureddy,你可以试试这个:df.toDF(c.replace('.', '_') for c in df.columns) 或者 df.toDF((c.replace('.', '_') for c in df.columns)) 或者 df.toDF(*(c.replace('.', '_') for c in df.columns)) - MaxU - stand with Ukraine
1
非常感谢您的帮助和耐心。 - User12345
我能够同时进行空格和点的替换(我也删除了if条件)。你也可以将多个replace()调用串联在一起,以处理多个字符替换,但如果要替换的特殊字符数量太多,则原始帖子中“更新”下的解决方案会更好,因为您可以只需将更多字符添加到正则表达式模式中。replacements = {c:c.replace('.','_').replace(' ','_') for c in df.columns} - rp1
在Spark(Scala/Python)中,使用df.select是正确的方法。请查看此链接:https://dev59.com/U1gQ5IYBdhLWcg3wMhBJ#62728542 - Krunal Patel
显示剩余16条评论

6

我为您编写了一个简单快捷的函数,希望您能享受使用它! :)

def rename_cols(rename_df):
    for column in rename_df.columns:
        new_column = column.replace('.','_')
        rename_df = rename_df.withColumnRenamed(column, new_column)
    return rename_df

0

最简单的方法如下:

解释:

  1. 使用df.columns获取pyspark dataframe中的所有列
  2. 创建一个循环遍历步骤1中的每一列的列表
  3. 该列表将输出:col("col.1").alias(c.replace('.',"_")。仅对所需列执行此操作。replace函数可帮助替换任何模式。您还可以排除重命名某些列
  4. *[list]将为pypsark中的select语句解包列表

from pyspark.sql import functions as F (df .select(*[F.col(c).alias(c.replace('.',"_")) for c in df.columns]) .toPandas().head() )

希望这有所帮助


0

MaxU的回答很好而且高效。这篇文章介绍了另一种同样高效并有助于保持代码干净的方法(使用quinn库)。

假设您有以下DataFrame:

+---+-----+--------+-------+
| id| name|emp.city|emp.sal|
+---+-----+--------+-------+
| 12|  bob|New York|     80|
| 99|alice| Atlanta|     90|
+---+-----+--------+-------+

以下是如何在所有列中将点号替换为下划线的方法。

import quinn

def dots_to_underscores(s):
    return s.replace('.', '_')
actual_df = df.transform(quinn.with_columns_renamed(dots_to_underscores))
actual_df.show()

这是生成的actual_df
+---+-----+--------+-------+
| id| name|emp_city|emp_sal|
+---+-----+--------+-------+
| 12|  bob|New York|     80|
| 99|alice| Atlanta|     90|
+---+-----+--------+-------+

让我们使用 explain() 来验证该函数是否执行高效:

actual_df.explain(True)

这里是输出的逻辑计划:
== Parsed Logical Plan ==
'Project ['id AS id#50, 'name AS name#51, '`emp.city` AS emp_city#52, '`emp.sal` AS emp_sal#53]
+- LogicalRDD [id#29, name#30, emp.city#31, emp.sal#32], false

== Analyzed Logical Plan ==
id: string, name: string, emp_city: string, emp_sal: string
Project [id#29 AS id#50, name#30 AS name#51, emp.city#31 AS emp_city#52, emp.sal#32 AS emp_sal#53]
+- LogicalRDD [id#29, name#30, emp.city#31, emp.sal#32], false

== Optimized Logical Plan ==
Project [id#29, name#30, emp.city#31 AS emp_city#52, emp.sal#32 AS emp_sal#53]
+- LogicalRDD [id#29, name#30, emp.city#31, emp.sal#32], false

== Physical Plan ==
*(1) Project [id#29, name#30, emp.city#31 AS emp_city#52, emp.sal#32 AS emp_sal#53]

您可以看到,解析的逻辑计划几乎与物理计划相同,因此Catalyst优化器不需要进行太多的优化工作。它将id AS id#50转换为id#29,但这并不需要太多的工作。

with_some_columns_renamed方法生成了一个更高效的解析计划。

def dots_to_underscores(s):
    return s.replace('.', '_')
def change_col_name(s):
  return '.' in s
actual_df = df.transform(quinn.with_some_columns_renamed(dots_to_underscores, change_col_name))
actual_df.explain(True)

这个解析计划仅使用点别名列。

== Parsed Logical Plan ==
'Project [unresolvedalias('id, None), unresolvedalias('name, None), '`emp.city` AS emp_city#42, '`emp.sal` AS emp_sal#43]
+- LogicalRDD [id#34, name#35, emp.city#36, emp.sal#37], false

== Analyzed Logical Plan ==
id: string, name: string, emp_city: string, emp_sal: string
Project [id#34, name#35, emp.city#36 AS emp_city#42, emp.sal#37 AS emp_sal#43]
+- LogicalRDD [id#34, name#35, emp.city#36, emp.sal#37], false

== Optimized Logical Plan ==
Project [id#34, name#35, emp.city#36 AS emp_city#42, emp.sal#37 AS emp_sal#43]
+- LogicalRDD [id#34, name#35, emp.city#36, emp.sal#37], false

== Physical Plan ==
*(1) Project [id#34, name#35, emp.city#36 AS emp_city#42, emp.sal#37 AS emp_sal#43]

更多信息:为什么在DataFrame上循环并多次调用withColumnRenamed会创建过于复杂的解析计划,应该避免。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接