เปลี่ยนชื่อคอลัมน์เฉพาะในนุ่น


182

ฉันมี dataframe dataที่เรียกว่า ฉันจะเปลี่ยนชื่อส่วนหัวคอลัมน์เดียวได้อย่างไร ยกตัวอย่างเช่นgdpการlog(gdp)?

data =
    y  gdp  cap
0   1    2    5
1   2    3    9
2   8    7    2
3   3    4    7
4   6    7    7
5   4    8    3
6   8    2    8
7   9    9   10
8   6    6    4
9  10   10    7

7
มีการทับซ้อนกันอย่างแน่นอน แต่มันก็ไม่ชัดเจนสำหรับฉันจาก "การเปลี่ยนชื่อคอลัมน์ในแพนด้า" ที่คุณสามารถแยกองค์ประกอบคอลัมน์เดี่ยวสำหรับการเปลี่ยนชื่อ แน่นอนว่าเมื่อมองย้อนกลับไปจะเห็นได้ชัดและถ้าฉันขุดลึกลงไปฉันอาจจะคิดได้ แต่ฉันคิดว่าคำถาม / คำตอบนี้ดีกว่าที่จะชี้ให้เห็น
jeremiahbuddha

คำตอบ:


360
data.rename(columns={'gdp':'log(gdp)'}, inplace=True)

การrenameแสดงที่ยอมรับ dict เป็น param เพื่อcolumnsให้คุณผ่าน dict ที่มีรายการเดียว

ดูเพิ่มเติมที่เกี่ยวข้อง


3
ใช้เวลานานมากในดาต้าเฟรมขนาดใหญ่ดังนั้นฉันเชื่อว่านี่เป็นการคัดลอกดาต้าเฟรมทั้งหมดในหน่วยความจำหรือไม่?
elgehelge

1
@elgehelge ไม่ควรทำการดำเนินการของ pandas ส่วนใหญ่จะส่งคืนสำเนาและยอมรับinplaceparam หากไม่สนใจ param นี้นี่เป็นข้อผิดพลาดคุณสามารถกำหนดเวลาด้วยและไม่ใช้ param ได้ลองทำสิ่งที่ชอบnew_df = df.rename(columns={'new_name':'old_name'})และดูว่าสิ่งนี้ไหม เร็วขึ้นหรือไม่
EdChum

1
@ EdChum ขอบคุณ การลบinplaceพารามิเตอร์เกือบสองเท่าของเวลาจาก 14 วินาทีถึง 26 วินาที แต่ 14 วินาทียังคงค่อนข้างนานเพียงเพื่อเปลี่ยนส่วนหัว ..
elgehelge

2
แค่บันทึกเดียวระวัง! หากไม่มีคอลัมน์เป้าหมาย (สะกดชื่อผิด) จะไม่ทำอะไรเลยโดยไม่มีข้อผิดพลาดหรือคำเตือน
Amir

1
@Quastiat เป็นเรื่องที่ค่อนข้างกดดันว่าทำไมบาง ops ง่าย ๆ เหล่านี้ถึงเร็วขึ้นด้วยการทำรายการความเข้าใจ แม้ว่าโดยพื้นฐานแล้วถ้าคุณมี df ที่มีขนาดใหญ่มากมันก็ไม่ควรสำคัญถ้าคุณเปลี่ยนชื่อคอลัมน์เป็นจำนวนมากใน df ที่มีขนาดใหญ่
EdChum

27

การนำไปใช้ที่เร็วขึ้นนั้นจะต้องใช้list-comprehensionหากคุณต้องการเปลี่ยนชื่อคอลัมน์เดียว

df.columns = ['log(gdp)' if x=='gdp' else x for x in df.columns]

หากความต้องการเกิดขึ้นเพื่อเปลี่ยนชื่อหลายคอลัมน์ให้ใช้การแสดงออกตามเงื่อนไขเช่น:

df.columns = ['log(gdp)' if x=='gdp' else 'cap_mod' if x=='cap' else x for x in df.columns]

หรือสร้างการแมปโดยใช้dictionaryและดำเนินการlist-comprehensionกับgetการดำเนินการโดยตั้งค่าเริ่มต้นเป็นชื่อเก่า:

col_dict = {'gdp': 'log(gdp)', 'cap': 'cap_mod'}   ## key→old name, value→new name

