パンダのマージ-列の重複を回避する方法


95

2つのデータフレーム間のマージを試みています。各データフレームには、2つのインデックスレベル(日付、cusip)があります。列では、たとえば、いくつかの列が2つ(通貨、調整日)の間で一致します。

これらをインデックスでマージする最良の方法は何ですか。ただし、通貨と調整日を2つコピーしないでください。

各データフレームは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

ありがとうございました!..。

回答:


148

1つの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')

これにより、マージで列が衝突するのを防ぐことができます。


3
キーが列であり、同じ名前である場合はどうなりますか?それは最初のステップで削除されます。
ゲラ

93

私はで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


17
filteringのコードが含まれていると、より役立つ回答になります(これはかなり簡単ですが、検索に時間がかかり、エラーが発生しやすくなります)。すなわち dfNew.drop(list(dfNew.filter(regex='_y$')), axis=1, inplace=True)
ijoseph

6

@rprogの回答に基づいて、負の正規表現を使用して、接尾辞とフィルターのステップのさまざまな部分を1行に組み合わせることができます。

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」という単語で終わらないものをすべて保持しているため、列にまだ表示されていないサフィックスを使用してください。


5

私はPandasを初めて使用しましたが、同じことを実現したかったのです。_xまたは_yの列名を自動的に回避し、重複データを削除しました。私は最終的に、この使用してそれをやった答えはこの1 stackoverflowのからを

sales.csv

    市;州;単位
    メンドシノ; CA; 1
    デンバー; CO; 4
    オースティン; TX; 2

収益.csv

    branch_id; city; revenue; state_id
    10;オースティン; 100; TX
    20;オースティン; 83; TX
    30;オースティン; 4; TX
    47;オースティン; 200; TX
    20;デンバー; 83; CO
    30;スプリングフィールド; 4;私

merge.py importpandas

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

マージコマンドを実行するとき、_xサフィックスを空の文字列に置き換え、それらで終わる列を削除できます_y

output.csv

    id; city; state; units; branch_id; revenue; state_id
    0;デンバー; CO; 4; 20; 83; CO
    1;オースティン; TX; 2; 10; 100; TX
    2;オースティン; TX; 2; 20; 83; TX
    3;オースティン; TX; 2; 30; 4; TX
    4;オースティン; TX; 2; 47; 200; TX

0

これは問題を少し回避することですが、基本的に余分な列を処理する関数を作成しました。

def merge_fix_cols(df_company,df_product,uniqueID):
    
    df_merged = pd.merge(df_company,
                         df_product,
                         how='left',left_on=uniqueID,right_on=uniqueID)    
    for col in df_merged:
        if col.endswith('_x'):
            df_merged.rename(columns = lambda col:col.rstrip('_x'),inplace=True)
        elif col.endswith('_y'):
            to_drop = [col for col in df_merged if col.endswith('_y')]
            df_merged.drop(to_drop,axis=1,inplace=True)
        else:
            pass
    return df_merged

私のマージでうまくいくようです!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.