Je veux changer le nom de deux colonnes en utilisant la fonction spark withColumnRenamed. Bien sûr, je peux écrire:
data = sqlContext.createDataFrame([(1,2), (3,4)], ['x1', 'x2'])
data = (data
.withColumnRenamed('x1','x3')
.withColumnRenamed('x2', 'x4'))
mais je veux le faire en une étape (avoir la liste/le nuplet de nouveaux noms). Malheureusement, ni ceci:
data = data.withColumnRenamed(['x1', 'x2'], ['x3', 'x4'])
ni ceci:
data = data.withColumnRenamed(('x1', 'x2'), ('x3', 'x4'))
travaille. Est-il possible de faire cela de cette façon?
Il n'est pas possible d'utiliser un seul appel withColumnRenamed
.
Vous pouvez utiliser DataFrame.toDF
method *
data.toDF('x3', 'x4')
ou
new_names = ['x3', 'x4']
data.toDF(*new_names)
Il est également possible de renommer avec la simple select
:
from pyspark.sql.functions import col
mapping = dict(Zip(['x1', 'x2'], ['x3', 'x4']))
data.select([col(c).alias(mapping.get(c, c)) for c in data.columns])
De même à Scala, vous pouvez:
Renommez toutes les colonnes:
val newNames = Seq("x3", "x4")
data.toDF(newNames: _*)
Renommez à partir de la correspondance avec select
:
val mapping = Map("x1" -> "x3", "x2" -> "x4")
df.select(
df.columns.map(c => df(c).alias(mapping.get(c).getOrElse(c))): _*
)
ou foldLeft
+ withColumnRenamed
mapping.foldLeft(data){
case (data, (oldName, newName)) => data.withColumnRenamed(oldName, newName)
}
* Ne pas confondre avec RDD.toDF
qui n'est pas une fonction variadique et prend les noms de colonne comme une liste,
Je ne trouvais pas non plus de solution facile pour pyspark, alors venez de construire la mienne, semblable au df.rename(columns={'old_name_1':'new_name_1', 'old_name_2':'new_name_2'})
de pandas.
def rename_columns(df, columns):
if isinstance(columns, dict):
for old_name, new_name in columns.items():
df = df.withColumnRenamed(old_name, new_name)
return df
else:
raise ValueError("'columns' should be a dict, like {'old_name_1':'new_name_1', 'old_name_2':'new_name_2'}")
Votre solution ressemblera donc à data = rename_columns(data, {'x1': 'x3', 'x2': 'x4'})
Cela me permet d'économiser quelques lignes de code, j'espère que cela vous aidera aussi.
pourquoi voulez-vous l'exécuter sur une seule ligne si vous imprimez le plan d'exécution, il est en réalité effectué sur une seule ligne
data = spark.createDataFrame([(1,2), (3,4)], ['x1', 'x2'])
data = (data
.withColumnRenamed('x1','x3')
.withColumnRenamed('x2', 'x4'))
data.explain()
SORTIE
== Physical Plan ==
*(1) Project [x1#1548L AS x3#1552L, x2#1549L AS x4#1555L]
+- Scan ExistingRDD[x1#1548L,x2#1549L]
si vous voulez le faire avec un tuple de listevous pouvez utiliser une simple fonction de carte
data = spark.createDataFrame([(1,2), (3,4)], ['x1', 'x2'])
new_names = [("x1","x3"),("x2","x4")]
data = data.select(list(
map(lambda old,new:F.col(old).alias(new),*Zip(*new_names))
))
data.explain()
a toujours le même plan
SORTIE
== Physical Plan ==
*(1) Project [x1#1650L AS x3#1654L, x2#1651L AS x4#1655L]
+- Scan ExistingRDD[x1#1650L,x2#1651L]