Bagaimana cara mengubah nama kolom dataframe di pyspark?

201

Saya berasal dari latar belakang panda dan terbiasa membaca data dari file CSV ke dalam kerangka data dan kemudian hanya mengubah nama kolom menjadi sesuatu yang berguna menggunakan perintah sederhana:

df.columns = new_column_name_list

Namun, hal yang sama tidak berfungsi di pyspark dataframe yang dibuat menggunakan sqlContext. Satu-satunya solusi yang saya bisa lakukan dengan mudah adalah sebagai berikut:

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)

Ini pada dasarnya mendefinisikan variabel dua kali dan menyimpulkan skema pertama kemudian mengganti nama nama kolom dan kemudian memuat dataframe lagi dengan skema yang diperbarui.

Apakah ada cara yang lebih baik dan lebih efisien untuk melakukan ini seperti yang kita lakukan di panda?

Versi percikan saya adalah 1.5.0

Shubhanshu Mishra
sumber

Jawaban:

334

Ada banyak cara untuk melakukan itu:

  • Opsi 1. Menggunakan 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)
  • Opsi 2. Menggunakan withColumnRenamed , perhatikan bahwa metode ini memungkinkan Anda untuk "menimpa" kolom yang sama. Untuk Python3, ganti xrangedengan range.

    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()
  • Opsi 3. menggunakan alias , di Scala Anda juga dapat menggunakan sebagai .

    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|
    #+-------+---+
  • Opsi 4. Menggunakan sqlContext.sql , yang memungkinkan Anda menggunakan query SQL pada DataFramesterdaftar sebagai tabel.

    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|
    #+-------+---+
Alberto Bonsanto
sumber
1
Saya melakukannya dengan forloop + withColumnRenamed, tetapi reducepilihan Anda sangat bagus :)
Felipe Gerard
1
Ya karena tidak ada yang dilakukan di Spark sampai suatu tindakan dipanggil pada DF, itu hanya kode yang kurang elegan ... Pada akhirnya DF yang dihasilkan persis sama!
Felipe Gerard
2
@FelipeGerard Silakan periksa pos ini , hal-hal buruk dapat terjadi jika Anda memiliki banyak kolom.
Alberto Bonsanto
1
@AlbertoBonsanto Cara memilih kolom sebagai alias jika ada lebih dari 100 kolom yang merupakan pilihan terbaik
3
@NuValue, Anda harus terlebih dahulu menjalankanfrom functools import reduce
joaofbsm
168
df = df.withColumnRenamed("colName", "newColName")
       .withColumnRenamed("colName2", "newColName2")

Keuntungan menggunakan cara ini: Dengan daftar kolom yang panjang, Anda hanya ingin mengubah sedikit nama kolom. Ini bisa sangat nyaman dalam skenario ini. Sangat berguna saat bergabung dengan tabel dengan nama kolom duplikat.

Pankaj Kumar
sumber
apakah ada varian dari solusi ini yang membuat semua kolom lainnya tidak berubah? dengan metode ini, dan yang lainnya, hanya kolom-kolom yang dinamai secara eksplisit tetap (semua yang lain dihapus)
Quetzalcoatl
1
+1 berfungsi dengan baik untuk saya, baru saja mengedit kolom yang ditentukan sehingga yang lain tidak berubah dan tidak ada kolom yang dihapus.
mnis.p
2
@Quetzalcoatl Perintah ini tampaknya hanya mengubah kolom yang ditentukan sambil mempertahankan semua kolom lainnya. Oleh karena itu, perintah yang bagus untuk mengganti nama hanya satu dari banyak nama kolom yang berpotensi
user989762
@ user989762: disetujui; pemahaman awal saya salah tentang yang ini ...!
Quetzalcoatl
61

Jika Anda ingin mengubah semua nama kolom, coba df.toDF(*cols)

