2015-12-03 58 views
44

我来自熊猫的背景和我习惯于阅读从CSV文件数据到数据帧,然后只需使用简单的命令更改列名到一些有用的东西:如何更改pyspark中的数据框列名?

df.columns = new_column_name_list 

然而,同样不起作用在使用sqlContext创建的pyspark数据框。 我能想出很容易地做到这一点,唯一的解决办法是:

df = sqlContext.read.format("com.databricks.spark.csv").options(header='false', inferschema='true', delimiter='\t').load("data.txt") 
oldSchema = df.schema 
for i,k in enumerate(oldSchema.fields): 
    k.name = new_column_name_list[i] 
df = sqlContext.read.format("com.databricks.spark.csv").options(header='false', delimiter='\t').load("data.txt", schema=oldSchema) 

这基本上是用更新的架构定义变量两次,第一次推断架构,然后重命名列名,然后加载数据帧再次。

有没有更好更高效的方法来做到这一点,就像我们在熊猫做的一样?

我的火花的版本是1.5.0

回答

114

有很多方法可以做到这一点:

  • 选项1.使用selectExpr

    data = sqlContext.createDataFrame([("Alberto", 2), ("Dakota", 2)], 
                ["Name", "askdaosdka"]) 
    data.show() 
    data.printSchema() 
    
    # Output 
    #+-------+----------+ 
    #| Name|askdaosdka| 
    #+-------+----------+ 
    #|Alberto|   2| 
    #| Dakota|   2| 
    #+-------+----------+ 
    
    #root 
    # |-- Name: string (nullable = true) 
    # |-- askdaosdka: long (nullable = true) 
    
    df = data.selectExpr("Name as name", "askdaosdka as age") 
    df.show() 
    df.printSchema() 
    
    # Output 
    #+-------+---+ 
    #| name|age| 
    #+-------+---+ 
    #|Alberto| 2| 
    #| Dakota| 2| 
    #+-------+---+ 
    
    #root 
    # |-- name: string (nullable = true) 
    # |-- age: long (nullable = true) 
    
  • 选项2.使用withColumnRenamed,发现这种方法可以让你“覆盖”在同一列。

    oldColumns = data.schema.names 
    newColumns = ["name", "age"] 
    
    df = reduce(lambda data, idx: data.withColumnRenamed(oldColumns[idx], newColumns[idx]), xrange(len(oldColumns)), data) 
    df.printSchema() 
    df.show() 
    
  • 选项3.使用 alias,Scala里你也可以使用as

    from pyspark.sql.functions import * 
    
    data = data.select(col("Name").alias("name"), col("askdaosdka").alias("age")) 
    data.show() 
    
    # Output 
    #+-------+---+ 
    #| name|age| 
    #+-------+---+ 
    #|Alberto| 2| 
    #| Dakota| 2| 
    #+-------+---+ 
    
  • 选项4.使用sqlContext.sql,它可以让你使用SQL查询上DataFrames登记表。

    sqlContext.registerDataFrameAsTable(data, "myTable") 
    df2 = sqlContext.sql("SELECT Name AS name, askdaosdka as age from myTable") 
    
    df2.show() 
    
    # Output 
    #+-------+---+ 
    #| name|age| 
    #+-------+---+ 
    #|Alberto| 2| 
    #| Dakota| 2| 
    #+-------+---+ 
    
+0

我用'for'环+'withColumnRenamed'做到了,但你的'reduce'选项是非常好的:) –

+0

@FelipeGerard那是一个非常糟糕的主意 –

+0

好吧,因为在DF上调用一个动作之前没有任何东西在Spark中完成,它只是不那么优雅的代码......最终得到的DF完全相同! –

35
df = df.withColumnRenamed("colName", "newColName").withColumnRenamed("colName2", "newColName2") 

优势利用这样的:随着列长长的清单,你想改变只有少数列名。这在这些情况下可能非常方便。连接具有重复列名的表时非常有用。

+0

有没有这种解决方案的变体使所有其他列保持不变?使用此方法和其他方法时,只剩下明确命名的列(所有其他列都被删除) – Quetzalcoatl

5

如果要重命名一列,并保持休息,因为它是:

from pyspark.sql.functions import col 
new_df = old_df.select(*[col(s).alias(new_name) if s == column_to_change else s for s in old_df.columns]) 
5

如果你想改变所有的列名,尝试df.toDF(*cols)

0

对于单个列重命名,你可以仍然使用toDF()。例如,

df1.selectExpr("SALARY*2").toDF("REVISED_SALARY").show() 
0

我用这一个:

from pyspark.sql.functions import col 
df.select(['vin',col('timeStamp').alias('Date')]).show() 
+0

这不提供问题的答案。一旦你有足够的[声誉](https://stackoverflow.com/help/whats-reputation),你将可以[对任何帖子发表评论](https://stackoverflow.com/help/privileges/comment);相反,[提供不需要提问者澄清的答案](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-c​​an- I-DO-代替)。 - [来自评论](/ review/low-quality-posts/18681369) –

+0

虽然此代码片段可能会解决问题,[包括解释](http://meta.stackexchange.com/questions/114762/explaining-entirely基于代码的答案)真的有助于提高您的帖子的质量。请记住,您将来会为读者回答问题,而这些人可能不知道您的代码建议的原因。 – Isma

相关问题