当前位置: 首页 > 知识库问答 >
问题:

在Spark Scala中重命名DataFrame的列名

须捷
2023-03-14

我正在尝试转换Spark-Scala中dataframe的所有标题/列名。到目前为止,我提出了以下代码,它只替换单个列名。

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

共有1个答案

姚煜
2023-03-14

如果结构是扁平的:

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)

如果要重命名单个列,可以使用,选择,别名:

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))): _*)
df.withColumnRenamed("_1", "x1")
lookup.foldLeft(df)((acc, ca) => acc.withColumnRenamed(ca._1, ca._2))
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)
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)
 类似资料:
  • 我还尝试了以下操作: 同样,在我运行脚本之后,不会出现。我只有前两个字段名;第三个不停地掉下来。我该怎么解决这个?

  • 我正在尝试用dataframe.from_dict操作命名新dataframe的列。

  • 我正在尝试更改dataframe列的名称,我尝试了两种方法,但都不起作用。这是我的代码; 方法一:

  • 我想在sqlite中重命名列。我为一些列创建了两个带空格的单词标题,这些标题稍后会产生问题(例如而不是。 以前,这似乎是不可能的链接。但是几个月前的一个版本似乎包含了选项链接。 然而,这似乎不起作用。 查询将生成以下错误消息: 我为列名添加了引号,以防出现空格问题: 但也会出现同样的错误。 此解决方案提示重命名是可能的。但只重命名表(这很好),而不重命名列。

  • 还有其他关于如何重命名PySpark DataFrame中的列的线程,请参见这里、这里和这里。我不认为现有的解决方案具有足够的性能或通用性(我有一个应该更好的解决方案,但我被一个边缘情况bug所困扰)。让我们从回顾当前解决方案中的问题开始: 重复调用可能会遇到与多次调用相同的性能问题,如本博客文章所述。请参见此答案中的选项2。 toDF方法依赖于模式推断,不一定保留列的nullable属性(在生产