pengguna8117731
sumber
5
solusi ini adalah yang paling dekat dengan df.columns = new_column_name_list per OP, baik dalam cara ringkas dan pelaksanaannya.
Quetzalcoatl
Saya pikir ini harus dipilih sebagai jawaban terbaik
HanaKaze
Bagi saya, saya mendapatkan nama-nama tajuk dari bingkai data panda, jadi saya hanya menggunakandf = df.toDF(*my_pandas_df.columns)
Nic Scozzaro
Jawaban ini membingungkan saya. Tidakkah seharusnya ada pemetaan dari nama kolom lama ke nama baru? Apakah ini berhasil dengan colsmenjadi nama kolom yang baru, dan hanya mengasumsikan urutan nama colssesuai dengan urutan kolom dari dataframe?
rbatt
47

Jika Anda ingin menerapkan transformasi sederhana pada semua nama kolom, kode ini melakukan trik: (Saya mengganti semua spasi dengan garis bawah)

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

df = df.toDF(*new_column_name_list)

Terima kasih kepada @ user8117731 untuk toDftriknya.

pbah
sumber
13

Jika Anda ingin mengganti nama satu kolom dan simpan sisanya seperti apa adanya:

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])
Ratul Ghosh
sumber
13

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

Sahan Jayasumana
sumber
1
Jawaban Pankaj Kumar dan jawaban Alberto Bonsanto (masing-masing berasal dari 2016 dan 2015) sudah menyarankan menggunakan withColumnRenamed.
Andrew Myers
Terima kasih, ya tetapi ada beberapa sintaks yang berbeda, mungkin kita harus mengumpulkannya menjadi jawaban yang lebih formal? data.withColumnRenamed (oldColumns [idx], newColumns [idx]) vs data.withColumnRenamed (nama kolom, nama kolom baru) saya pikir itu tergantung pada versi pyspark yang Anda gunakan
Sahan Jayasumana
1
Ini bukan sintaks yang berbeda. Satu-satunya perbedaan adalah Anda tidak menyimpan nama kolom Anda dalam array.
Ed Bordin
13

inilah pendekatan yang saya gunakan:

buat sesi pyspark:

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

buat dataframe:

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

lihat df dengan nama kolom:

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

buat daftar dengan nama kolom baru:

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

ubah nama kolom df:

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

lihat df dengan nama kolom baru:

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

Saya membuat fungsi yang mudah digunakan untuk mengganti nama beberapa kolom untuk pyspark dataframe, kalau-kalau ada yang ingin menggunakannya:

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)

Hati-hati, kedua daftar harus memiliki panjang yang sama.

Manrique
sumber
1
Kerja bagus untuk yang satu ini. Sedikit berlebihan untuk apa yang saya butuhkan. Dan Anda bisa melewati df karena old_columnsakan sama dengan df.columns.
Darth Egregious
6

Cara lain untuk mengganti nama hanya satu kolom (menggunakan import pyspark.sql.functions as F):

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

Saya menggunakan ini:

from pyspark.sql.functions import col
df.select(['vin',col('timeStamp').alias('Date')]).show()
mike
sumber
2
Sementara potongan kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan sangat membantu untuk meningkatkan kualitas posting Anda. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, dan orang-orang itu mungkin tidak tahu alasan untuk saran kode Anda.
Isma
1

Anda dapat menggunakan fungsi berikut untuk mengubah nama semua kolom bingkai data Anda.

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

Jika Anda hanya perlu memperbarui beberapa nama kolom, Anda dapat menggunakan nama kolom yang sama di daftar replace_with

Untuk mengganti nama semua kolom

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

Untuk mengganti nama beberapa kolom

df_col_rename(X,['a', 'b', 'c'], ['a', 'y', 'z'])
Jam Budak
sumber
0

Untuk penggantian nama kolom tunggal, Anda masih dapat menggunakan toDF (). Sebagai contoh,

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

Kita dapat menggunakan berbagai pendekatan untuk mengganti nama nama kolom.

Pertama, mari kita buat DataFrame sederhana.

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

Sekarang mari kita coba ganti nama col_1 menjadi col_3. PFB beberapa pendekatan untuk melakukan hal yang sama.

# 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()

Ini outputnya.

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

Saya harap ini membantu.

Bhadani neeraj
sumber