Panda 合并-如何避免重复列

我正在尝试合并两个数据帧。每个数据帧有两个索引级别(日期、尖端)。在这些列中,有些列在两者之间匹配(例如,货币、日期)。

什么是最好的方式合并这些索引,但不采取两个副本的货币和日期。

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

谢谢! ...

232487 次浏览

您可以计算出仅在一个 DataFrame 中的列,并使用该框架在合并中选择列的子集。

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

然后执行 merge (注意,这是一个 index 对象,但它有一个方便的 tolist()方法)。

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

这将避免合并中的任何列冲突。

我在 .merge()中使用 suffixes选项:

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


dfNew.drop(dfNew.filter(regex='_y$').columns, axis=1, inplace=True)

谢谢@ijoseph

我刚刚接触过熊猫,但是我想做同样的事情,自动避免使用 _ x 或 _ y 列名,并删除重复的数据。我最终使用了这个来自 Stackoverflow 的 abc0和这个

Sales.csv

city;state;units
Mendocino;CA;1
Denver;CO;4
Austin;TX;2

收入 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

合并 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;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

基于@rprog 的回答,您可以使用负 regex 将后缀 & 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”结尾的任何内容,所以只要确保使用一个没有出现在列中的后缀即可。

这个问题有点复杂,但是我已经编写了一个函数,它主要处理额外的列:

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

看来我的合并进行得很顺利!

你就不能先从 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')

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

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

这将过滤数据框中除了“ currency”和“ adj _ date”列之外的所有列,您必须编写如下的 merge:

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

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

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

# 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')。

您可以删除联接之后不需要的重复 y列:

# Join df and df2
dfNew = merge(df, df2, left_index=True, right_index=True, how='inner')

输出: currency_x | adj_date_x | data_col1 | ... | currency_y | adj_date_y | data_col2

# Remove the y columns by selecting the columns you want to keep
dfNew = dfNew.loc[:, ("currency_x", "adj_date_x", "data_col1", "data_col2")]

输出: currency_x | adj_date_x | data_col1 | data_col2

如果你是在任意列上合并,并且不想保留 右键,这个方法可以解决这个问题:

mrg = pd.merge(a, b, how="left", left_on="A_KEY", right_on="B_KEY")
mrg.drop(columns=b.columns.difference(cols_to_use))