Làm cách nào để thay đổi tên cột dataframe trong pyspark?


201

Tôi đến từ nền gấu trúc và quen đọc dữ liệu từ các tệp CSV thành một khung dữ liệu và sau đó chỉ cần thay đổi tên cột thành một cái gì đó hữu ích bằng cách sử dụng lệnh đơn giản:

df.columns = new_column_name_list

Tuy nhiên, điều tương tự không hoạt động trong các tệp dữ liệu pyspark được tạo bằng sqlContext. Giải pháp duy nhất tôi có thể tìm ra để làm điều này một cách dễ dàng là như sau:

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)

Điều này về cơ bản là xác định biến hai lần và suy ra lược đồ trước sau đó đổi tên các tên cột và sau đó tải lại khung dữ liệu với lược đồ được cập nhật.

Có cách nào tốt hơn và hiệu quả hơn để làm điều này giống như chúng ta làm trong gấu trúc không?

Phiên bản tia lửa của tôi là 1.5.0

Câu trả lời:


334

Có nhiều cách để làm điều đó:

  • Tùy chọn 1. Sử dụng 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)
    
  • Tùy chọn 2. Sử dụng withColumnRenamed , lưu ý rằng phương pháp này cho phép bạn "ghi đè" cùng một cột. Đối với Python3, thay thế xrangebằng 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()
    
  • Tùy chọn 3. sử dụng bí danh , trong Scala bạn cũng có thể sử dụng như .

    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|
    #+-------+---+
    
  • Tùy chọn 4. Sử dụng sqlContext.sql , cho phép bạn sử dụng các truy vấn SQL trên DataFramesđăng ký dưới dạng bảng.

    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
Tôi đã làm điều đó với một forvòng lặp + withColumnRenamed, nhưng reducetùy chọn của bạn rất hay :)
Felipe Gerard

1
Chà vì không có gì được thực hiện trong Spark cho đến khi một hành động được gọi trên DF, nó chỉ là mã kém thanh lịch hơn ... Cuối cùng, kết quả DF hoàn toàn giống nhau!
Felipe Gerard

2
@FelipeGerard Vui lòng kiểm tra bài đăng này , điều tồi tệ có thể xảy ra nếu bạn có nhiều cột.
Alberto Bonsanto

1
@AlbertoBonsanto Cách chọn cột làm bí danh nếu có hơn 100 cột là tùy chọn tốt nhất

3
@NuValue, trước tiên bạn nên chạyfrom functools import reduce
joaofbsm

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

Ưu điểm của việc sử dụng theo cách này: Với danh sách các cột dài, bạn chỉ muốn thay đổi một vài tên cột. Điều này có thể rất thuận tiện trong các kịch bản. Rất hữu ích khi nối các bảng với tên cột trùng lặp.


Có một biến thể của giải pháp này mà giữ cho tất cả các cột khác không thay đổi? với phương thức này và các phương thức khác, chỉ còn lại các cột được đặt tên rõ ràng (tất cả các cột khác đã bị xóa)
Quetzalcoatl

1
+1 nó hoạt động tốt với tôi, chỉ cần chỉnh sửa cột được chỉ định mà không thay đổi cột khác và không có cột nào bị xóa.
mnis.p 18/07/18

2
@Quetzalcoatl Lệnh này dường như chỉ thay đổi cột được chỉ định trong khi duy trì tất cả các cột khác. Do đó, một lệnh tuyệt vời để đổi tên chỉ một trong số nhiều tên cột có khả năng
user989762

@ user989762: đã đồng ý; sự hiểu biết ban đầu của tôi là không chính xác về điều này ...!
Quetzalcoatl

61

Nếu bạn muốn thay đổi tất cả các tên cột, hãy thử df.toDF(*cols)


5
giải pháp này là gần nhất với df.columns = new_column_name_list cho mỗi OP, cả về cách thức ngắn gọn và thực thi của nó.
Quetzalcoatl

