pandas合并操作

一、基础用法

1. merge 操作

merge 操作类似于 SQL 中的 JOIN 操作,可以根据一个或多个键将两个 DataFrame 合并。

常见参数:
  • left:左边的 DataFrame。
  • right:右边的 DataFrame。
  • how:合并的方式,常用的有 ‘left’(左连接)、‘right’(右连接)、‘outer’(外连接)、‘inner’(内连接)。
  • on:用于连接的列名,如果两个 DataFrame 中有相同的列名,可以用 on 指定。
  • left_on:左边 DataFrame 用于连接的列名。
  • right_on:右边 DataFrame 用于连接的列名。
  • suffixes:当合并的两个 DataFrame 中存在相同列名时,用于追加到列名的后缀,默认是 (‘_x’, ‘_y’)。
示例 1:根据单列合并
import pandas as pd

# 创建 DataFrame
df1 = pd.DataFrame({
    'id': [1, 2, 3, 4],
    'name': ['Alice', 'Bob', 'Charlie', 'David']
})

df2 = pd.DataFrame({
    'id': [3, 4, 5, 6],
    'age': [23, 34, 45, 56]
})

# 内连接(inner join)合并
result = pd.merge(df1, df2, on='id', how='inner')
print(result)

输出:

   id     name  age
0   3  Charlie   23
1   4    David   34
示例 2:根据多列合并
# 创建 DataFrame
df3 = pd.DataFrame({
    'id': [1, 2, 3, 4],
    'name': ['Alice', 'Bob', 'Charlie', 'David'],
    'age': [24, 27, 22, 32]
})

df4 = pd.DataFrame({
    'id': [3, 4, 5, 6],
    'name': ['Charlie', 'David', 'Edward', 'Fiona'],
    'salary': [50000, 60000, 70000, 80000]
})

# 根据 'id' 和 'name' 列合并
result = pd.merge(df3, df4, on=['id', 'name'], how='inner')
print(result)

输出:

   id     name  age  salary
0   3  Charlie   22   50000
1   4    David   32   60000

2. join 操作

join 是专门用于基于索引合并的操作,常用于需要用 DataFrame 的索引进行连接的情况。

常见参数:
  • other:要合并的 DataFrame。
  • how:连接方式,同 merge
  • on:用于连接的列名,如果不是基于索引连接,则需要指定。
  • lsuffixrsuffix:左右重名列的后缀。
示例 3:索引合并
df5 = pd.DataFrame({
    'age': [24, 27, 22, 32]
}, index=['Alice', 'Bob', 'Charlie', 'David'])

df6 = pd.DataFrame({
    'salary': [50000, 60000, 70000, 80000]
}, index=['Bob', 'Charlie', 'David', 'Edward'])

# 使用 join 合并
result = df5.join(df6, how='inner')
print(result)

输出:

         age  salary
Bob       27   50000
Charlie   22   60000
David     32   70000

3. concat 操作

concat 用于沿一个轴(行或列)连接多个 DataFrame。与 mergejoin 不同的是,它并不需要依据键来合并数据,而是简单地将数据拼接在一起。

常见参数:
  • objs:需要连接的 DataFrame 或 Series 序列。
  • axis:连接方向,0 为沿着行方向(纵向),1 为沿着列方向(横向)。
  • join:连接方式,默认为 ‘outer’。
  • ignore_index:是否忽略原有的索引,重新生成新的索引。
示例 4:纵向合并
df7 = pd.DataFrame({
    'name': ['Alice', 'Bob'],
    'age': [24, 27]
})

df8 = pd.DataFrame({
    'name': ['Charlie', 'David'],
    'age': [22, 32]
})

# 使用 concat 纵向合并
result = pd.concat([df7, df8], axis=0, ignore_index=True)
print(result)

输出:

      name  age
0    Alice   24
1      Bob   27
2  Charlie   22
3    David   32
示例 5:横向合并
# 使用 concat 横向合并
result = pd.concat([df7, df8], axis=1)
print(result)

输出:

      name  age     name  age
0    Alice   24  Charlie   22
1      Bob   27    David   32

二、进阶用法

1. merge

1.1 使用 indicator 参数追踪合并操作

indicator 参数可以帮助你了解每一行数据在合并过程中的来源。这个功能对调试数据合并或理解合并结果非常有用。

import pandas as pd

df1 = pd.DataFrame({'id': [1, 2, 3], 'name': ['Alice', 'Bob', 'Charlie']})
df2 = pd.DataFrame({'id': [2, 3, 4], 'age': [24, 27, 22]})

# 使用 indicator 追踪合并来源
result = pd.merge(df1, df2, on='id', how='outer', indicator=True)
print(result)

输出:

   id     name   age      _merge
