วิธีการเปลี่ยนชื่อคอลัมน์ข้อมูลใน pyspark?


201

ฉันมาจากพื้นหลังของ pandas และฉันคุ้นเคยกับการอ่านข้อมูลจากไฟล์ CSV เป็น dataframe แล้วก็เปลี่ยนชื่อคอลัมน์เป็นสิ่งที่มีประโยชน์โดยใช้คำสั่งง่าย ๆ :

df.columns = new_column_name_list

อย่างไรก็ตามเดียวกันไม่สามารถใช้งานได้ใน pyspark dataframes ที่สร้างขึ้นโดยใช้ sqlContext ทางออกเดียวที่ฉันสามารถคิดให้ทำได้ง่าย ๆ คือ:

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)

นี่คือการกำหนดตัวแปรโดยทั่วไปสองครั้งและอนุมานสคีมาก่อนจากนั้นเปลี่ยนชื่อชื่อคอลัมน์แล้วโหลดดาต้าเฟรมอีกครั้งด้วยสคีมาที่อัปเดต

มีวิธีที่ดีกว่าและมีประสิทธิภาพมากกว่าในการทำเช่นนี้ในแพนด้าหรือไม่?

เวอร์ชั่น Spark ของฉันคือ 1.5.0

คำตอบ:


334

มีหลายวิธีที่จะทำเช่นนั้น:

  • ตัวเลือกที่ 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สังเกตว่าวิธีนี้ช่วยให้คุณ "เขียนทับ" คอลัมน์เดียวกัน สำหรับ Python3 แทนที่ด้วยxrangerange

    from functools import reduce
    
    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 โดยใช้ นามแฝงใน Scala คุณยังสามารถใช้เป็น

    from pyspark.sql.functions import col
    
    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|
    #+-------+---+

1
ฉันไม่ได้มีforห่วง + withColumnRenamedแต่ของคุณreduceเป็นตัวเลือกที่ดีมาก :)
เฟลิเจอราร์ด

1
เนื่องจากไม่มีอะไรที่จะทำใน Spark จนกว่าจะมีการเรียกใช้การกระทำบน DF มันเป็นรหัสที่สง่างามน้อยกว่า ... ในที่สุด DF ผลลัพธ์ที่ได้ก็เหมือนกันทุกประการ!
เฟลิเป้เจอราร์ด

2
@FelipeGerard โปรดตรวจสอบโพสต์นี้อาจมีสิ่งไม่ดีเกิดขึ้นหากคุณมีหลายคอลัมน์
Alberto Bonsanto

1
@AlbertoBonsanto วิธีเลือกคอลัมน์เป็นนามแฝงหากมีมากกว่า 100 คอลัมน์ซึ่งเป็นตัวเลือกที่ดีที่สุด

3
@NuValue คุณควรวิ่งก่อนfrom functools import reduce
joaofbsm

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

ข้อดีของการใช้วิธีนี้: ด้วยรายการคอลัมน์แบบยาวคุณต้องการเปลี่ยนชื่อคอลัมน์เพียงเล็กน้อย สิ่งนี้จะสะดวกมากในสถานการณ์เหล่านี้ มีประโยชน์มากเมื่อเข้าร่วมตารางที่มีชื่อคอลัมน์ซ้ำกัน


มีความแตกต่างของการแก้ปัญหานี้ที่ทำให้คอลัมน์อื่น ๆ ทั้งหมดไม่เปลี่ยนแปลง? ด้วยวิธีนี้และอื่น ๆ เพียงคอลัมน์แจ้งชื่อยังคงอยู่ (คนอื่น ๆ ทั้งหมดออก)
Quetzalcoatl

1
+1 มันใช้ได้ดีสำหรับฉันเพิ่งแก้ไขคอลัมน์ที่ระบุโดยปล่อยให้ผู้อื่นไม่เปลี่ยนแปลงและไม่มีการลบคอลัมน์
mnis.p

2
@Quetzalcoatl คำสั่งนี้ดูเหมือนจะเปลี่ยนเฉพาะคอลัมน์ที่ระบุขณะที่ยังคงคอลัมน์อื่นทั้งหมด ดังนั้นคำสั่งที่ยอดเยี่ยมในการเปลี่ยนชื่อเพียงหนึ่งในชื่อคอลัมน์ที่อาจเกิดขึ้นมากมาย
user989762

