Pandas Tips: 使用merge实现关系型合并

数据分析
Author

Tom

Published

August 3, 2023

Pandas 中提供了 merge 函数实现关系型合并。

df1.merge(df2, how='inner', on=None, left_on=None, right_on=None, 
         left_index=False, right_index=False, sort=False, 
         suffixes=('_x', '_y'), copy=None, indicator=False, validate=None)

主要参数含义:

import numpy as np
import pandas as pd
# create some toy data
df1 = pd.DataFrame({'Date': pd.date_range('2023-08-01', periods=5),
                    'Company': ['A', 'B', 'C', 'D', 'E'],
                    'Close': [20, 23, 21, 22, 20]})
df2 = pd.DataFrame({'Date': pd.date_range('2023-08-03', periods=5),
                    'Firm': ['C', 'D', 'E', 'F', 'G'],
                    'Volume': [100, 101, 120, 110, 105]})
df1
Date Company Close
0 2023-08-01 A 20
1 2023-08-02 B 23
2 2023-08-03 C 21
3 2023-08-04 D 22
4 2023-08-05 E 20
df2
Date Firm Volume
0 2023-08-03 C 100
1 2023-08-04 D 101
2 2023-08-05 E 120
3 2023-08-06 F 110
4 2023-08-07 G 105

merge 默认使用内连接(inner),如果不指定合并的键,默认使用两张表中共同的列作合并,df1 和 df2 共同的列是 date,合并后显示共有的 date:

df1.merge(df2)
Date Company Close Firm Volume
0 2023-08-03 C 21 C 100
1 2023-08-04 D 22 D 101
2 2023-08-05 E 20 E 120

使用 left_onright_on 参数可以指定两张表做合并的键,下面指定使用 df1 中的 Company 和 df2 中的 Firm 来做合并:

df1.merge(df2, 
          left_on='Company', 
          right_on='Firm')
Date_x Company Close Date_y Firm Volume
0 2023-08-03 C 21 2023-08-03 C 100
1 2023-08-04 D 22 2023-08-04 D 101
2 2023-08-05 E 20 2023-08-05 E 120

由于 df1 和 df2 中都有 Date 这一列,为了加以区分,Pandas 自动给两张表中的 Date 加了后缀,我们可以使用 suffixes 参数来自定义后缀:

df1.merge(df2,
          left_on='Company', 
          right_on='Firm',
          suffixes=['_1', '_2'])
Date_1 Company Close Date_2 Firm Volume
0 2023-08-03 C 21 2023-08-03 C 100
1 2023-08-04 D 22 2023-08-04 D 101
2 2023-08-05 E 20 2023-08-05 E 120

但是既然两张表里都有 Date 这一列,最好的方式是使用多键合并:

df1.merge(df2, 
          left_on=['Date', 'Company'], 
          right_on=['Date','Firm'])
Date Company Close Firm Volume
0 2023-08-03 C 21 C 100
1 2023-08-04 D 22 D 101
2 2023-08-05 E 20 E 120

使用 how 参数可以指定合并的方式,left 表示左连接,合并后显示 df1 的所有行,df2 中没有 2023-08-01 和 2023-08-02 两天,则对应的 Firm 和 Volume 显示为空值。

df1.merge(df2, how='left')
Date Company Close Firm Volume
0 2023-08-01 A 20 NaN NaN
1 2023-08-02 B 23 NaN NaN
2 2023-08-03 C 21 C 100.0
3 2023-08-04 D 22 D 101.0
4 2023-08-05 E 20 E 120.0

right 表示右连接,合并后显示 df2 的所有行:

df1.merge(df2, how='right')
Date Company Close Firm Volume
0 2023-08-03 C 21.0 C 100
1 2023-08-04 D 22.0 D 101
2 2023-08-05 E 20.0 E 120
3 2023-08-06 NaN NaN F 110
4 2023-08-07 NaN NaN G 105

outer 表示外连接,合并后显示 df1 和 df2 的所有行:

df1.merge(df2, how='outer')
Date Company Close Firm Volume
0 2023-08-01 A 20.0 NaN NaN
1 2023-08-02 B 23.0 NaN NaN
2 2023-08-03 C 21.0 C 100.0
3 2023-08-04 D 22.0 D 101.0
4 2023-08-05 E 20.0 E 120.0
5 2023-08-06 NaN NaN F 110.0
6 2023-08-07 NaN NaN G 105.0

cross 表示交叉合并,合并后显示 df1 和 df2 的笛卡尔积:

df1.merge(df2, how='cross')
Date_x Company Close Date_y Firm Volume
0 2023-08-01 A 20 2023-08-03 C 100
1 2023-08-01 A 20 2023-08-04 D 101
2 2023-08-01 A 20 2023-08-05 E 120
3 2023-08-01 A 20 2023-08-06 F 110
4 2023-08-01 A 20 2023-08-07 G 105
5 2023-08-02 B 23 2023-08-03 C 100
6 2023-08-02 B 23 2023-08-04 D 101
7 2023-08-02 B 23 2023-08-05 E 120
8 2023-08-02 B 23 2023-08-06 F 110
9 2023-08-02 B 23 2023-08-07 G 105
10 2023-08-03 C 21 2023-08-03 C 100
11 2023-08-03 C 21 2023-08-04 D 101
12 2023-08-03 C 21 2023-08-05 E 120
13 2023-08-03 C 21 2023-08-06 F 110
14 2023-08-03 C 21 2023-08-07 G 105
15 2023-08-04 D 22 2023-08-03 C 100
16 2023-08-04 D 22 2023-08-04 D 101
17 2023-08-04 D 22 2023-08-05 E 120
18 2023-08-04 D 22 2023-08-06 F 110
19 2023-08-04 D 22 2023-08-07 G 105
20 2023-08-05 E 20 2023-08-03 C 100
21 2023-08-05 E 20 2023-08-04 D 101
22 2023-08-05 E 20 2023-08-05 E 120
23 2023-08-05 E 20 2023-08-06 F 110
24 2023-08-05 E 20 2023-08-07 G 105