0   1    Alice   NaN   left_only
1   2      Bob  24.0        both
2   3  Charlie  27.0        both
3   4      NaN  22.0  right_only

_merge 列显示了每一行是来自于左表(left_only)、右表(right_only)还是两个表都有的数据(both)。

1.2 自定义列名后缀

当合并的 DataFrame 存在相同的列名时,suffixes 参数可以帮助你自定义合并后列名的后缀。

df1 = pd.DataFrame({'id': [1, 2, 3], 'name': ['Alice', 'Bob', 'Charlie'], 'age': [24, 27, 22]})
df2 = pd.DataFrame({'id': [2, 3, 4], 'name': ['David', 'Edward', 'Fiona'], 'age': [30, 35, 40]})

# 使用自定义的后缀
result = pd.merge(df1, df2, on='id', how='outer', suffixes=('_left', '_right'))
print(result)

输出:

   id     name_left  age_left name_right  age_right
0   1    Alice        24.0       NaN         NaN
1   2      Bob         27.0      David        30.0
2   3  Charlie       22.0     Edward       35.0
3   4      NaN        NaN     Fiona          40.0

2. concat

2.1 合并时忽略索引

concatignore_index 参数允许你在合并时忽略原始索引,并为结果 DataFrame 生成新的连续索引。

df3 = pd.DataFrame({'name': ['Alice', 'Bob'], 'age': [24, 27]}, index=[0, 1])
df4 = pd.DataFrame({'name': ['Charlie', 'David'], 'age': [22, 32]}, index=[2, 3])

# 使用 ignore_index 忽略原索引
result = pd.concat([df3, df4], ignore_index=True)
print(result)

输出:

      name  age
0    Alice   24
1      Bob   27
2  Charlie   22
3    David   32
2.2 使用 keys 参数分层级索引

当合并多个 DataFrame 时,可以使用 keys 参数创建一个分层索引,方便日后引用和处理。

df5 = pd.DataFrame({'name': ['Alice', 'Bob'], 'age': [24, 27]})
df6 = pd.DataFrame({'name': ['Charlie', 'David'], 'age': [22, 32]})

# 使用 keys 创建分层索引
result = pd.concat([df5, df6], keys=['group1', 'group2'])
print(result)

输出:

            name  age
group1 0    Alice   24
       1      Bob   27
group2 0  Charlie   22
       1    David   32

3. join

3.1 基于索引的多重合并

join 可以一次性合并多个 DataFrame,并且可以指定多种合并方式。

df7 = pd.DataFrame({'age': [24, 27, 22]}, index=['Alice', 'Bob', 'Charlie'])
df8 = pd.DataFrame({'salary': [50000, 60000, 70000]}, index=['Bob', 'Charlie', 'David'])
df9 = pd.DataFrame({'department': ['HR', 'Finance', 'IT']}, index=['Alice', 'Charlie', 'David'])

# 一次性合并多个 DataFrame
result = df7.join([df8, df9], how='outer')
print(result)

输出:

           age   salary department
Alice     24.0      NaN        HR
Bob       27.0  50000.0       NaN
Charlie   22.0  60000.0  Finance
David      NaN  70000.0        IT

4. 其它高级技巧和注意事项

4.1 数据对齐

Pandas 合并操作默认是基于标签对齐的,因此合并的 DataFrame 的索引或列名称是关键。如果你在合并过程中遇到问题,检查标签对齐是否是你想要的非常重要。

4.2 性能优化

在合并大数据集时,考虑使用 sort=False 来避免排序开销,从而提高性能。

result = pd.merge(df1, df2, on='id', how='outer', sort=False)
4.3 避免内存不足

对于非常大的数据集,合并操作可能会导致内存不足。可以使用 chunk 读取方式或 Dask 库处理大数据集。

5. 实际应用场景中的合并

5.1 时间序列数据对齐

假设你有两个不同频率的时间序列数据集,可以使用 pd.merge_asof 来进行对齐,这对处理金融数据、IoT 数据等非常有用。

df10 = pd.DataFrame({
    'time': pd.to_datetime(['2021-01-01 01:00:00', '2021-01-01 02:00:00', '2021-01-01 03:00:00']),
    'value': [10, 15, 20]
})

df11 = pd.DataFrame({
    'time': pd.to_datetime(['2021-01-01 01:30:00', '2021-01-01 02:30:00']),
    'value2': [5, 10]
})

# 使用 merge_asof 对齐
result = pd.merge_asof(df10, df11, on='time')
print(result)

输出:

                 time  value  value2
0 2021-01-01 01:00:00     10     NaN
1 2021-01-01 02:00:00     15     5.0
2 2021-01-01 03:00:00     20    10.0
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