合并与连接
合并与连接
import pandas as pdconcat: 合并多个 DataFrame 和 Series
垂直合并
left = pd.DataFrame({'Name': ['Sam', 'Emma'], 'Age': [14, 15]})
left| Name | Age | |
|---|---|---|
| 0 | Sam | 14 |
| 1 | Emma | 15 |
right = pd.DataFrame({'Name': ['Karen', 'Rahul'], 'Age': [10, 13]})
right| Name | Age | |
|---|---|---|
| 0 | Karen | 10 |
| 1 | Rahul | 13 |
垂直合并即按列合并,一般需要 DataFrame 的 column 完全一致。
pd.concat([left, right])| 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| Name | Age | |
|---|---|---|
| 0 | Sam | 14 |
| 1 | Emma | 15 |
right = pd.DataFrame({'Math': ['B', 'A+'], 'Science': ['A', 'B+']})
right| Math | Science | |
|---|---|---|
| 0 | B | A |
| 1 | A+ | B+ |
设置 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")
s0 X0
1 X1
2 X2
3 X3
Name: X, dtype: object
df = pd.DataFrame({'Name': ['Sam', 'Emma'], 'Age': [14, 15]})
df| Name | Age | |
|---|---|---|
| 0 | Sam | 14 |
| 1 | Emma | 15 |
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| A | B | |
|---|---|---|
| K0 | A0 | B0 |
| K1 | A1 | B1 |
| K2 | A2 | B2 |
right = pd.DataFrame(
{"C": ["C0", "C2", "C3"], "D": ["D0", "D2", "D3"]}, index=["K0", "K2", "K3"]
)
right| C | D | |
|---|---|---|
| K0 | C0 | D0 |
| K2 | C2 | D2 |
| K3 | C3 | D3 |
left.join(right)| A | B | C | D | |
|---|---|---|---|---|
| K0 | A0 | B0 | C0 | D0 |
| K1 | A1 | B1 | NaN | NaN |
| K2 | A2 | B2 | C2 | D2 |
right.join(left)| 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')| A | B | C | D | |
|---|---|---|---|---|
| K0 | A0 | B0 | C0 | D0 |
| K2 | A2 | B2 | C2 | D2 |