@ user989762: ตกลง ความเข้าใจเริ่มแรกของฉันไม่ถูกต้องสำหรับอันนี้ ... !
Quetzalcoatl

62

หากคุณต้องการเปลี่ยนชื่อคอลัมน์ทั้งหมดให้ลอง df.toDF(*cols)


5
วิธีนี้เป็นวิธีที่ใกล้เคียงที่สุดกับ df.columns = new_column_name_list ต่อ OP ทั้งในแง่ของความกระชับและการปฏิบัติ
Quetzalcoatl

ฉันคิดว่าสิ่งนี้ควรถูกเลือกเป็นคำตอบที่ดีที่สุด
HanaKaze

สำหรับฉันฉันได้รับชื่อส่วนหัวจาก dataframe แพนด้าดังนั้นฉันเพิ่งใช้df = df.toDF(*my_pandas_df.columns)
Nic Scozzaro

คำตอบนี้ทำให้ฉันสับสน ไม่ควรมีการแมปจากชื่อคอลัมน์เก่าไปยังชื่อใหม่หรือ มันทำงานได้โดยมีcolsชื่อคอลัมน์ใหม่และเพียงแค่สมมติลำดับของชื่อที่colsสอดคล้องกับลำดับคอลัมน์ของ dataframe?
rbatt

47

ในกรณีที่คุณต้องการใช้การแปลงอย่างง่ายกับชื่อคอลัมน์ทั้งหมดรหัสนี้ใช้เคล็ดลับ: (ฉันกำลังแทนที่ช่องว่างทั้งหมดด้วยเครื่องหมายขีดล่าง)

new_column_name_list= list(map(lambda x: x.replace(" ", "_"), df.columns))

df = df.toDF(*new_column_name_list)

ขอบคุณที่ @ user8117731 สำหรับtoDfเคล็ดลับ


14

หากคุณต้องการเปลี่ยนชื่อคอลัมน์เดียวและคงส่วนที่เหลือไว้เหมือนเดิม:

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])

14

df.withColumnRenamed('age', 'age2')


1
คำตอบของ Pankaj KumarและคำตอบของAlberto Bonsanto (ซึ่งมาจาก 2016 และ 2015 ตามลำดับ) แนะนำให้ใช้withColumnRenamedแล้ว
Andrew Myers

ขอบคุณใช่ แต่มีไวยากรณ์ที่แตกต่างกันสองสามข้อเราอาจรวบรวมคำตอบที่เป็นทางการมากกว่านี้ data.withColumnRenamed (oldColumns [idx], newColumns [idx]) vs data.withColumnRenamed (คอลัมน์ชื่อคอลัมน์ใหม่) ฉันคิดว่ามันขึ้นอยู่กับเวอร์ชันของ pyspark ที่คุณใช้
Sahan Jayasumana

1
นี่ไม่ใช่ไวยากรณ์ที่แตกต่างกัน ข้อแตกต่างคือคุณไม่ได้เก็บชื่อคอลัมน์ไว้ในอาร์เรย์
Ed Bordin

13

นี่คือวิธีการที่ฉันใช้:

สร้างเซสชัน pyspark:

import pyspark
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName('changeColNames').getOrCreate()

สร้างดาต้าเฟรม:

df = spark.createDataFrame(data = [('Bob', 5.62,'juice'),  ('Sue',0.85,'milk')], schema = ["Name", "Amount","Item"])

ดู df ด้วยชื่อคอลัมน์:

df.show()
+----+------+-----+
|Name|Amount| Item|
+----+------+-----+
| Bob|  5.62|juice|
| Sue|  0.85| milk|
+----+------+-----+

สร้างรายการด้วยชื่อคอลัมน์ใหม่:

newcolnames = ['NameNew','AmountNew','ItemNew']

เปลี่ยนชื่อคอลัมน์ของ df:

for c,n in zip(df.columns,newcolnames):
    df=df.withColumnRenamed(c,n)

ดู df ด้วยชื่อคอลัมน์ใหม่:

df.show()
+-------+---------+-------+
|NameNew|AmountNew|ItemNew|
+-------+---------+-------+
|    Bob|     5.62|  juice|
|    Sue|     0.85|   milk|
+-------+---------+-------+

9

ฉันสร้างฟังก์ชันที่ใช้งานง่ายเพื่อเปลี่ยนชื่อหลายคอลัมน์สำหรับ pyspark dataframe ในกรณีที่ทุกคนต้องการใช้:

def renameCols(df, old_columns, new_columns):
    for old_col,new_col in zip(old_columns,new_columns):
        df = df.withColumnRenamed(old_col,new_col)
    return df

old_columns = ['old_name1','old_name2']
new_columns = ['new_name1', 'new_name2']
df_renamed = renameCols(df, old_columns, new_columns)

ระวังรายการทั้งสองจะต้องมีความยาวเท่ากัน


1
ทำได้ดีมากกับสิ่งนี้ overkill เล็กน้อยสำหรับสิ่งที่ฉันต้องการแม้ว่า และคุณก็สามารถส่งผ่าน DF เพราะจะเป็นเช่นเดียวกับold_columns df.columns
Darth Egregious

7

อีกวิธีในการเปลี่ยนชื่อเพียงหนึ่งคอลัมน์ (โดยใช้import pyspark.sql.functions as F):

df = df.select( '*', F.col('count').alias('new_count') ).drop('count')

3

ฉันใช้อันนี้:

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

2
ในขณะที่ข้อมูลโค้ดนี้อาจแก้ไขคำถามรวมถึงคำอธิบายช่วยปรับปรุงคุณภาพของโพสต์ของคุณ จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตและคนเหล่านั้นอาจไม่ทราบสาเหตุของการแนะนำรหัสของคุณ
Isma

1

คุณสามารถใช้ฟังก์ชันต่อไปนี้เพื่อเปลี่ยนชื่อคอลัมน์ทั้งหมดของ dataframe ของคุณ

def df_col_rename(X, to_rename, replace_with):
    """
    :param X: spark dataframe
    :param to_rename: list of original names
    :param replace_with: list of new names
    :return: dataframe with updated names
    """
    import pyspark.sql.functions as F
    mapping = dict(zip(to_rename, replace_with))
    X = X.select([F.col(c).alias(mapping.get(c, c)) for c in to_rename])
    return X

ในกรณีที่คุณต้องการอัปเดตชื่อคอลัมน์เพียงไม่กี่คอลัมน์คุณสามารถใช้ชื่อคอลัมน์เดียวกันในรายการ replace_with

หากต้องการเปลี่ยนชื่อคอลัมน์ทั้งหมด

df_col_rename(X,['a', 'b', 'c'], ['x', 'y', 'z'])

หากต้องการเปลี่ยนชื่อบางคอลัมน์

df_col_rename(X,['a', 'b', 'c'], ['a', 'y', 'z'])

0

สำหรับการเปลี่ยนชื่อคอลัมน์เดียวคุณยังสามารถใช้ toDF () ตัวอย่างเช่น,

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

0

เราสามารถใช้วิธีการต่าง ๆ เพื่อเปลี่ยนชื่อคอลัมน์

ก่อนอื่นให้สร้าง DataFrame อย่างง่าย ๆ

df = spark.createDataFrame([("x", 1), ("y", 2)], 
                                  ["col_1", "col_2"])

ตอนนี้ลองเปลี่ยนชื่อ col_1 เป็น col_3 PFB ไม่กี่วิธีในการทำเช่นเดียวกัน

# Approach - 1 : using withColumnRenamed function.
df.withColumnRenamed("col_1", "col_3").show()

# Approach - 2 : using alias function.
df.select(df["col_1"].alias("col3"), "col_2").show()

# Approach - 3 : using selectExpr function.
df.selectExpr("col_1 as col_3", "col_2").show()

# Rename all columns
# Approach - 4 : using toDF function. Here you need to pass the list of all columns present in DataFrame.
df.toDF("col_3", "col_2").show()

นี่คือผลลัพธ์

+-----+-----+
|col_3|col_2|
+-----+-----+
|    x|    1|
|    y|    2|
+-----+-----+

ฉันหวังว่านี่จะช่วยได้.

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.