Pandas Merge - วิธีหลีกเลี่ยงการทำซ้ำคอลัมน์


93

ฉันกำลังพยายามผสานระหว่างสองกรอบข้อมูล แต่ละกรอบข้อมูลมีดัชนีสองระดับ (วันที่, cusip) ในคอลัมน์บางคอลัมน์จะจับคู่ระหว่างสอง (currency, adj date) เช่น

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

แต่ละเฟรมข้อมูลมี 90 คอลัมน์ดังนั้นฉันจึงพยายามหลีกเลี่ยงการเขียนทุกอย่างด้วยมือ

df:                 currency  adj_date   data_col1 ...
date        cusip
2012-01-01  XSDP      USD      2012-01-03   0.45
...

df2:                currency  adj_date   data_col2 ...
date        cusip
2012-01-01  XSDP      USD      2012-01-03   0.45
...

ถ้าฉันทำ:

dfNew = merge(df, df2, left_index=True, right_index=True, how='outer')

ฉันเข้าใจ

dfNew:              currency_x  adj_date_x   data_col2 ... currency_y adj_date_y
date        cusip
2012-01-01  XSDP      USD      2012-01-03   0.45             USD         2012-01-03

ขอบคุณ! ...

คำตอบ:


143

คุณสามารถกำหนดคอลัมน์ที่อยู่ใน DataFrame เดียวเท่านั้นและใช้สิ่งนี้เพื่อเลือกคอลัมน์ย่อยในการผสาน

cols_to_use = df2.columns.difference(df.columns)

จากนั้นทำการผสาน (โปรดทราบว่านี่เป็นวัตถุดัชนี แต่มีtolist()วิธีการที่สะดวก)

dfNew = merge(df, df2[cols_to_use], left_index=True, right_index=True, how='outer')

วิธีนี้จะหลีกเลี่ยงไม่ให้คอลัมน์ใด ๆ ปะทะกันในการผสาน


จะเกิดอะไรขึ้นถ้าคีย์เป็นคอลัมน์และเรียกว่าเหมือนกัน? มันจะถูกทิ้งด้วยขั้นตอนแรก
Guerra

ขอบคุณมาก!!!
Cloudy_Green

88

ฉันใช้suffixesตัวเลือกใน.merge():

dfNew = df.merge(df2, left_index=True, right_index=True,
                 how='outer', suffixes=('', '_y'))
dfNew.drop(dfNew.filter(regex='_y$').columns.tolist(),axis=1, inplace=True)

ขอบคุณ @ijoseph


15
จะเป็นคำตอบที่เป็นประโยชน์มากขึ้นหากมีรหัสสำหรับfiltering (ซึ่งค่อนข้างตรงไปตรงมา แต่ก็ยังใช้เวลานานในการค้นหา / จำข้อผิดพลาดได้ง่าย) คือ dfNew.drop(list(dfNew.filter(regex='_y$')), axis=1, inplace=True)
ijoseph

5

ฉันเพิ่งใหม่กับ Pandas แต่ฉันต้องการบรรลุสิ่งเดียวกันโดยหลีกเลี่ยงชื่อคอลัมน์ที่มี _x หรือ _y และลบข้อมูลที่ซ้ำกันโดยอัตโนมัติ ในที่สุดผมก็ทำมันโดยใช้นี้คำตอบนี้และหนึ่งจาก Stackoverflow

sales.csv

    เมือง; รัฐ; หน่วย
    เมนโดซิโน; แคลิฟอร์เนีย; 1
    เดนเวอร์; CO; 4
    ออสติน; เท็กซัส; 2

Revenue.csv

    branch_id; เมือง; รายได้; state_id
    10; ออสติน; 100; เท็กซัส
    20; ออสติน 83; TX
    30; ออสติน; 4; TX
    47; ออสติน; 200; TX
    20; เดนเวอร์ 83; CO
    30; สปริงฟิลด์; 4; I

merge.py นำเข้าแพนด้า

def drop_y(df):
    # list comprehension of the cols that end with '_y'
    to_drop = [x for x in df if x.endswith('_y')]
    df.drop(to_drop, axis=1, inplace=True)


sales = pandas.read_csv('data/sales.csv', delimiter=';')
revenue = pandas.read_csv('data/revenue.csv', delimiter=';')

result = pandas.merge(sales, revenue,  how='inner', left_on=['state'], right_on=['state_id'], suffixes=('', '_y'))
drop_y(result)
result.to_csv('results/output.csv', index=True, index_label='id', sep=';')

เมื่อเรียกใช้คำสั่ง merge ฉันแทนที่_xคำต่อท้ายด้วยสตริงว่างและฉันสามารถลบคอลัมน์ที่ลงท้ายด้วย_y

output.csv

    id; เมือง; รัฐ; หน่วย; branch_id; รายได้; state_id
    0; เดนเวอร์; CO; 4; 20; 83; CO
    1; ออสตินเท็กซัส; 2; 10; 100; เท็กซัส
    2; ออสติน; TX; 2; 20; 83; TX
    3; ออสติน; เท็กซัส; 2; 30; 4; เท็กซัส
    4; ออสติน; TX; 2; 47; 200; TX

4

จากคำตอบของ @ rprog คุณสามารถรวมส่วนต่างๆของคำต่อท้ายและขั้นตอนตัวกรองเป็นบรรทัดเดียวโดยใช้ regex เชิงลบ:

dfNew = df.merge(df2, left_index=True, right_index=True,
             how='outer', suffixes=('', '_DROP')).filter(regex='^(?!.*_DROP)')

หรือใช้df.join:

dfNew = df.join(df2),lsuffix="DROP").filter(regex="^(?!.*DROP)")

นิพจน์ทั่วไปในที่นี้จะเก็บทุกสิ่งที่ไม่ได้ลงท้ายด้วยคำว่า "DROP" ดังนั้นโปรดใช้คำต่อท้ายที่ไม่ปรากฏในคอลัมน์อยู่แล้ว

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