concat: 合并多个 DataFrame 和 Series
垂直合并
left = pd.DataFrame({'Name': ['Sam', 'Emma'], 'Age': [14, 15]})
left
right = pd.DataFrame({'Name': ['Karen', 'Rahul'], 'Age': [10, 13]})
right
垂直合并即按列合并,一般需要 DataFrame 的 column 完全一致。
| Name | Age |
---|
0 | Sam | 14 |
---|
1 | Emma | 15 |
---|
0 | Karen | 10 |
---|
1 | Rahul | 13 |
---|
不过,上面的结果仍然保留了这些 DataFrame 原来的索引。我们可以重置索引:
pd.concat([left, right]).reset_index(drop=True)
| Name | Age |
---|
0 | Sam | 14 |
---|
1 | Emma | 15 |
---|
2 | Karen | 10 |
---|
3 | Rahul | 13 |
---|
水平合并
left = pd.DataFrame({'Name': ['Sam', 'Emma'], 'Age': [14, 15]})
left
right = pd.DataFrame({'Math': ['B', 'A+'], 'Science': ['A', 'B+']})
right
设置 axis=1
即可实现水平合并,即按行合并,一般要求 DataFrame 的 index 完全一致。
pd.concat([left, right], axis=1)
| Name | Age | Math | Science |
---|
0 | Sam | 14 | B | A |
---|
1 | Emma | 15 | A+ | B+ |
---|
设置合并模式
如果 index 或者 column 不一致,则可以设置连接 join
的方式。
outer
:类似于关系代数的外连接运算,没有的内容补 NaN 值。该选项为默认值。inner
:类似于关系代数的自然连接运算,先求笛卡尔积中对应相等的元组,再去掉其中重复的属性值。
注:与关系代数不同的是,pandas 对 DataFrame 的连接可以在 index 和 column 上都可以进行。
left = pd.DataFrame(
{
"A": ["A0", "A1", "A2", "A3"],
"B": ["B0", "B1", "B2", "B3"],
"C": ["C0", "C1", "C2", "C3"],
"D": ["D0", "D1", "D2", "D3"],
},
index=[0, 1, 2, 3],
)
left
| A | B | C | D |
---|
0 | A0 | B0 | C0 | D0 |
---|
1 | A1 | B1 | C1 | D1 |
---|
2 | A2 | B2 | C2 | D2 |
---|
3 | A3 | B3 | C3 | D3 |
---|
right = pd.DataFrame(
{
"B": ["B2", "B3", "B6", "B7"],
"D": ["D2", "D3", "D6", "D7"],
"F": ["F2", "F3", "F6", "F7"],
},
index=[2, 3, 6, 7],
)
right
| B | D | F |
---|
2 | B2 | D2 | F2 |
---|
3 | B3 | D3 | F3 |
---|
6 | B6 | D6 | F6 |
---|
7 | B7 | D7 | F7 |
---|
pd.concat([left, right], axis=1, join='outer')
| A | B | C | D | B | D | F |
---|
0 | A0 | B0 | C0 | D0 | NaN | NaN | NaN |
---|
1 | A1 | B1 | C1 | D1 | NaN | NaN | NaN |
---|
2 | A2 | B2 | C2 | D2 | B2 | D2 | F2 |
---|
3 | A3 | B3 | C3 | D3 | B3 | D3 | F3 |
---|
6 | NaN | NaN | NaN | NaN | B6 | D6 | F6 |
---|
7 | NaN | NaN | NaN | NaN | B7 | D7 | F7 |
---|
pd.concat([left, right], axis=1, join='inner')
| A | B | C | D | B | D | F |
---|
2 | A2 | B2 | C2 | D2 | B2 | D2 | F2 |
---|
3 | A3 | B3 | C3 | D3 | B3 | D3 | F3 |
---|
pd.concat([left, right], axis=0, join='outer')
| A | B | C | D | F |
---|
0 | A0 | B0 | C0 | D0 | NaN |
---|
1 | A1 | B1 | C1 | D1 | NaN |
---|
2 | A2 | B2 | C2 | D2 | NaN |
---|
3 | A3 | B3 | C3 | D3 | NaN |
---|
2 | NaN | B2 | NaN | D2 | F2 |
---|
3 | NaN | B3 | NaN | D3 | F3 |
---|
6 | NaN | B6 | NaN | D6 | F6 |
---|
7 | NaN | B7 | NaN | D7 | F7 |
---|
pd.concat([left, right], axis=0, join='inner')
| B | D |
---|
0 | B0 | D0 |
---|
1 | B1 | D1 |
---|
2 | B2 | D2 |
---|
3 | B3 | D3 |
---|
2 | B2 | D2 |
---|
3 | B3 | D3 |
---|
6 | B6 | D6 |
---|
7 | B7 | D7 |
---|
可以设置忽略 index,index 将按照顺序递增。这样就和关系代数中的连接运算完全一致了。
pd.concat([left, right], ignore_index=True)
| A | B | C | D | F |
---|
0 | A0 | B0 | C0 | D0 | NaN |
---|
1 | A1 | B1 | C1 | D1 | NaN |
---|
2 | A2 | B2 | C2 | D2 | NaN |
---|
3 | A3 | B3 | C3 | D3 | NaN |
---|
4 | NaN | B2 | NaN | D2 | F2 |
---|
5 | NaN | B3 | NaN | D3 | F3 |
---|
6 | NaN | B6 | NaN | D6 | F6 |
---|
7 | NaN | B7 | NaN | D7 | F7 |
---|
DataFrame 和 Series 可以直接合并
s = pd.Series(["X0", "X1", "X2", "X3"], name="X")
s
0 X0
1 X1
2 X2
3 X3
Name: X, dtype: object
df = pd.DataFrame({'Name': ['Sam', 'Emma'], 'Age': [14, 15]})
df
pd.concat([df, s], axis=1)
| Name | Age | X |
---|
0 | Sam | 14.0 | X0 |
---|
1 | Emma | 15.0 | X1 |
---|
2 | NaN | NaN | X2 |
---|
3 | NaN | NaN | X3 |
---|
merge: 功能更强大的数据库连接操作
left = pd.DataFrame(
{
"key": ["K0", "K1", "K2", "K3"],
"A": ["A0", "A1", "A2", "A3"],
"B": ["B0", "B1", "B2", "B3"],
}
)
left
| key | A | B |
---|
0 | K0 | A0 | B0 |
---|
1 | K1 | A1 | B1 |
---|
2 | K2 | A2 | B2 |
---|
3 | K3 | A3 | B3 |
---|
right = pd.DataFrame(
{
"key": ["K0", "K1", "K2", "K3"],
"C": ["C0", "C1", "C2", "C3"],
"D": ["D0", "D1", "D2", "D3"],
}
)
right
| key | C | D |
---|
0 | K0 | C0 | D0 |
---|
1 | K1 | C1 | D1 |
---|
2 | K2 | C2 | D2 |
---|
3 | K3 | C3 | D3 |
---|
pd.merge(left, right, on='key')
| key | A | B | C | D |
---|
0 | K0 | A0 | B0 | C0 | D0 |
---|
1 | K1 | A1 | B1 | C1 | D1 |
---|
2 | K2 | A2 | B2 | C2 | D2 |
---|
3 | K3 | A3 | B3 | C3 | D3 |
---|
连接方式
merge
可以实现关系代数当中的除自然连接和外连接更强大的连接操作。因此,它的 how
参数支持如下五种运算:
outer
:外连接inner
:自然连接left
:左连接right
:右连接cross
:笛卡尔积
这种运算要求左表和右表有交叉点 intersection
存在,因此连接方式默认值为 inner
。
left = pd.DataFrame(
{
"key1": ["K0", "K0", "K1", "K2"],
"key2": ["K0", "K1", "K0", "K1"],
"A": ["A0", "A1", "A2", "A3"],
"B": ["B0", "B1", "B2", "B3"],
}
)
left
| key1 | key2 | A | B |
---|
0 | K0 | K0 | A0 | B0 |
---|
1 | K0 | K1 | A1 | B1 |
---|
2 | K1 | K0 | A2 | B2 |
---|
3 | K2 | K1 | A3 | B3 |
---|
right = pd.DataFrame(
{
"key1": ["K0", "K1", "K1", "K2"],
"key2": ["K0", "K0", "K0", "K0"],
"C": ["C0", "C1", "C2", "C3"],
"D": ["D0", "D1", "D2", "D3"],
}
)
right
| key1 | key2 | C | D |
---|
0 | K0 | K0 | C0 | D0 |
---|
1 | K1 | K0 | C1 | D1 |
---|
2 | K1 | K0 | C2 | D2 |
---|
3 | K2 | K0 | C3 | D3 |
---|
这个例子是由两个字段组成主码的表的连接操作。
pd.merge(left, right, on=["key1", "key2"])
| key1 | key2 | A | B | C | D |
---|
0 | K0 | K0 | A0 | B0 | C0 | D0 |
---|
1 | K1 | K0 | A2 | B2 | C1 | D1 |
---|
2 | K1 | K0 | A2 | B2 | C2 | D2 |
---|
自然连接
pd.merge(left, right, how="inner", on=["key1", "key2"])
| key1 | key2 | A | B | C | D |
---|
0 | K0 | K0 | A0 | B0 | C0 | D0 |
---|
1 | K1 | K0 | A2 | B2 | C1 | D1 |
---|
2 | K1 | K0 | A2 | B2 | C2 | D2 |
---|
外连接
pd.merge(left, right, how="outer", on=["key1", "key2"])
| key1 | key2 | A | B | C | D |
---|
0 | K0 | K0 | A0 | B0 | C0 | D0 |
---|
1 | K0 | K1 | A1 | B1 | NaN | NaN |
---|
2 | K1 | K0 | A2 | B2 | C1 | D1 |
---|
3 | K1 | K0 | A2 | B2 | C2 | D2 |
---|
4 | K2 | K0 | NaN | NaN | C3 | D3 |
---|
5 | K2 | K1 | A3 | B3 | NaN | NaN |
---|
左连接
pd.merge(left, right, how="left", on=["key1", "key2"])
| key1 | key2 | A | B | C | D |
---|
0 | K0 | K0 | A0 | B0 | C0 | D0 |
---|
1 | K0 | K1 | A1 | B1 | NaN | NaN |
---|
2 | K1 | K0 | A2 | B2 | C1 | D1 |
---|
3 | K1 | K0 | A2 | B2 | C2 | D2 |
---|
4 | K2 | K1 | A3 | B3 | NaN | NaN |
---|
右连接
pd.merge(left, right, how="right", on=["key1", "key2"])
| key1 | key2 | A | B | C | D |
---|
0 | K0 | K0 | A0 | B0 | C0 | D0 |
---|
1 | K1 | K0 | A2 | B2 | C1 | D1 |
---|
2 | K1 | K0 | A2 | B2 | C2 | D2 |
---|
3 | K2 | K0 | NaN | NaN | C3 | D3 |
---|
笛卡尔积
pd.merge(left, right, how="cross")
| key1_x | key2_x | A | B | key1_y | key2_y | C | D |
---|
0 | K0 | K0 | A0 | B0 | K0 | K0 | C0 | D0 |
---|
1 | K0 | K0 | A0 | B0 | K1 | K0 | C1 | D1 |
---|
2 | K0 | K0 | A0 | B0 | K1 | K0 | C2 | D2 |
---|
3 | K0 | K0 | A0 | B0 | K2 | K0 | C3 | D3 |
---|
4 | K0 | K1 | A1 | B1 | K0 | K0 | C0 | D0 |
---|
5 | K0 | K1 | A1 | B1 | K1 | K0 | C1 | D1 |
---|
6 | K0 | K1 | A1 | B1 | K1 | K0 | C2 | D2 |
---|
7 | K0 | K1 | A1 | B1 | K2 | K0 | C3 | D3 |
---|
8 | K1 | K0 | A2 | B2 | K0 | K0 | C0 | D0 |
---|
9 | K1 | K0 | A2 | B2 | K1 | K0 | C1 | D1 |
---|
10 | K1 | K0 | A2 | B2 | K1 | K0 | C2 | D2 |
---|
11 | K1 | K0 | A2 | B2 | K2 | K0 | C3 | D3 |
---|
12 | K2 | K1 | A3 | B3 | K0 | K0 | C0 | D0 |
---|
13 | K2 | K1 | A3 | B3 | K1 | K0 | C1 | D1 |
---|
14 | K2 | K1 | A3 | B3 | K1 | K0 | C2 | D2 |
---|
15 | K2 | K1 | A3 | B3 | K2 | K0 | C3 | D3 |
---|
join: DataFrame 对象的强大连接操作
left = pd.DataFrame(
{"A": ["A0", "A1", "A2"], "B": ["B0", "B1", "B2"]}, index=["K0", "K1", "K2"]
)
left
right = pd.DataFrame(
{"C": ["C0", "C2", "C3"], "D": ["D0", "D2", "D3"]}, index=["K0", "K2", "K3"]
)
right
| A | B | C | D |
---|
K0 | A0 | B0 | C0 | D0 |
---|
K1 | A1 | B1 | NaN | NaN |
---|
K2 | A2 | B2 | C2 | D2 |
---|
| C | D | A | B |
---|
K0 | C0 | D0 | A0 | B0 |
---|
K2 | C2 | D2 | A2 | B2 |
---|
K3 | C3 | D3 | NaN | NaN |
---|
DataFrame 的 join
默认值为 left
,可以设置为除笛卡尔积外的连接方式。
left.join(right, how='inner')