Tôi nghĩ rằng đây nên được chọn là câu trả lời hay nhất
HanaKaze

Đối với tôi, tôi đã nhận được tên tiêu đề từ khung dữ liệu gấu trúc, vì vậy tôi chỉ sử dụngdf = df.toDF(*my_pandas_df.columns)
Nic Scozzaro

Câu trả lời này làm tôi bối rối. Không nên có một ánh xạ từ tên cột cũ sang tên mới? Điều này có hoạt động bằng cách có colscác tên cột mới và chỉ giả sử thứ tự các tên colstương ứng với thứ tự cột của khung dữ liệu?
rbatt

47

Trong trường hợp bạn muốn áp dụng một phép chuyển đổi đơn giản cho tất cả các tên cột, mã này thực hiện thủ thuật: (Tôi đang thay thế tất cả các khoảng trắng bằng dấu gạch dưới)

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

df = df.toDF(*new_column_name_list)

Cảm ơn @ user8117731 để toDflừa.


13

Nếu bạn muốn đổi tên một cột và giữ phần còn lại như sau:

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

13

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


1
Câu trả lời của Pankaj Kumarcâu trả lời của Alberto Bonsanto (tương ứng từ năm 2016 và 2015) đã đề xuất sử dụng withColumnRenamed.
Andrew Myers

Cảm ơn, có nhưng có một vài cú pháp khác nhau, có lẽ chúng ta nên thu thập chúng thành một câu trả lời chính thức hơn? data.withColumnRenamed (oldColumns [idx], newColumns [idx]) vs data.withColumnRenamed (tên cột, tên cột mới) tôi nghĩ rằng nó phụ thuộc vào phiên bản pyspark nào bạn sử dụng
Sahan Jayasumana

1
Đây không phải là một cú pháp khác nhau. Sự khác biệt duy nhất là bạn đã không lưu trữ tên cột của bạn trong một mảng.
Ed Bordin

13

đây là cách tiếp cận mà tôi đã sử dụng:

tạo phiên pyspark:

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

tạo khung dữ liệu:

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

xem df với tên cột:

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

tạo một danh sách với các tên cột mới:

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

thay đổi tên cột của df:

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

xem df với tên cột mới:

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

9

Tôi đã tạo một hàm dễ sử dụng để đổi tên nhiều cột cho khung dữ liệu pyspark, trong trường hợp bất kỳ ai cũng muốn sử dụng nó:

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)

Hãy cẩn thận, cả hai danh sách phải có cùng độ dài.


1
Tốt công việc này. Một chút quá mức cho những gì tôi cần mặc dù. Và bạn chỉ có thể vượt qua df vì old_columnssẽ giống như df.columns.
Darth Egregious

6

Một cách khác để đổi tên chỉ một cột (sử dụng import pyspark.sql.functions as F):

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

3

Tôi sử dụng cái này:

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

2
Mặc dù đoạn mã này có thể giải quyết câu hỏi, bao gồm một lời giải thích thực sự giúp cải thiện chất lượng bài đăng của bạn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai và những người đó có thể không biết lý do cho đề xuất mã của bạn.
Isma

1

Bạn có thể sử dụng chức năng sau để đổi tên tất cả các cột trong khung dữ liệu của mình.

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

Trong trường hợp bạn chỉ cần cập nhật một vài tên cột, bạn có thể sử dụng cùng tên cột trong danh sách thay thế

Để đổi tên tất cả các cột

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

Để đổi tên một số cột

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

0

Đối với đổi tên cột đơn, bạn vẫn có thể sử dụng toDF (). Ví dụ,

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

0

Chúng ta có thể sử dụng các cách tiếp cận khác nhau để đổi tên tên cột.

Đầu tiên, hãy tạo một DataFrame đơn giản.

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

Bây giờ, hãy thử đổi tên col_1 thành col_3. PFB một vài cách tiếp cận để làm như vậy.

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

Đây là đầu ra.

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

Tôi hi vọng cái này giúp được.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.