Подтвердить что ты не робот

Переименование имен столбцов DataFrame в Spark Scala

Я пытаюсь преобразовать все заголовки/имена столбцов DataFrame в Spark-Scala. на данный момент я придумал следующий код, который заменяет только одно имя столбца.

for( i <- 0 to origCols.length - 1) {
  df.withColumnRenamed(
    df.columns(i), 
    df.columns(i).toLowerCase
  );
}
4b9b3361

Ответ 1

Если структура плоская:

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)

Простейшая вещь, которую вы можете сделать, это использовать метод toDF:

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)

Если вы хотите переименовать отдельные столбцы, вы можете использовать либо select с alias:

df.select($"_1".alias("x1"))

который легко обобщается на несколько столбцов:

val lookup = Map("_1" -> "foo", "_3" -> "bar")

df.select(df.columns.map(c => col(c).as(lookup.getOrElse(c, c))): _*)

или withColumnRenamed:

df.withColumnRenamed("_1", "x1")

которые используют foldLeft для переименования нескольких столбцов:

lookup.foldLeft(df)((acc, ca) => acc.withColumnRenamed(ca._1, ca._2))

С вложенными структурами (structs) одним из возможных вариантов является переименование, выбирая целую структуру:

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)

Обратите внимание, что это может повлиять на метаданные nullability. Другая возможность - переименовать путем кастинга:

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)

или

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)

Ответ 2

Для тех из вас, кто интересуется версией PySpark (на самом деле это то же самое в Scala - см. Комментарий ниже):

merchants_df_renamed = merchants_df.toDF(
    'merchant_id', 'category', 'subcategory', 'merchant')

merchants_df_renamed.printSchema()

Результат:

корень
| - Куплю/продам
| - Тематические форумы
| - Подкатегория: строка (nullable = true)
| - Охота и рыбалка

Ответ 3

def aliasAllColumns(t: DataFrame, p: String = "", s: String = ""): DataFrame =
{
  t.select( t.columns.map { c => t.col(c).as( p + c + s) } : _* )
}

В случае, если это не очевидно, это добавляет префикс и суффикс для каждого из текущих имен столбцов. Это может быть полезно, когда у вас есть две таблицы с одним или несколькими столбцами с тем же именем, и вы хотите присоединиться к ним, но все же сможете устранить неоднозначность столбцов в результирующей таблице. Конечно, было бы неплохо, если бы был аналогичный способ сделать это в "нормальном" SQL.