128

我正在尝试在两个数据框之间进行合并。每个数据框都有两个索引级别(日期、cusip)。例如,在列中,某些列在两者之间匹配(货币、调整日期)。

按索引合并这些的最佳方法是什么,但不要复制两份货币和调整日期。

每个数据框有 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

谢谢!...

4

8 回答 8

181

您可以计算出仅在一个 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')

这将避免任何列在合并中发生冲突。

于 2013-10-01T20:43:17.660 回答
139

我使用以下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)

谢谢@joseph

于 2016-06-26T00:13:15.310 回答
16

基于@rprog 的回答,您可以使用负正则表达式将后缀和过滤步骤的各个部分组合成一行:

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”结尾的任何内容,因此只需确保使用列中未出现的后缀即可。

于 2020-06-25T06:53:45.227 回答
5

我是 Pandas 的新手,但我想实现同样的目标,自动避免使用 _x 或 _y 的列名并删除重复数据。我终于通过使用这个答案来自Stackoverflow的这个答案做到了

销售.csv

    城市;州;单位
    门多西诺;CA;1
    丹佛;CO;4
    奥斯汀;德克萨斯州;2

收入.csv

    branch_id;city;revenue;state_id
    10;奥斯汀;100;德克萨斯州
    20;奥斯汀;83;德克萨斯州
    30;奥斯汀;4;德克萨斯州
    47;奥斯汀;200;德克萨斯州
    20;丹佛;83;CO
    30;斯普林菲尔德;4;我

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

执行合并命令时,我用_x空字符串替换后缀,我可以删除以_y

输出.csv

    id;city;state;units;branch_id;revenue;state_id
    0;丹佛;一氧化碳;4;20;83;一氧化碳
    1;奥斯汀;TX;2;10;100;TX
    2;奥斯汀;TX;2;20;83;TX
    3;奥斯汀;TX;2;30;4;TX
    4;奥斯汀;TX;2;47;200;TX
于 2017-11-22T15:56:23.623 回答
1

这有点解决问题,但我编写了一个基本上处理额外列的函数:

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

似乎与我的合并工作得很好!

于 2020-11-20T15:55:50.820 回答
0

您不能先将任一 df 中的列子集化吗?

[i for i in df.columns if i not in df2.columns]
dfNew = merge(df **[i for i in df.columns if i not in df2.columns]**, df2, left_index=True, right_index=True, how='outer')
于 2021-01-08T16:20:44.330 回答
0

当您要避免的列数低于您要保留的列数时......您可以使用这种过滤:

df.loc[:, ~df.columns.isin(['currency', 'adj_date'])]

这将过滤数据框中的所有列,除了 'currency' 和 'adj_date' 列,你必须像这样编写合并:

    dfNew = merge(df, 
                  df2.loc[:, ~df.columns.isin(['currency', 'adj_date'])], 
                  left_index=True,
                  right_index=True,
                  how='outer')

注意“~”,它的意思是“不是”。

于 2021-05-28T18:09:19.903 回答
0

您可以在要合并的键中包含重复的列,以确保结果中只出现一个副本。

# Generate some dummy data.
shared = pd.DataFrame({'key': range(5), 'name': list('abcde')})
a = shared.copy()
a['value_a'] = np.random.normal(0, 1, 5)
b = shared.copy()
b['value_b'] = np.random.normal(0, 1, 5)

# Standard merge.
merged = pd.merge(a, b, on='key')
print(merged.columns)  # Index(['key', 'name_x', 'value_a', 'name_y', 'value_b'], dtype='object')

# Merge with both keys.
merged = pd.merge(a, b, on=['key', 'name'])
print(merged.columns)  # Index(['key', 'name', 'value_a', 'value_b'], dtype='object')

此方法还确保出现在两个数据框中的列中的值是一致的(例如,两个列中的货币相同)。如果不是,则相应的行将被删除(如果how = 'inner')或出现缺失值(如果how = 'outer')。

于 2021-07-28T14:09:00.950 回答