Renommer les noms de colonnes d'un DataFrame dans Spark Scala
J'essaie de convertir tous les en-têtes / noms de colonnes d'un DataFrame
dans Spark-Scala. maintenant je viens avec code suivant qui ne remplace qu'un seul nom de colonne.
for( i <- 0 to origCols.length - 1) {
df.withColumnRenamed(
df.columns(i),
df.columns(i).toLowerCase
);
}
3 réponses
Si la structure est plate:
val df = Seq((1L, "a", "foo", 3.0)).toDF
df.printSchema
// root
// |-- _1: long (nullable = false)
// |-- _2: string (nullable = true)
// |-- _3: string (nullable = true)
// |-- _4: double (nullable = false)
La chose La plus simple que vous pouvez faire est d'utiliser toDF
méthode:
val newNames = Seq("id", "x1", "x2", "x3")
val dfRenamed = df.toDF(newNames: _*)
dfRenamed.printSchema
// root
// |-- id: long (nullable = false)
// |-- x1: string (nullable = true)
// |-- x2: string (nullable = true)
// |-- x3: double (nullable = false)
Si vous souhaitez renommer des colonnes individuelles, vous pouvez utiliser soit select
avec alias
:
df.select($"_1".alias("x1"))
Qui peut être facilement généralisé à plusieurs colonnes:
val lookup = Map("_1" -> "foo", "_3" -> "bar")
df.select(df.columns.map(c => col(c).as(lookup.getOrElse(c, c))): _*)
Ou withColumnRenamed
:
df.withColumnRenamed("_1", "x1")
, Qui utilisent avec foldLeft
pour renommer plusieurs colonnes:
lookup.foldLeft(df)((acc, ca) => acc.withColumnRenamed(ca._1, ca._2))
Avec les structures imbriquées (structs
), une option possible consiste à renommer en sélectionnant un ensemble structure:
val nested = spark.read.json(sc.parallelize(Seq(
"""{"foobar": {"foo": {"bar": {"first": 1.0, "second": 2.0}}}, "id": 1}"""
)))
nested.printSchema
// root
// |-- foobar: struct (nullable = true)
// | |-- foo: struct (nullable = true)
// | | |-- bar: struct (nullable = true)
// | | | |-- first: double (nullable = true)
// | | | |-- second: double (nullable = true)
// |-- id: long (nullable = true)
@transient val foobarRenamed = struct(
struct(
struct(
$"foobar.foo.bar.first".as("x"), $"foobar.foo.bar.first".as("y")
).alias("point")
).alias("location")
).alias("record")
nested.select(foobarRenamed, $"id").printSchema
// root
// |-- record: struct (nullable = false)
// | |-- location: struct (nullable = false)
// | | |-- point: struct (nullable = false)
// | | | |-- x: double (nullable = true)
// | | | |-- y: double (nullable = true)
// |-- id: long (nullable = true)
Notez que cela peut affecter nullability
métadonnées. Une autre possibilité est de renommer par casting:
nested.select($"foobar".cast(
"struct<location:struct<point:struct<x:double,y:double>>>"
).alias("record")).printSchema
// root
// |-- record: struct (nullable = true)
// | |-- location: struct (nullable = true)
// | | |-- point: struct (nullable = true)
// | | | |-- x: double (nullable = true)
// | | | |-- y: double (nullable = true)
Ou:
import org.apache.spark.sql.types._
nested.select($"foobar".cast(
StructType(Seq(
StructField("location", StructType(Seq(
StructField("point", StructType(Seq(
StructField("x", DoubleType), StructField("y", DoubleType)))))))))
).alias("record")).printSchema
// root
// |-- record: struct (nullable = true)
// | |-- location: struct (nullable = true)
// | | |-- point: struct (nullable = true)
// | | | |-- x: double (nullable = true)
// | | | |-- y: double (nullable = true)
Pour ceux d'entre vous intéressés par la version PySpark (en fait C'est la même chose dans Scala-voir le commentaire ci-dessous):
merchants_df_renamed = merchants_df.toDF(
'merchant_id', 'category', 'subcategory', 'merchant')
merchants_df_renamed.printSchema()
root
|-- merchant_id: integer (nullable = true)
|-- category: string (nullable = true)
|-- subcategory: string (nullable = true)
|-- merchant: string (nullable = true)
def aliasAllColumns(t: DataFrame, p: String = "", s: String = ""): DataFrame =
{
t.select( t.columns.map { c => t.col(c).as( p + c + s) } : _* )
}
Dans le cas où is n'est pas évident, cela ajoute un préfixe et un suffixe à chacun des noms de colonne actuels. Cela peut être utile lorsque vous avez deux tables avec une ou plusieurs colonnes ayant le même nom, et que vous souhaitez les rejoindre mais que vous pouvez toujours désambiguïser les colonnes de la table résultante. Ce serait bien s'il y avait une manière similaire de le faire dans SQL "normal".