我正在尝试两个数据帧之间的合并。每个数据框都有两个索引级别(日期,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
谢谢! ...
答案 0 :(得分:90)
您可以计算仅在一个数据框中的列,并使用它来选择合并中的列子集
cols_to_use = df2.columns - df.columns
然后使用它执行合并(注意这是一个索引对象,但它有一个方便的tolist()
方法)
dfNew = merge(df, df2[cols_to_use], left_index=True, right_index=True, how='outer')
这将避免合并中的任何列发生冲突
对于0.15及更高版本,新的首选语法为:
cols_to_use = df2.columns.difference(df.columns)
感谢@odedbd
答案 1 :(得分:44)
我使用.merge()
中的suffixes
选项:
dfNew = df.merge(df2, left_index=True, right_index=True,
how='outer', suffixes=('', '_y'))
然后,您可以根据标志“_y”过滤列,即删除它们。
答案 2 :(得分:5)
基于@rprog的答案,您可以使用负的正则表达式将后缀和filter步骤的各个部分组合为一行:
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”结尾的内容,因此请确保使用未在各列之间出现的后缀。
答案 3 :(得分:3)
我是Pandas的新手,但我想实现同样的目的,自动避免使用_x或_y删除列名并删除重复数据。我最终使用了这个answer和来自Stackoverflow的这个one
sales.csv
city;state;units Mendocino;CA;1 Denver;CO;4 Austin;TX;2
revenue.csv
branch_id;city;revenue;state_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 进口熊猫
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;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 :(得分: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
似乎可以很好地处理我的合并!
答案 5 :(得分: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')
答案 6 :(得分: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')
注意“~”,意思是“不是”。
答案 7 :(得分: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'
)。