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
  );
}
59
demandé sur user8371915 2016-02-24 06:51:50

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)
182
répondu zero323 2017-03-26 20:15:56

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)
12
répondu Tagar 2018-08-09 04:13:54
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".

3
répondu Mylo Stone 2018-04-12 23:06:56