两个或多个数据帧的完全外连接

时间:2018-04-12 03:06:39

标签: python python-3.x pandas

鉴于以下三个Pandas数据帧,我需要将它们合并为类似于SQL全外连接。请注意,密钥是多索引type_Nid_NN = 1,2,3:

import pandas as pd

raw_data = {
        'type_1': [0, 1, 1,1],
        'id_1': ['3', '4', '5','5'],
        'name_1': ['Alex', 'Amy', 'Allen', 'Jane']}
df_a = pd.DataFrame(raw_data, columns = ['type_1', 'id_1', 'name_1' ])

raw_datab = {
        'type_2': [1, 1, 1, 0],
        'id_2': ['4', '5', '5', '7'],
        'name_2': ['Bill', 'Brian', 'Joe', 'Bryce']}
df_b = pd.DataFrame(raw_datab, columns = ['type_2', 'id_2', 'name_2'])

raw_datac = {
        'type_3': [1, 0],
        'id_3': ['4', '7'],
        'name_3': ['School', 'White']}
df_c = pd.DataFrame(raw_datac, columns = ['type_3', 'id_3', 'name_3'])

预期结果应为:

type_1   id_1   name_1   type_2   id_2   name_2   type_3   id_3   name_3
0        3      Alex     NaN      NaN    NaN      NaN      NaN    NaN
1        4      Amy      1        4      Bill     1        4      School
1        5      Allen    1        5      Brian    NaN      NaN    NaN
1        5      Allen    1        5      Joe      NaN      NaN    NaN
1        5      Jane     1        5      Brian    NaN      NaN    NaN
1        5      Jane     1        5      Joe      NaN      NaN    NaN
NaN      NaN    NaN      0        7      Bryce    0        7      White

如何在熊猫中实现这一目标?

3 个答案:

答案 0 :(得分:3)

您可以使用2个连续合并,首先是df_adf_b,然后是df_c

In [49]: df_temp = df_a.merge(df_b, how='outer', left_on=['type_1', 'id_1'], right_on=['type_2', 'id_2'])

In [50]: df_temp.merge(df_c, how='outer', left_on=['type_2', 'id_2'], right_on=['type_3', 'id_3'])
Out[50]:
   type_1 id_1 name_1 type_2 id_2 name_2  type_3 id_3  name_3
0     0.0    3   Alex    NaN  NaN    NaN     NaN  NaN     NaN
1     1.0    4    Amy      1    4   Bill     1.0    4  School
2     1.0    5  Allen      1    5  Brian     NaN  NaN     NaN
3     1.0    5  Allen      1    5    Joe     NaN  NaN     NaN
4     1.0    5   Jane      1    5  Brian     NaN  NaN     NaN
5     1.0    5   Jane      1    5    Joe     NaN  NaN     NaN
6     NaN  NaN    NaN      0    7  Bryce     0.0    7   White

答案 1 :(得分:3)

我建议你让生活变得不那么复杂,并且你想要合并的东西没有不同的名字。

da = df_a.set_index(['type_1', 'id_1']).rename_axis(['type', 'id'])
db = df_b.set_index(['type_2', 'id_2']).rename_axis(['type', 'id'])
dc = df_c.set_index(['type_3', 'id_3']).rename_axis(['type', 'id'])

da.join(db, how='outer').join(dc, how='outer')

        name_1 name_2  name_3
type id                      
0    3    Alex    NaN     NaN
     7     NaN  Bryce   White
1    4     Amy   Bill  School
     5   Allen  Brian     NaN
     5   Allen    Joe     NaN
     5    Jane  Brian     NaN
     5    Jane    Joe     NaN

这是获取其他专栏的令人讨厌的方法

from cytoolz.dicttoolz import merge

i = pd.DataFrame(d.index.values.tolist(), d.index, d.index.names)
d = d.assign(**merge(
    i.mask(d[f'name_{j}'].isna()).add_suffix(f'_{j}').to_dict('l')
    for j in [1, 2, 3]
))

d[sorted(d.columns, key=lambda x: x.split('_')[::-1])]

        id_1 name_1  type_1 id_2 name_2  type_2 id_3  name_3  type_3
type id                                                             
0    3     3   Alex     0.0  NaN    NaN     NaN  NaN     NaN     NaN
     7   NaN    NaN     NaN    7  Bryce     0.0    7   White     0.0
1    4     4    Amy     1.0    4   Bill     1.0    4  School     1.0
     5     5  Allen     1.0    5  Brian     1.0  NaN     NaN     NaN
     5     5  Allen     1.0    5    Joe     1.0  NaN     NaN     NaN
     5     5   Jane     1.0    5  Brian     1.0  NaN     NaN     NaN
     5     5   Jane     1.0    5    Joe     1.0  NaN     NaN     NaN

答案 2 :(得分:2)

让我们尝试为此创建一个新密钥,我在这里使用reduce

import functools
dfs=[df_a,df_b,df_c]
dfs=[x.assign(key=list(zip(x.iloc[:,0],x.iloc[:,1]))) for x in dfs]
merged_df = functools.reduce(lambda left,right: pd.merge(left,right,on='key',how='outer'), dfs)
merged_df.drop('key',1) 
Out[110]: 
   type_1 id_1 name_1  type_2 id_2 name_2  type_3 id_3  name_3
0     0.0    3   Alex     NaN  NaN    NaN     NaN  NaN     NaN
1     1.0    4    Amy     1.0    4   Bill     1.0    4  School
2     1.0    5  Allen     1.0    5  Brian     NaN  NaN     NaN
3     1.0    5  Allen     1.0    5    Joe     NaN  NaN     NaN
4     1.0    5   Jane     1.0    5  Brian     NaN  NaN     NaN
5     1.0    5   Jane     1.0    5    Joe     NaN  NaN     NaN
6     NaN  NaN    NaN     0.0    7  Bryce     0.0    7   White