df.columns = [col_dict.get(x, x) for x in df.columns]

การกำหนดเวลา:

%%timeit
df.rename(columns={'gdp':'log(gdp)'}, inplace=True)
10000 loops, best of 3: 168 µs per loop

%%timeit
df.columns = ['log(gdp)' if x=='gdp' else x for x in df.columns]
10000 loops, best of 3: 58.5 µs per loop

ฉันชอบที่จะใช้วิธีนี้ แต่น่าเสียดายที่มันไม่ทำงานpd.merge_asof()เพราะเป็นนิพจน์ :(.
thdoan

14

ฉันจะเปลี่ยนชื่อคอลัมน์เฉพาะในแพนด้าได้อย่างไร

จาก v0.24 + เพื่อเปลี่ยนชื่อทีละหนึ่งคอลัมน์ (หรือมากกว่า)

  • DataFrame.rename()ด้วยaxis=1หรือaxis='columns'(คนโต้แย้งเป็นที่รู้จักในaxisv0.21

  • Index.str.replace() สำหรับการแทนที่ด้วยสตริง / regex

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

  • DataFrame.set_axis()axis=1ด้วยวิธี ผ่านลำดับเหมือนรายการ ตัวเลือกที่มีอยู่สำหรับการปรับเปลี่ยนในสถานที่เช่นกัน

rename กับ axis=1

df = pd.DataFrame('x', columns=['y', 'gdp', 'cap'], index=range(5))
df

   y gdp cap
0  x   x   x
1  x   x   x
2  x   x   x
3  x   x   x
4  x   x   x

ด้วย 0.21+ ตอนนี้คุณสามารถระบุaxisพารามิเตอร์ด้วยrename:

df.rename({'gdp':'log(gdp)'}, axis=1)
# df.rename({'gdp':'log(gdp)'}, axis='columns')
    
   y log(gdp) cap
0  x        x   x
1  x        x   x
2  x        x   x
3  x        x   x
4  x        x   x

(โปรดทราบว่าrenameไม่ใช่ค่าเริ่มต้นแทนดังนั้นคุณจะต้องกำหนดผลลัพธ์คืน )

การเพิ่มนี้มีขึ้นเพื่อปรับปรุงความสอดคล้องกับส่วนที่เหลือของ API axisอาร์กิวเมนต์ใหม่นั้นคล้ายคลึงกับcolumnsพารามิเตอร์ซึ่งทำในสิ่งเดียวกัน

df.rename(columns={'gdp': 'log(gdp)'})

   y log(gdp) cap
0  x        x   x
1  x        x   x
2  x        x   x
3  x        x   x
4  x        x   x

rename ยอมรับการเรียกกลับที่ถูกเรียกหนึ่งครั้งสำหรับแต่ละคอลัมน์

df.rename(lambda x: x[0], axis=1)
# df.rename(lambda x: x[0], axis='columns')

   y  g  c
0  x  x  x
1  x  x  x
2  x  x  x
3  x  x  x
4  x  x  x

สำหรับสถานการณ์เฉพาะนี้คุณต้องการใช้

df.rename(lambda x: 'log(gdp)' if x == 'gdp' else x, axis=1)

Index.str.replace

คล้ายกับreplaceวิธีการของสตริงใน python ดัชนี pandas และ Series (object dtype เท่านั้น) กำหนดวิธี ("vectorized") str.replaceสำหรับการแทนที่สตริงและตาม regex

df.columns = df.columns.str.replace('gdp', 'log(gdp)')
df
 
   y log(gdp) cap
0  x        x   x
1  x        x   x
2  x        x   x
3  x        x   x
4  x        x   x

ข้อดีของการใช้วิธีนี้มากกว่าวิธีอื่นคือstr.replaceรองรับ regex (เปิดใช้งานโดยค่าเริ่มต้น) ดูเอกสารสำหรับข้อมูลเพิ่มเติม


ผ่านรายการไปset_axisด้วยaxis=1

โทรset_axisด้วยรายการส่วนหัว รายการต้องมีความยาวเท่ากับคอลัมน์ / ขนาดดัชนี set_axisเปลี่ยนค่า DataFrame ดั้งเดิมตามค่าเริ่มต้น แต่คุณสามารถระบุinplace=Falseเพื่อส่งคืนสำเนาที่แก้ไข

df.set_axis(['cap', 'log(gdp)', 'y'], axis=1, inplace=False)
# df.set_axis(['cap', 'log(gdp)', 'y'], axis='columns', inplace=False)

  cap log(gdp)  y
0   x        x  x
1   x        x  x
2   x        x  x
3   x        x  x
4   x        x  x

หมายเหตุ: ในรุ่นอนาคต inplaceTrueจะเริ่มต้น

วิธีการผูกมัด
ทำไมต้องเลือกset_axisเมื่อเรามีวิธีที่มีประสิทธิภาพในการกำหนดคอลัมน์ด้วยแล้วdf.columns = ...? ตามที่แสดงโดย Ted Petrou ใน [คำตอบนี้], ( https://stackoverflow.com/a/46912050/4909087 ) set_axisมีประโยชน์เมื่อพยายามเชื่อมโยงวิธีต่างๆ

เปรียบเทียบ

# new for pandas 0.21+
df.some_method1()
  .some_method2()
  .set_axis()
  .some_method3()

กับ

# old way
df1 = df.some_method1()
        .some_method2()
df1.columns = columns
df1.some_method3()

อดีตเป็นไวยากรณ์ที่เป็นธรรมชาติมากขึ้นและเป็นอิสระ


3

มีวิธีที่แตกต่างกันอย่างน้อยห้าวิธีในการเปลี่ยนชื่อคอลัมน์เฉพาะในนุ่นและฉันได้ระบุไว้ด้านล่างพร้อมกับลิงก์ไปยังคำตอบเดิม ฉันยังตั้งเวลาวิธีการเหล่านี้และพบว่าพวกเขาดำเนินการเกี่ยวกับเดียวกัน (แม้ว่า YMMV ขึ้นอยู่กับชุดข้อมูลและสถานการณ์ของคุณ) การทดสอบกรณีดังต่อไปนี้คือการเปลี่ยนชื่อคอลัมน์A M N ZไปA2 M2 N2 Z2ใน dataframe กับคอลัมน์Aที่จะZมีล้านแถว

# Import required modules
import numpy as np
import pandas as pd
import timeit

# Create sample data
df = pd.DataFrame(np.random.randint(0,9999,size=(1000000, 26)), columns=list('ABCDEFGHIJKLMNOPQRSTUVWXYZ'))

# Standard way - https://stackoverflow.com/a/19758398/452587
def method_1():
    df_renamed = df.rename(columns={'A': 'A2', 'M': 'M2', 'N': 'N2', 'Z': 'Z2'})

# Lambda function - https://stackoverflow.com/a/16770353/452587
def method_2():
    df_renamed = df.rename(columns=lambda x: x + '2' if x in ['A', 'M', 'N', 'Z'] else x)

# Mapping function - https://stackoverflow.com/a/19758398/452587
def rename_some(x):
    if x=='A' or x=='M' or x=='N' or x=='Z':
        return x + '2'
    return x
def method_3():
    df_renamed = df.rename(columns=rename_some)

# Dictionary comprehension - https://stackoverflow.com/a/58143182/452587
def method_4():
    df_renamed = df.rename(columns={col: col + '2' for col in df.columns[
        np.asarray([i for i, col in enumerate(df.columns) if 'A' in col or 'M' in col or 'N' in col or 'Z' in col])
    ]})

# Dictionary comprehension - https://stackoverflow.com/a/38101084/452587
def method_5():
    df_renamed = df.rename(columns=dict(zip(df[['A', 'M', 'N', 'Z']], ['A2', 'M2', 'N2', 'Z2'])))

print('Method 1:', timeit.timeit(method_1, number=10))
print('Method 2:', timeit.timeit(method_2, number=10))
print('Method 3:', timeit.timeit(method_3, number=10))
print('Method 4:', timeit.timeit(method_4, number=10))
print('Method 5:', timeit.timeit(method_5, number=10))

เอาท์พุท:

Method 1: 3.650640267
Method 2: 3.163998427
Method 3: 2.998530871
Method 4: 2.9918436889999995
Method 5: 3.2436501520000007

ใช้วิธีการที่ง่ายที่สุดสำหรับคุณและง่ายที่สุดสำหรับคุณในการนำไปใช้ในแอปพลิเคชันของคุณ

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