Pandas Merge - Cách tránh trùng lặp các cột


93

Tôi đang cố gắng hợp nhất giữa hai khung dữ liệu. Mỗi khung dữ liệu có hai mức chỉ mục (ngày tháng, cusip). Ví dụ: trong các cột, một số cột khớp giữa hai (đơn vị tiền tệ, ngày điều chỉnh).

Cách tốt nhất để hợp nhất chúng theo chỉ mục, nhưng không lấy hai bản sao của tiền tệ và ngày điều chỉnh.

Mỗi khung dữ liệu là 90 cột, vì vậy tôi đang cố gắng tránh viết mọi thứ ra bằng tay.

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
...

Nếu tôi làm:

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

tôi có

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

Cảm ơn bạn! ...

Câu trả lời:


143

Bạn có thể tính ra các cột chỉ có trong một DataFrame và sử dụng cột này để chọn một tập hợp con các cột trong hợp nhất.

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

Sau đó thực hiện hợp nhất (lưu ý đây là một đối tượng chỉ mục nhưng nó có một tolist()phương thức tiện dụng ).

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

Điều này sẽ tránh bất kỳ cột nào xung đột trong hợp nhất.


Điều gì sẽ xảy ra nếu khóa là một cột và nó được gọi giống nhau? Nó sẽ bị loại bỏ với bước đầu tiên.
Guerra

cảm ơn bạn rất nhiều!!!
Có mây_Green

89

Tôi sử dụng suffixestùy chọn trong .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)

Cảm ơn @ijoseph


15
Sẽ là một câu trả lời hữu ích hơn nếu nó bao gồm mã cho filtering (khá đơn giản, nhưng vẫn tốn thời gian để tra cứu / dễ bị lỗi để ghi nhớ). tức là dfNew.drop(list(dfNew.filter(regex='_y$')), axis=1, inplace=True)
ijoseph

5

Tôi mới làm quen với Pandas nhưng tôi muốn đạt được điều tương tự, tự động tránh các tên cột có _x hoặc _y và xóa dữ liệu trùng lặp. Cuối cùng tôi đã làm điều đó bằng cách sử dụng này câu trả lời và điều này một từ Stackoverflow

sales.csv

    thành phố; tiểu bang; đơn vị
    Mendocino; CA; 1
    Denver; CO; 4
    Austin; TX; 2

doanh thu.csv

    chi nhánh_id; thành phố; doanh thu; bang_id
    10; Austin; 100; TX
    20; Austin; 83; TX
    30; Austin; 4; TX
    47; Austin; 200; TX
    20; Denver; 83; CO
    30; Springfield; 4; I

merge.py nhập gấu trúc

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=';')

Khi thực hiện lệnh hợp nhất, tôi thay thế _xhậu tố bằng một chuỗi trống và chúng tôi có thể xóa các cột kết thúc bằng_y

output.csv

    id; thành phố; tiểu bang; đơn vị; chi nhánh_id; doanh thu; bang_id
    0; Denver; CO; 4; 20; 83; CO
    1; Austin; TX; 2; 10; 100; TX
    2; Austin; TX; 2; 20; 83; TX
    3; Austin; TX; 2; 30; 4; TX
    4; Austin; TX; 2; 47; 200; TX

4

Dựa trên câu trả lời của @ rprog, bạn có thể kết hợp các phần khác nhau của hậu tố & bước lọc thành một dòng bằng cách sử dụng regex phủ định:

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

Hoặc sử dụng df.join:

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

Regex ở đây là giữ bất kỳ thứ gì không kết thúc bằng từ "DROP", vì vậy chỉ cần đảm bảo sử dụng một hậu tố không xuất hiện giữa các cột.

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.