文章目录
- `concat()`
- 连接轴的连接逻辑
- 忽略连接轴上的索引
- 将 [`Series`](https://pandas.pydata.org/docs/reference/api/pandas.Series.html#pandas.Series) 和 [`DataFrame`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html#pandas.DataFrame) 连接在一起
- 结果的 `keys`
- 将行附加到 [`DataFrame`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html#pandas.DataFrame)
- `merge()`
- `merge()`
- `merge_ordered()`
- `merge_asof()`
- `compare()`
- Pandas 2 使用指南导读
pandas 提供了多种方法来合并和比较
Series
或
DataFrame
。
concat()
:沿着共享的索引或列合并多个Series
或DataFrame
对象DataFrame.join()
:沿着列合并多个DataFrame
对象DataFrame.combine_first()
:将缺失值用同一位置上的非缺失值更新merge()
:使用 SQL 风格的连接方式合并两个Series
或DataFrame
对象merge_ordered()
:沿着有序轴合并两个Series
或DataFrame
对象merge_asof()
:通过近似匹配键合并两个Series
或DataFrame
对象Series.compare()
和DataFrame.compare()
:显示两个Series
或DataFrame
对象之间的差异值
concat()
concat()
函数沿着轴将任意数量的 Series
或 DataFrame
对象串联在一起,并在其他轴上执行可选的集合逻辑(并集或交集)。与 numpy.concatenate
类似,concat()
接受一个同类型对象的列表或字典,并将它们串联在一起。
df1 = 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],
)
df2 = pd.DataFrame(
{
"A": ["A4", "A5", "A6", "A7"],
"B": ["B4", "B5", "B6", "B7"],
"C": ["C4", "C5", "C6", "C7"],
"D": ["D4", "D5", "D6", "D7"],
},
index=[4, 5, 6, 7],
)
df3 = pd.DataFrame(
{
"A": ["A8", "A9", "A10", "A11"],
"B": ["B8", "B9", "B10", "B11"],
"C": ["C8", "C9", "C10", "C11"],
"D": ["D8", "D9", "D10", "D11"],
},
index=[8, 9, 10, 11],
)
frames = [df1, df2, df3]
result = pd.concat(frames)
result
Out[6]:
A B C D
0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11
注意
concat()
会完全复制数据,并且反复使用 concat()
可能会创建不必要的副本。在使用 concat()
之前,将所有的 DataFrame
或 Series
对象收集到一个列表中。
frames = [process_your_file(f) for f in files]
result = pd.concat(frames)
注意
当串联具有命名轴的 DataFrame
时,pandas 会尽可能保留这些索引/列名。如果所有输入共享一个公共名称,该名称将分配给结果。当输入名称不完全一致时,结果将没有名称。对于 MultiIndex
也是如此,但逻辑是在逐级基础上分别应用的。
连接轴的连接逻辑
join
关键字指定如何处理第一个DataFrame
中不存在的轴值。
join='outer'
取所有轴值的并集
df4 = pd.DataFrame(
{
"B": ["B2", "B3", "B6", "B7"],
"D": ["D2", "D3", "D6", "D7"],
"F": ["F2", "F3", "F6", "F7"],
},
index=[2, 3, 6, 7],
)
result = pd.concat([df1, df4], axis=1)
result
Out[9]:
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
join='inner'
取所有轴值的交集
result = pd.concat([df1, df4], axis=1, join="inner")
result
Out[11]:
A B C D B D F
2 A2 B2 C2 D2 B2 D2 F2
3 A3 B3 C3 D3 B3 D3 F3
为了使用原始DataFrame
的精确索引执行有效的“左连接”,可以重新索引结果。
result = pd.concat([df1, df4], axis=1).reindex(df1.index)
result
Out[13]:
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
忽略连接轴上的索引
对于没有有意义索引的 DataFrame
对象,ignore_index
可以忽略重叠的索引。
result = pd.concat([df1, df4], ignore_index=True, sort=False)
result
Out[15]:
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
将 Series
和 DataFrame
连接在一起
可以将混合的 Series
和 DataFrame
对象连接在一起。Series
将被转换为具有 Series
名称作为列名的 DataFrame
。
s1 = pd.Series(["X0", "X1", "X2", "X3"], name="X")
result = pd.concat([df1, s1], axis=1)
result
Out[18]:
A B C D X
0 A0 B0 C0 D0 X0
1 A1 B1 C1 D1 X1
2 A2 B2 C2 D2 X2
3 A3 B3 C3 D3 X3
无名称的 Series
将按顺序编号。
s2 = pd.Series(["_0", "_1", "_2", "_3"])
result = pd.concat([df1, s2, s2, s2], axis=1)
result
Out[21]:
A B C D 0 1 2
0 A0 B0 C0 D0 _0 _0 _0
1 A1 B1 C1 D1 _1 _1 _1
2 A2 B2 C2 D2 _2 _2 _2
3 A3 B3 C3 D3 _3 _3 _3
ignore_index=True
会丢弃所有的名称引用。
result = pd.concat([df1, s1], axis=1, ignore_index=True)
result
Out[23]:
0 1 2 3 4
0 A0 B0 C0 D0 X0
1 A1 B1 C1 D1 X1
2 A2 B2 C2 D2 X2
3 A3 B3 C3 D3 X3
结果的 keys
keys
参数会在结果的索引或列上添加另一个轴级别(创建一个 MultiIndex
),将特定的键与每个原始 DataFrame
关联起来。
result = pd.concat(frames, keys=["x", "y", "z"])
result
Out[25]:
A B C D
x 0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
y 4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
z 8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11
result.loc["y"]
Out[26]:
A B C D
4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
当创建一个基于现有 Series
的新 DataFrame
时,keys
参数可以覆盖列名。
s3 = pd.Series([0, 1, 2, 3], name="foo")
s4 = pd.Series([0, 1, 2, 3])
s5 = pd.Series([0, 1, 4, 5])
pd.concat([s3, s4, s5], axis=1)
Out[30]:
foo 0 1
0 0 0 0
1 1 1 1
2 2 2 4
3 3 3 5
pd.concat([s3, s4, s5], axis=1, keys=["red", "blue", "yellow"])
Out[31]:
red blue yellow
0 0 0 0
1 1 1 1
2 2 2 4
3 3 3 5
你还可以将一个字典传递给 concat()
,在这种情况下,字典的键将用于 keys
参数,除非指定了其他的 keys
参数:
pieces = {"x": df1, "y": df2, "z": df3}
result = pd.concat(pieces)
result
Out[34]:
A B C D
x 0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
y 4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
z 8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11
result = pd.concat(pieces, keys=["z", "y"])
result
Out[36]:
A B C D
z 8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11
y 4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
MultiIndex
的级别是根据传递的键和 DataFrame
片段的索引构建的:
result.index.levels
Out[37]: FrozenList([['z', 'y'], [4, 5, 6, 7, 8, 9, 10, 11]])
levels
参数允许指定与 keys
关联的结果级别:
result = pd.concat(
pieces, keys=["x", "y", "z"], levels=[["z", "y", "x", "w"]], names=["group_key"]
)
result
Out[39]:
A B C D
group_key
x 0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
y 4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
z 8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11
result.index.levels
Out[40]: FrozenList([['z', 'y', 'x', 'w'], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]])
将行附加到 DataFrame
如果你有一个要作为单行附加到 DataFrame
的 Series
,你可以将该行转换为 DataFrame
,然后使用 concat()
。
s2 = pd.Series(["X0", "X1", "X2", "X3"], index=["A", "B", "C", "D"])
result = pd.concat([df1, s2.to_frame().T], ignore_index=True)
result
Out[43]:
A B C D
0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
4 X0 X1 X2 X3
merge()
merge()
执行类似于 SQL 的连接操作。熟悉 SQL 但是对 pandas 新手的用户可以参考 与 SQL 的比较。
连接类型
merge()
实现了常见的 SQL 风格的连接操作。
- one-to-one:在它们的索引上连接两个
DataFrame
对象,索引必须包含唯一值。 - many-to-one:将唯一索引连接到不同
DataFrame
中的一个或多个列。 - many-to-many:在列上连接列。
注意
当在列上连接列时,可能是多对多连接,传递的 DataFrame
对象上的任何索引都将被丢弃。
对于多对多连接,如果一个键组合在两个表中都出现了多次,那么 DataFrame
将具有相关数据的笛卡尔积。
left = pd.DataFrame(
{
"key": ["K0", "K1", "K2", "K3"],
"A": ["A0", "A1", "A2", "A3"],
"B": ["B0", "B1", "B2", "B3"],
}
)
right = pd.DataFrame(
{
"key": ["K0", "K1", "K2", "K3"],
"C": ["C0", "C1", "C2", "C3"],
"D": ["D0", "D1", "D2", "D3"],
}
)
result = pd.merge(left, right, on="key")
result
Out[47]:
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
how
参数用于指定哪些键包含在结果表中。如果一个键组合在左表或右表中都没有出现,那么连接表中的值将为 NA
。下面是 how
选项及其 SQL 等效名称的摘要:
连接方法 | SQL 连接名称 | 描述 |
---|---|---|
left | LEFT OUTERJOIN | 仅使用左侧表的键 |
right | RIGHT OUTERJOIN | 仅使用右侧表的键 |
outer | FULL OUTERJOIN | 使用左右两侧表的键的并集 |
inner | INNER JOIN | 使用左右两侧表的键的交集 |
cross | CROSS JOIN | 创建左右两侧表行的笛卡尔积 |
left = pd.DataFrame(
{
"key1": ["K0", "K0", "K1", "K2"],
"key2": ["K0", "K1", "K0", "K1"],
"A": ["A0", "A1", "A2", "A3"],
"B": ["B0", "B1", "B2", "B3"],
}
)
right = pd.DataFrame(
{
"key1": ["K0", "K1", "K1", "K2"],
"key2": ["K0", "K0", "K0", "K0"],
"C": ["C0", "C1", "C2", "C3"],
"D": ["D0", "D1", "D2", "D3"],
}
)
result = pd.merge(left, right, how="left", on=["key1", "key2"])
result
Out[51]:
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
result = pd.merge(left, right, how="right", on=["key1", "key2"])
result
Out[53]:
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
result = pd.merge(left, right, how="outer", on=["key1", "key2"])
result
Out[55]:
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
你还可以将一个字典传递给 concat()
,在这种情况下,字典的键将用于 keys
参数,除非指定了其他的 keys
参数:
pieces = {"x": df1, "y": df2, "z": df3}
result = pd.concat(pieces)
result
Out[34]:
A B C D
x 0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
y 4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
z 8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11
result = pd.concat(pieces, keys=["z", "y"])
result
Out[36]:
A B C D
z 8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11
y 4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
MultiIndex
创建的级别是根据传递的键和 DataFrame
片段的索引构建的:
result.index.levels
Out[37]: FrozenList([['z', 'y'], [4, 5, 6, 7, 8, 9, 10, 11]])
levels
参数允许指定与 keys
关联的结果级别:
result = pd.concat(
pieces, keys=["x", "y", "z"], levels=[["z", "y", "x", "w"]], names=["group_key"]
)
result
Out[39]:
A B C D
group_key
x 0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
y 4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
z 8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11
result.index.levels
Out[40]: FrozenList([['z', 'y', 'x', 'w'], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]])
将行附加到 DataFrame
如果你有一个要作为单行附加到 DataFrame
的 Series
,你可以将该行转换为 DataFrame
,然后使用 concat()
。
s2 = pd.Series(["X0", "X1", "X2", "X3"], index=["A", "B", "C", "D"])
result = pd.concat([df1, s2.to_frame().T], ignore_index=True)
result
Out[43]:
A B C D
0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
4 X0 X1 X2 X3
merge()
merge()
执行类似于 SQL 的连接操作。熟悉 SQL 但是对 pandas 新手的用户可以参考 与 SQL 的比较。
连接类型
merge()
实现了常见的 SQL 风格的连接操作。
- one-to-one:在它们的索引上连接两个
DataFrame
对象,索引必须包含唯一值。 - many-to-one:将唯一索引连接到不同
DataFrame
中的一个或多个列。 - many-to-many:在列上连接列。
注意
当在列上连接列时,可能是多对多连接,传递的 DataFrame
对象上的任何索引都将被丢弃。
对于多对多连接,如果一个键组合在两个表中都出现了多次,那么 DataFrame
将具有相关数据的笛卡尔积。
left = pd.DataFrame(
{
"key": ["K0", "K1", "K2", "K3"],
"A": ["A0", "A1", "A2", "A3"],
"B": ["B0", "B1", "B2", "B3"],
}
)
right = pd.DataFrame(
{
"key": ["K0", "K1", "K2", "K3"],
"C": ["C0", "C1", "C2", "C3"],
"D": ["D0", "D1", "D2", "D3"],
}
)
result = pd.merge(left, right, on="key")
result
Out[47]:
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
how
参数用于指定哪些键包含在结果表中。如果一个键组合在左表或右表中都没有出现,那么连接表中的值将为 NA
。下面是 how
选项及其 SQL 等效名称的摘要:
连接方法 | SQL 连接名称 | 描述 |
---|---|---|
left | LEFT OUTERJOIN | 仅使用左侧表的键 |
right | RIGHT OUTERJOIN | 仅使用右侧表的键 |
outer | FULL OUTERJOIN | 使用左右两侧表的键的并集 |
inner | INNER JOIN | 使用左右两侧表的键的交集 |
cross | CROSS JOIN | 创建左右两侧表行的笛卡尔积 |
left = pd.DataFrame(
{
"key1": ["K0", "K0", "K1", "K2"],
"key2": ["K0", "K1", "K0", "K1"],
"A": ["A0", "A1", "A2", "A3"],
"B": ["B0", "B1", "B2", "B3"],
}
)
right = pd.DataFrame(
{
"key1": ["K0", "K1", "K1", "K2"],
"key2": ["K0", "K0", "K0", "K0"],
"C": ["C0", "C1", "C2", "C3"],
"D": ["D0", "D1", "D2", "D3"],
}
)
result = pd.merge(left, right, how="left", on=["key1", "key2"])
result
Out[51]:
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
result = pd.merge(left, right, how="right", on=["key1", "key2"])
result
Out[53]:
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
result = pd.merge(left, right, how="outer", on=["key1", "key2"])
result
Out[55]:
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
你还可以将一个字典传递给 concat()
,在这种情况下,字典的键将用于 keys
参数,除非指定了其他的 keys
参数:
pieces = {"x": df1, "y": df2, "z": df3}
result = pd.concat(pieces)
result
Out[34]:
A B C D
x 0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
y 4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
z 8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11
result = pd.concat(pieces, keys=["z", "y"])
result
Out[36]:
A B C D
z 8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11
y 4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
MultiIndex
创建的级别是根据传递的键和 DataFrame
片段的索引构建的:
result.index.levels
Out[37]: FrozenList([['z', 'y'], [4, 5, 6, 7, 8, 9, 10, 11]])
levels
参数允许指定与 keys
关联的结果级别:
result = pd.concat(
pieces, keys=["x", "y", "z"], levels=[["z", "y", "x", "w"]], names=["group_key"]
)
result
Out[39]:
A B C D
group_key
x 0 A0 B0 C0 D0
1 A1 B1 C1 D1
2 A2 B2 C2 D2
3 A3 B3 C3 D3
y 4 A4 B4 C4 D4
5 A5 B5 C5 D5
6 A6 B6 C6 D6
7 A7 B7 C7 D7
z 8 A8 B8 C8 D8
9 A9 B9 C9 D9
10 A10 B10 C10 D10
11 A11 B11 C11 D11
result.index.levels
Out[40]: FrozenList([['z', 'y', 'x', 'w'], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]])
result = pd.merge(left, right, how="inner", on=["key1", "key2"])
result
Out[57]:
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()
函数将两个 DataFrame left
和 right
进行内连接。内连接是指只保留两个 DataFrame 中共有的键值对,其他的键值对将被丢弃。在这个例子中,我们使用了 key1
和 key2
作为连接的键。连接后的结果存储在变量 result
中。
result = pd.merge(left, right, how="cross")
result
Out[59]:
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
.. ... ... .. .. ... ... .. ..
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
[16 rows x 8 columns]
在这个例子中,我们使用了 pd.merge()
函数将两个 DataFrame left
和 right
进行交叉连接。交叉连接是指将两个 DataFrame 中的每一行都与另一个 DataFrame 中的每一行进行连接,生成的结果 DataFrame 的行数为两个 DataFrame 的行数的乘积。连接后的结果存储在变量 result
中。
df = pd.DataFrame({"Let": ["A", "B", "C"], "Num": [1, 2, 3]})
df
Out[61]:
Let Num
0 A 1
1 B 2
2 C 3
ser = pd.Series(
["a", "b", "c", "d", "e", "f"],
index=pd.MultiIndex.from_arrays(
[["A", "B", "C"] * 2, [1, 2, 3, 4, 5, 6]], names=["Let", "Num"]
),
)
ser
Out[63]:
Let Num
A 1 a
B 2 b
C 3 c
A 4 d
B 5 e
C 6 f
dtype: object
pd.merge(df, ser.reset_index(), on=["Let", "Num"])
Out[64]:
Let Num 0
0 A 1 a
1 B 2 b
2 C 3 c
在这个例子中,我们使用了 pd.merge()
函数将 DataFrame df
和 Series ser
进行连接。连接的键是 Let
和 Num
。连接后的结果存储在变量 result
中。
left = pd.DataFrame({"A": [1, 2], "B": [2, 2]})
right = pd.DataFrame({"A": [4, 5, 6], "B": [2, 2, 2]})
result = pd.merge(left, right, on="B", how="outer")
result
Out[68]:
A_x B A_y
0 1 2 4
1 1 2 5
2 1 2 6
3 2 2 4
4 2 2 5
5 2 2 6
在这个例子中,我们使用了 pd.merge()
函数将两个 DataFrame left
和 right
进行外连接。外连接是指保留两个 DataFrame 中所有的键值对,如果某个键在其中一个 DataFrame 中不存在,则用 NaN 填充。连接后的结果存储在变量 result
中。
警告:在进行外连接时,如果连接的键存在重复值,会导致结果的维度显著增加,可能会导致内存溢出。
left = pd.DataFrame({"A": [1, 2], "B": [1, 2]})
right = pd.DataFrame({"A": [4, 5, 6], "B": [2, 2, 2]})
result = pd.merge(left, right, on="B", how="outer", validate="one_to_one")
---------------------------------------------------------------------------
MergeError Traceback (most recent call last)
Cell In[71], line 1
----> 1 result = pd.merge(left, right, on="B", how="outer", validate="one_to_one")
...
MergeError: Merge keys are not unique in right dataset; not a one-to-one merge
在这个例子中,我们使用了 pd.merge()
函数将两个 DataFrame left
和 right
进行外连接,并使用 validate="one_to_one"
参数进行验证。由于右侧 DataFrame 中的连接键存在重复值,所以验证失败,抛出了 MergeError
异常。
如果用户知道右侧 DataFrame 中存在重复值,但希望确保左侧 DataFrame 中没有重复值,可以使用 validate='one_to_many'
参数,这样就不会抛出异常。
pd.merge(left, right, on="B", how="outer", validate="one_to_many")
Out[72]:
A_x B A_y
0 1 1 NaN
1 2 2 4.0
2 2 2 5.0
3 2 2 6.0
在这个例子中,我们使用了 pd.merge()
函数将两个 DataFrame left
和 right
进行外连接,并使用 validate="one_to_many"
参数进行验证。由于左侧 DataFrame 中的连接键不存在重复值,所以验证通过,连接后的结果存储在变量 result
中。
merge()
函数接受一个 indicator
参数。如果设置为 True
,则会在输出对象中添加一个名为 _merge
的分类列,其取值如下:
- 只在
'left'
DataFrame 中存在连接键:left_only
- 只在
'right'
DataFrame 中存在连接键:right_only
- 在两个 DataFrame 中都存在连接键:
both
df1 = pd.DataFrame({"col1": [0, 1], "col_left": ["a", "b"]})
df2 = pd.DataFrame({"col1": [1, 2, 2], "col_right": [2, 2, 2]})
pd.merge(df1, df2, on="col1", how="outer", indicator=True)
Out[75]:
col1 col_left col_right _merge
0 0 a NaN left_only
1 1 b 2.0 both
2 2 NaN 2.0 right_only
3 2 NaN 2.0 right_only
在这个例子中,我们使用了 pd.merge()
函数将两个 DataFrame df1
和 df2
进行外连接,并设置 indicator=True
。连接后的结果中添加了一个名为 _merge
的列,用于指示连接的来源。
indicator
参数也可以设置为字符串,此时该字符串将作为指示列的名称。
pd.merge(df1, df2, on="col1", how="outer", indicator="indicator_column")
Out[76]:
col1 col_left col_right indicator_column
0 0 a NaN left_only
1 1 b 2.0 both
2 2 NaN 2.0 right_only
3 2 NaN 2.0 right_only
在这个例子中,我们使用了 pd.merge()
函数将两个 DataFrame df1
和 df2
进行外连接,并设置 indicator="indicator_column"
。连接后的结果中添加了一个名为 indicator_column
的列,用于指示连接的来源。
merge()
函数的 suffixes
参数接受一个字符串列表或元组,用于在输入 DataFrame 的重叠列名后添加后缀,以区分结果列。
left = pd.DataFrame({"A": [1, 2], "B": [2, 2]})
right = pd.DataFrame({"A": [4, 5, 6], "B": [2, 2, 2]})
result = pd.merge(left, right, on="B")
result
Out[80]:
A_x B A_y
0 1 2 4
1 1 2 5
在这个例子中,我们使用了 pd.merge()
函数将两个 DataFrame left
和 right
进行连接,并设置连接键为 B
。由于两个 DataFrame 中都存在列名为 A
的列,所以连接后的结果中会出现重叠列名。为了区分这些列,我们可以使用 suffixes=("_l", "_r")
参数,将左侧 DataFrame 的列名后缀设置为 _l
,将右侧 DataFrame 的列名后缀设置为 _r
。
result = pd.merge(left, right, on="B", suffixes=("_l", "_r"))
result
Out[82]:
A_l B A_r
0 1 2 4
1 1 2 5
在这个例子中,我们使用了 pd.merge()
函数将两个 DataFrame left
和 right
进行连接,并设置连接键为 B
,同时设置了 suffixes=("_l", "_r")
参数。连接后的结果中的列名为 A_l
、B
和 A_r
,用于区分两个 DataFrame 中的重叠列。
DataFrame.join()
函数将多个可能具有不同索引的 DataFrame 的列组合成一个结果 DataFrame。
left = pd.DataFrame(
{"A": ["A0", "A1", "A2"], "B": ["B0", "B1", "B2"]}, index=["K0", "K1", "K2"]
)
right = pd.DataFrame(
{"C": ["C0", "C2", "C3"], "D": ["D0", "D2", "D3"]}, index=["K0", "K2", "K3"]
)
result = left.join(right)
result
Out[86]:
A B C D
K0 A0 B0 C0 D0
K1 A1 B1 NaN NaN
K2 A2 B2 C2 D2
在这个例子中,我们使用了 DataFrame.join()
函数将 DataFrame left
和 right
进行连接。连接的结果存储在变量 result
中。连接的方式是根据索引进行连接,即将 left
DataFrame 和 right
DataFrame 中具有相同索引的行进行连接。
result = left.join(right, how="outer")
result
Out[88]:
A B C D
K0 A0 B0 C0 D0
K1 A1 B1 NaN NaN
K2 A2 B2 C2 D2
K3 NaN NaN C3 D3
在这个例子中,我们使用了 DataFrame.join()
函数将 DataFrame left
和 right
进行外连接。外连接是指保留两个 DataFrame 中所有的行,如果某个行在其中一个 DataFrame 中不存在,则用 NaN 填充。连接后的结果存储在变量 result
中。
result = left.join(right, how="inner")
result
Out[90]:
A B C D
K0 A0 B0 C0 D0
K2 A2 B2 C2 D2
在这个例子中,我们使用了 DataFrame.join()
函数将 DataFrame left
和 right
进行内连接。内连接是指只保留两个 DataFrame 中共有的行,其他的行将被丢弃。连接后的结果存储在变量 result
中。
[`DataFrame.join()`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.join.html#pandas.DataFrame.join) 方法可以接受一个可选的 `on` 参数,该参数可以是一个列名或多个列名,用于对齐传入的 [`DataFrame`](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html#pandas.DataFrame)。
```python
left = pd.DataFrame(
{
"A": ["A0", "A1", "A2", "A3"],
"B": ["B0", "B1", "B2", "B3"],
"key": ["K0", "K1", "K0", "K1"],
}
)
right = pd.DataFrame({"C": ["C0", "C1"], "D": ["D0", "D1"]}, index=["K0", "K1"])
result = left.join(right, on="key")
result
Out[94]:
A B key C D
0 A0 B0 K0 C0 D0
1 A1 B1 K1 C1 D1
2 A2 B2 K0 C0 D0
3 A3 B3 K1 C1 D1
DataFrame.join()
方法可以接受一个可选的 on
参数,该参数可以是一个列名或多个列名,用于对齐传入的 DataFrame
。
result = pd.merge(
left, right, left_on="key", right_index=True, how="left", sort=False
)
result
Out[96]:
A B key C D
0 A0 B0 K0 C0 D0
1 A1 B1 K1 C1 D1
2 A2 B2 K0 C0 D0
3 A3 B3 K1 C1 D1
要使用多个键进行连接,传入的 DataFrame
必须具有 MultiIndex
:
left = pd.DataFrame(
{
"A": ["A0", "A1", "A2", "A3"],
"B": ["B0", "B1", "B2", "B3"],
"key1": ["K0", "K0", "K1", "K2"],
"key2": ["K0", "K1", "K0", "K1"],
}
)
index = pd.MultiIndex.from_tuples(
[("K0", "K0"), ("K1", "K0"), ("K2", "K0"), ("K2", "K1")]
)
right = pd.DataFrame(
{"C": ["C0", "C1", "C2", "C3"], "D": ["D0", "D1", "D2", "D3"]}, index=index
)
result = left.join(right, on=["key1", "key2"])
result
Out[101]:
A B key1 key2 C D
0 A0 B0 K0 K0 C0 D0
1 A1 B1 K0 K1 NaN NaN
2 A2 B2 K1 K0 C1 D1
3 A3 B3 K2 K1 C3 D3
DataFrame.join()
方法的默认行为是执行左连接(left join),只使用调用 DataFrame
中找到的键。可以使用 how
参数指定其他连接类型。
result = left.join(right, on=["key1", "key2"], how="inner")
result
Out[103]:
A B key1 key2 C D
0 A0 B0 K0 K0 C0 D0
2 A2 B2 K1 K0 C1 D1
3 A3 B3 K2 K1 C3 D3
可以将一个具有 Index
的 DataFrame
与具有 MultiIndex
的 DataFrame
在一个级别上进行连接。Index
的 name
与 MultiIndex
的级别名称匹配。
left = pd.DataFrame(
{"A": ["A0", "A1", "A2"], "B": ["B0", "B1", "B2"]},
index=pd.Index(["K0", "K1", "K2"], name="key"),
)
index = pd.MultiIndex.from_tuples(
[("K0", "Y0"), ("K1", "Y1"), ("K2", "Y2"), ("K2", "Y3")],
names=["key", "Y"],
)
right = pd.DataFrame(
{"C": ["C0", "C1", "C2", "C3"], "D": ["D0", "D1", "D2", "D3"]},
index=index,
)
result = left.join(right, how="inner")
result
Out[108]:
A B C D
key Y
K0 Y0 A0 B0 C0 D0
K1 Y1 A1 B1 C1 D1
K2 Y2 A2 B2 C2 D2
Y3 A2 B2 C3 D3
可以将两个 MultiIndex
进行连接,输入参数的 MultiIndex
必须完全用于连接,并且是左侧参数中索引的子集。
leftindex = pd.MultiIndex.from_product(
[list("abc"), list("xy"), [1, 2]], names=["abc", "xy", "num"]
)
left = pd.DataFrame({"v1": range(12)}, index=leftindex)
left
Out[111]:
v1
abc xy num
a x 1 0
2 1
y 1 2
2 3
b x 1 4
2 5
y 1 6
2 7
c x 1 8
2 9
y 1 10
2 11
rightindex = pd.MultiIndex.from_product(
[list("abc"), list("xy")], names=["abc", "xy"]
)
right = pd.DataFrame({"v2": [100 * i for i in range(1, 7)]}, index=rightindex)
right
Out[114]:
v2
abc xy
a x 100
y 200
b x 300
y 400
c x 500
y 600
left.join(right, on=["abc", "xy"], how="inner")
Out[115]:
v1 v2
abc xy num
a x 1 0 100
2 1 100
y 1 2 200
2 3 200
b x 1 4 300
2 5 300
y 1 6 400
2 7 400
c x 1 8 500
2 9 500
y 1 10 600
2 11 600
DataFrame.join()
方法还可以将一个列表或元组的 DataFrame
一起传递给 join()
,在它们的索引上进行连接。
right2 = pd.DataFrame({"v": [7, 8, 9]}, index=["K1", "K1", "K2"])
result = left.join([right, right2])
DataFrame.combine_first()
方法可以使用另一个 DataFrame
中的非缺失值更新一个 DataFrame
中的缺失值。
df1 = pd.DataFrame(
[[np.nan, 3.0, 5.0], [-4.6, np.nan, np.nan], [np.nan, 7.0, np.nan]]
)
df2 = pd.DataFrame([[-42.6, np.nan, -8.2], [-5.0, 1.6, 4]], index=[1, 2])
result = df1.combine_first(df2)
result
Out[133]:
0 1 2
0 NaN 3.0 5.0
1 -4.6 NaN -8.2
2 -5.0 7.0 4.0
DataFrame.combine_first()
方法可以使用另一个 DataFrame
中的非缺失值更新一个 DataFrame
中的缺失值。
merge_ordered()
merge_ordered()
函数可以将有序数据(如数字或时间序列数据)进行合并,并可选择使用 fill_method
来填充缺失数据。
left = pd.DataFrame(
{"k": ["K0", "K1", "K1", "K2"], "lv": [1, 2, 3, 4], "s": ["a", "b", "c", "d"]}
)
right = pd.DataFrame({"k": ["K1", "K2", "K4"], "rv": [1, 2, 3]})
pd.merge_ordered(left, right, fill_method="ffill", left_by="s")
Out[136]:
k lv s rv
0 K0 1.0 a NaN
1 K1 1.0 a 1.0
2 K2 1.0 a 2.0
3 K4 1.0 a 3.0
4 K1 2.0 b 1.0
5 K2 2.0 b 2.0
6 K4 2.0 b 3.0
7 K1 3.0 c 1.0
8 K2 3.0 c 2.0
9 K4 3.0 c 3.0
10 K1 NaN d 1.0
11 K2 4.0 d 2.0
12 K4 4.0 d 3.0
merge_asof()
merge_asof()
函数类似于有序的左连接,但匹配是基于最近的键而不是相等的键。对于 left
DataFrame
中的每一行,选择 right
DataFrame
中最后一个键小于左键的行。两个 DataFrame
必须按键排序。
可选地,merge_asof()
可以通过在 by
键上进行匹配来执行分组合并。
trades = pd.DataFrame(
{
"time": pd.to_datetime(
[
"20160525 13:30:00.023",
"20160525 13:30:00.038",
"20160525 13:30:00.048",
"20160525 13:30:00.048",
"20160525 13:30:00.048",
]
),
"ticker": ["MSFT", "MSFT", "GOOG", "GOOG", "AAPL"],
"price": [51.95, 51.95, 720.77, 720.92, 98.00],
"quantity": [75, 155, 100, 100, 100],
},
columns=["time", "ticker", "price", "quantity"],
)
quotes = pd.DataFrame(
{
"time": pd.to_datetime(
[
"20160525 13:30:00.023",
"20160525 13:30:00.023",
"20160525 13:30:00.030",
"20160525 13:30:00.041",
"20160525 13:30:00.048",
"20160525 13:30:00.049",
"20160525 13:30:00.072",
"20160525 13:30:00.075",
]
),
"ticker": ["GOOG", "MSFT", "MSFT", "MSFT", "GOOG", "AAPL", "GOOG", "MSFT"],
"bid": [720.50, 51.95, 51.97, 51.99, 720.50, 97.99, 720.50, 52.01],
"ask": [720.93, 51.96, 51.98, 52.00, 720.93, 98.01, 720.88, 52.03],
},
columns=["time", "ticker", "bid", "ask"],
)
trades
Out[139]:
time ticker price quantity
0 2016-05-25 13:30:00.023 MSFT 51.95 75
1 2016-05-25 13:30:00.038 MSFT 51.95 155
2 2016-05-25 13:30:00.048 GOOG 720.77 100
3 2016-05-25 13:30:00.048 GOOG 720.92 100
4 2016-05-25 13:30:00.048 AAPL 98.00 100
quotes
Out[140]:
time ticker bid ask
0 2016-05-25 13:30:00.023 GOOG 720.50 720.93
1 2016-05-25 13:30:00.023 MSFT 51.95 51.96
2 2016-05-25 13:30:00.030 MSFT 51.97 51.98
3 2016-05-25 13:30:00.041 MSFT 51.99 52.00
4 2016-05-25 13:30:00.048 GOOG 720.50 720.93
5 2016-05-25 13:30:00.049 AAPL 97.99 98.01
6 2016-05-25 13:30:00.072 GOOG 720.50 720.88
7 2016-05-25 13:30:00.075 MSFT 52.01 52.03
pd.merge_asof(trades, quotes, on="time", by="ticker")
Out[141]:
time ticker price quantity bid ask
0 2016-05-25 13:30:00.023 MSFT 51.95 75 51.95 51.96
1 2016-05-25 13:30:00.038 MSFT 51.95 155 51.97 51.98
2 2016-05-25 13:30:00.048 GOOG 720.77 100 720.50 720.93
3 2016-05-25 13:30:00.048 GOOG 720.92 100 720.50 720.93
4 2016-05-25 13:30:00.048 AAPL 98.00 100 NaN NaN
merge_asof()
在报价时间和交易时间之间的时间差小于 2ms
。
pd.merge_asof(trades, quotes, on="time", by="ticker", tolerance=pd.Timedelta("2ms"))
Out[142]:
time ticker price quantity bid ask
0 2016-05-25 13:30:00.023 MSFT 51.95 75 51.95 51.96
1 2016-05-25 13:30:00.038 MSFT 51.95 155 NaN NaN
2 2016-05-25 13:30:00.048 GOOG 720.77 100 720.50 720.93
3 2016-05-25 13:30:00.048 GOOG 720.92 100 720.50 720.93
4 2016-05-25 13:30:00.048 AAPL 98.00 100 NaN NaN
merge_asof()
在报价时间和交易时间之间的时间差小于 10ms
,并排除时间上的精确匹配。请注意,尽管我们排除了精确匹配(报价),但之前的报价仍然会传播到该时间点。
pd.merge_asof(
trades,
quotes,
on="time",
by="ticker",
tolerance=pd.Timedelta("10ms"),
allow_exact_matches=False,
)
Out[143]:
time ticker price quantity bid ask
0 2016-05-25 13:30:00.023 MSFT 51.95 75 NaN NaN
1 2016-05-25 13:30:00.038 MSFT 51.95 155 51.97 51.98
2 2016-05-25 13:30:00.048 GOOG 720.77 100 NaN NaN
3 2016-05-25 13:30:00.048 GOOG 720.92 100 NaN NaN
4 2016-05-25 13:30:00.048 AAPL 98.00 100 NaN NaN
compare()
Series.compare()
和 DataFrame.compare()
方法允许您比较两个 DataFrame
或 Series
,并总结它们的差异。
df = pd.DataFrame(
{
"col1": ["a", "a", "b", "b", "a"],
"col2": [1.0, 2.0, 3.0, np.nan, 5.0],
"col3": [1.0, 2.0, 3.0, 4.0, 5.0],
},
columns=["col1", "col2", "col3"],
)
df
Out[145]:
col1 col2 col3
0 a 1.0 1.0
1 a 2.0 2.0
2 b 3.0 3.0
3 b NaN 4.0
4 a 5.0 5.0
df2 = df.copy()
df2.loc[0, "col1"] = "c"
df2.loc[2, "col3"] = 4.0
df2
Out[149]:
col1 col2 col3
0 c 1.0 1.0
1 a 2.0 2.0
2 b 3.0 4.0
3 b NaN 4.0
4 a 5.0 5.0
df.compare(df2)
Out[150]:
col1 col3
self other self other
0 a c NaN NaN
2 NaN NaN 3.0 4.0
默认情况下,如果两个对应的值相等,它们将显示为 NaN
。此外,如果整行/列中的所有值都相等,则该行/列将从结果中省略。剩下的差异将对齐在列上。
将差异堆叠在行上。
df.compare(df2, align_axis=0)
Out[151]:
col1 col3
0 self a NaN
other c NaN
2 self NaN 3.0
other NaN 4.0
保留所有原始行和列,使用 keep_shape=True
df.compare(df2, keep_shape=True)
Out[152]:
col1 col2 col3
self other self other self other
0 a c NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN 3.0 4.0
3 NaN NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN NaN
保留所有原始值,即使它们相等。
df.compare(df2, keep_shape=True, keep_equal=True)
Out[153]:
col1 col2 col3
self other self other self other
0 a c 1.0 1.0 1.0 1.0
1 a a 2.0 2.0 2.0 2.0
2 b b 3.0 3.0 3.0 4.0
3 b b NaN NaN 4.0 4.0
4 a a 5.0 5.0 5.0 5.0
Pandas 2 使用指南导读
Pandas 2 使用指南:4、IO工具(文本、CSV、HDF5等)
Pandas 2 使用指南:8、写时复制(Copy-on-Write,CoW)
Pandas 2 使用指南:10、重塑和透视表ReShapingand Pivot Tables
Pandas 2 使用指南:11、处理文本数据 Working with text data
Pandas 2 使用指南:12、处理缺失数据Working with missing data
Pandas 2 使用指南: 13、重复标签 Duplicate Labels
Pandas 2 使用指南:14、分类数据 Categorical data
Pandas 2 使用指南:15、可空整数数据类型、可空布尔数据类型
Pandas 2 使用指南:18、Groupby:拆分-应用-合并 split-apply-combine
Pandas 2 使用指南:19、窗口操作 Windowing operations
Pandas 2 使用指南:20、时间序列/日期功能
Pandas 2 使用指南:21、时间差 Timedelta
Pandas 2 使用指南:23、提升性能 Enhancing performance